背景:
公司的一个web应用,提交给测试部门做压力测试(由于不是我负责的,不清楚如何做的压力测试,以及测试指标),结果没压多久,就出现OutOfMemory.
接手协助原因查找,通过监控工具,发现StandardSession(org.apache.catalina.session.StandardSession)对象不断增长,毫无疑问,肯定是在不断创建Session对象.
备注:一般做压力测试,每次请求都不会指定JESSESIONID值,导致Web容器认为每次请求都是新的请求,于是创建Session对象.
同事负责代码Review,发现应用没有任何一个地方存放Session内容.困惑之...
问题:Tomcat容器何时创建Session对象?
想当然认为,只有动态存放Session内容的时候,才会创建Session对象.但是事实真得如此吗?
先看Servlet协议描述:
请看:
getSession(booleancreate)方法:
javax.servlet.http.HttpServletRequest.getSession(booleancreate)
ReturnsthecurrentHttpSessionassociatedwiththisrequestor,ififthereisnocurrentsessionandcreateistrue,returnsanewsession.
IfcreateisfalseandtherequesthasnovalidHttpSession,thismethodreturnsnull.
Tomakesurethesessionisproperlymaintained,youmustcallthismethodbeforetheresponseiscommitted.
简单地说:当create变量为true时,如果当前Session不存在,创建一个新的Session并且返回.
getSession()方法:
javax.servlet.http.HttpSessiongetSession();
Returnsthecurrentsessionassociatedwiththisrequest,oriftherequestdoesnothaveasession,createsone.
简单的说:当当前Session不存在,创建并且返回.
所以说,协议规定,在调用getSession方法的时候,就会创建Session对象.
既然协议这么定了,我们再来看看Tomcat是如何实现的:(下面的描述,是基于Tomcat6.0.14版本源码)
先看一张简单的类图:
ApplicationContext:Servlet规范中ServletContext的实现
StandardContext:Tomcat定义的Context默认实现.维护了一份SessionManager对象,管理Session对象.所有的Session对象都存放在Manager定义的Map<String,Session>容器中.
StanardManager:标准的Session管理,将Session存放在内容,Web容器关闭的时候,持久化到本地文件
PersistentManager:持久化实现的Session管理,默认有两种实现方式:
--持久化到本地文件
--持久化到数据库
了解了大概的概念后,回头再来看看org.apache.catalina.connector.Request.getSession()是如何实现的.
最终调用的是doGetSession(boolean create)方法,请看:
protectedSessiondoGetSession(booleancreate){
//Therecannotbeasessionifnocontexthasbeenassignedyet
if(context==null)
return(null);
//Returnthecurrentsessionifitexistsandisvalid
if((session!=null)&&!session.isValid())
session=null;
if(session!=null)
return(session);
//Returntherequestedsessionifitexistsandisvalid
Managermanager=null;
if(context!=null)
manager=context.getManager();
if(manager==null)
return(null);//Sessionsarenotsupported
if(requestedSessionId!=null){
try{
session=manager.findSession(requestedSessionId);
}catch(IOExceptione){
session=null;
}
if((session!=null)&&!session.isValid())
session=null;
if(session!=null){
session.access();
return(session);
}
}
//Createanewsessionifrequestedandtheresponseisnotcommitted
if(!create)
return(null);
if((context!=null)&&(response!=null)&&
context.getCookies()&&
response.getResponse().isCommitted()){
thrownewIllegalStateException
(sm.getString("coyoteRequest.sessionCreateCommitted"));
}
//Attempttoreusesessionidifonewassubmittedinacookie
//DonotreusethesessionidifitisfromaURL,topreventpossible
//phishingattacks
if(connector.getEmptySessionPath()
&&isRequestedSessionIdFromCookie()){
session=manager.createSession(getRequestedSessionId());
}else{
session=manager.createSession(null);
}
//Creatinganewsessioncookiebasedonthatsession
if((session!=null)&&(getContext()!=null)
&&getContext().getCookies()){
Cookiecookie=newCookie(Globals.SESSION_COOKIE_NAME,
session.getIdInternal());
configureSessionCookie(cookie);
response.addCookieInternal(cookie,context.getUseHttpOnly());
}
if(session!=null){
session.access();
return(session);
}else{
return(null);
}
}
至此,简单地描述了Tomcat Session创建的机制,有兴趣的同学要深入了解,不妨看看Tomcat源码实现.
补充说明,顺便提一下Session的过期策略.
过期方法在:
org.apache.catalina.session.ManagerBase(StandardManager基类) processExpires方法:
publicvoidprocessExpires(){
longtimeNow=System.currentTimeMillis();
Sessionsessions[]=findSessions();
intexpireHere=0;
if(log.isDebugEnabled())
log.debug("Startexpiresessions"+getName()+"at"+timeNow+"sessioncount"+sessions.length);
for(inti=0;i<sessions.length;i++){
if(sessions[i]!=null&&!sessions[i].isValid()){
expireHere++;
}
}
longtimeEnd=System.currentTimeMillis();
if(log.isDebugEnabled())
log.debug("Endexpiresessions"+getName()+"processingTime"+(timeEnd-timeNow)+"expiredsessions:"+expireHere);
processingTime+=(timeEnd-timeNow);
}
其中,Session.isValid()方法会做Session的清除工作.
在org.apache.catalina.core.ContainerBase中,会启动一个后台线程,跑一些后台任务,Session过期任务是其中之一:
protectedvoidthreadStart(){
if(thread!=null)
return;
if(backgroundProcessorDelay<=0)
return;
threadDone=false;
StringthreadName="ContainerBackgroundProcessor["+toString()+"]";
thread=newThread(newContainerBackgroundProcessor(),threadName);
thread.setDaemon(true);
thread.start();
}
准确地讲,除非你的应用完全不需要保存状态(无状态应用),不然地话,只要有一个新的连接过来,web容器都需要创建Session概念,维护状态信息.
但是Session是什么?Session仅仅是一个概念:"Provides a way to identify a user across more than one page request or visit to a Web site and to store information about that user."--简单地讲,保存用户状态信息.
所以说,我们完全可以根据应用的需求,定制Session的实现:
a. Session保存到JVM内容中--Tomcat默认的实现
b. Session保存到Cookie中--Cookie-Based Session
c. Session保存到本地文件--Tomcat提供的非默认实现之一
d. Session保存到Cache Store中--比如常见的Memcached
e. Session保存到数据库中--比如保存到mysql数据库session表,中间对于活跃的Session 缓存到cached中.
......
那么,假如一个应用有大量一次性不同用户的请求(仅仅是一次性的,比如上述文章描述的场景),那么选择c,d,e方案都能有效解决文中所描述的问题.
分享到:
相关推荐
8. **集群和负载均衡**:虽然Tomcat6.0.14的集群功能相比现代版本可能较为基础,但依然可以通过配置实现多个Tomcat实例间的session复制,以达到负载均衡的目的。 总之,Apache Tomcat 6.0.14是一个适合初学者入门的...
### Apache 2.2.4与Tomcat 6.0.14整合教程:构建负载均衡Web环境 在现代Web开发环境中,为了提高网站的可用性、可扩展性和响应速度,通常会采用负载均衡技术来分散请求到多台服务器上处理。本文将详细解析如何通过...
一直以来,我误解认为启动了n个tomcat,则Session需要同步复制到n个Tomcat中存在,因此在启动了6个以上的Tomcat,性能会大大下降。 而实际情况下,采取Apache 加Tomcat进行负载均衡集群的时候,是可以不用将Session...
Apache Tomcat 6.0.14 是一个广泛使用的开源软件,它是一个实现了Java Servlet和JavaServer Pages(JSP)规范的应用服务器,主要用于部署和运行Java Web应用程序。这个压缩包"apache-tomcat-6.0.14.rar"包含了Tomcat...
- Tomcat 6.0.14:Web应用服务器。 - Apache 2.2.6:作为负载均衡器。 - mod_jk-2.2.4:Apache与Tomcat的连接器。 - **硬件**: - 四台PC或虚拟机,分别作为Apache服务器和三个Tomcat服务器。 安装好所有软件...
- **Tomcat 6.0.14**: 下载地址:`apache-tomcat-6.0.14.zip` #### 四、安装步骤 1. **Apache安装目录**: `D:\Apache` 2. **Tomcat安装目录**: 解压缩至`D:\Tomcat集群服务器\`,具体包括: - `tomcat6.0` - `...
Apache版本为2.2.8,而Tomcat版本为6.0.14。确保已经安装了JDK 1.5或更高版本。Apache将作为前端HTTP服务器,负责分发请求到后台的多个Tomcat实例,每个实例都是一个独立的应用服务节点。在这个示例中,我们将在一个...
在"apache-tomcat-6.0.14-src"这个压缩包中,包含了Tomcat 6.0.14的源代码,这对于开发者来说是极其宝贵的资源。源代码的分析和学习可以帮助我们深入理解Tomcat的工作原理,如何处理HTTP请求,以及如何管理Web应用...
【压缩包子文件的文件名称】"apache-tomcat-6.0.14" 是Tomcat的一个具体版本,6.0.14代表了它的版本号。这个版本可能包含了Tomcat的完整二进制包,包括服务器本身、必要的库文件、配置文件、示例应用以及相关的文档...
2. **Tomcat** 版本至少为6.0.14。 3. **Apache HTTP Server**,例如2.2.6版本。 4. **JK模块** (mod_jk) 用于Apache和Tomcat之间的通信,如JK-2.2.4。 硬件上,需要四台PC或虚拟机,分别配置为Apache服务器和三个...
Tomcat支持集群配置,通过复制会话数据实现session在多台服务器间的同步,从而实现负载均衡和故障转移。这通常需要结合其他工具如Apache HTTP Server或Nginx实现。 8. **与其他服务器集成** Tomcat可以作为独立...
2. Tomcat 6.0.14:作为应用服务器,负责运行和部署 Java Web 应用程序。 3. Struts2 1.8:负责 MVC(Model-View-Controller)设计模式的实现,提供控制器层。 4. Hibernate 3:对象关系映射(ORM)工具,用于数据...