<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    stone2083

    Tomcat(6.0.14) Session創(chuàng)建機(jī)制簡介

    背景:
    公司的一個(gè)web應(yīng)用,提交給測試部門做壓力測試(由于不是我負(fù)責(zé)的,不清楚如何做的壓力測試,以及測試指標(biāo)),結(jié)果沒壓多久,就出現(xiàn)OutOfMemory.
    接手協(xié)助原因查找,通過監(jiān)控工具,發(fā)現(xiàn)StandardSession(org.apache.catalina.session.StandardSession)對象不斷增長,毫無疑問,肯定是在不斷創(chuàng)建Session對象.
    備注:一般做壓力測試,每次請求都不會(huì)指定JESSESIONID值,導(dǎo)致Web容器認(rèn)為每次請求都是新的請求,于是創(chuàng)建Session對象.
    同事負(fù)責(zé)代碼Review,發(fā)現(xiàn)應(yīng)用沒有任何一個(gè)地方存放Session內(nèi)容.困惑之...

    問題:Tomcat容器何時(shí)創(chuàng)建Session對象?
    想當(dāng)然認(rèn)為,只有動(dòng)態(tài)存放Session內(nèi)容的時(shí)候,才會(huì)創(chuàng)建Session對象.但是事實(shí)真得如此嗎?

    先看Servlet協(xié)議描述:
    請看:
    getSession(boolean create)方法:
    javax.servlet.http.HttpServletRequest.getSession(boolean create)

    Returns the current HttpSession associated with this request or, if if there is no current session and create is true, returns a new session. 

    If create is false and the request has no valid HttpSession, this method returns null. 

    To make sure the session is properly maintained, you must call this method before the response is committed.

    簡單地說:當(dāng)create變量為true時(shí),如果當(dāng)前Session不存在,創(chuàng)建一個(gè)新的Session并且返回.

    getSession()方法:
    javax.servlet.http.HttpSession getSession();

    Returns the current session associated with this request, or if the request does not have a session, creates one.
    簡單的說:當(dāng)當(dāng)前Session不存在,創(chuàng)建并且返回.


    所以說,協(xié)議規(guī)定,在調(diào)用getSession方法的時(shí)候,就會(huì)創(chuàng)建Session對象.



    既然協(xié)議這么定了,我們再來看看Tomcat是如何實(shí)現(xiàn)的:(下面的描述,是基于Tomcat6.0.14版本源碼)
    先看一張簡單的類圖:


    ApplicationContext:Servlet規(guī)范中ServletContext的實(shí)現(xiàn)
    StandardContext:Tomcat定義的Context默認(rèn)實(shí)現(xiàn).維護(hù)了一份SessionManager對象,管理Session對象.所有的Session對象都存放在Manager定義的Map<String,Session>容器中.
    StanardManager:標(biāo)準(zhǔn)的Session管理,將Session存放在內(nèi)容,Web容器關(guān)閉的時(shí)候,持久化到本地文件
    PersistentManager:持久化實(shí)現(xiàn)的Session管理,默認(rèn)有兩種實(shí)現(xiàn)方式:
    --持久化到本地文件
    --持久化到數(shù)據(jù)庫

    了解了大概的概念后,回頭再來看看org.apache.catalina.connector.Request.getSession()是如何實(shí)現(xiàn)的.
    最終調(diào)用的是doGetSession(boolean create)方法,請看:
    protected Session doGetSession(boolean create) {

            
    // There cannot be a session if no context has been assigned yet
            if (context == null)
                
    return (null);

            
    // Return the current session if it exists and is valid
            if ((session != null&& !session.isValid())
                session 
    = null;
            
    if (session != null)
                
    return (session);

            
    // Return the requested session if it exists and is valid
            Manager manager = null;
            
    if (context != null)
                manager 
    = context.getManager();
            
    if (manager == null)
                
    return (null);      // Sessions are not supported
            if (requestedSessionId != null) {
                
    try {
                    session 
    = manager.findSession(requestedSessionId);
                } 
    catch (IOException e) {
                    session 
    = null;
                }
                
    if ((session != null&& !session.isValid())
                    session 
    = null;
                
    if (session != null) {
                    session.access();
                    
    return (session);
                }
            }

            
    // Create a new session if requested and the response is not committed
            if (!create)
                
    return (null);
            
    if ((context != null&& (response != null&&
                context.getCookies() 
    &&
                response.getResponse().isCommitted()) {
                
    throw new IllegalStateException
                  (sm.getString(
    "coyoteRequest.sessionCreateCommitted"));
            }

            
    // Attempt to reuse session id if one was submitted in a cookie
            
    // Do not reuse the session id if it is from a URL, to prevent possible
            
    // phishing attacks
            if (connector.getEmptySessionPath() 
                    
    && isRequestedSessionIdFromCookie()) {
                session 
    = manager.createSession(getRequestedSessionId());
            } 
    else {
                session 
    = manager.createSession(null);
            }

            
    // Creating a new session cookie based on that session
            if ((session != null&& (getContext() != null)
                   
    && getContext().getCookies()) {
                Cookie cookie 
    = new Cookie(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創(chuàng)建的機(jī)制,有興趣的同學(xué)要深入了解,不妨看看Tomcat源碼實(shí)現(xiàn).



    補(bǔ)充說明,順便提一下Session的過期策略.
    過期方法在:
    org.apache.catalina.session.ManagerBase(StandardManager基類) processExpires方法:
    public void processExpires() {

            
    long timeNow = System.currentTimeMillis();
            Session sessions[] 
    = findSessions();
            
    int expireHere = 0 ;
            
            
    if(log.isDebugEnabled())
                log.debug(
    "Start expire sessions " + getName() + " at " + timeNow + " sessioncount " + sessions.length);
            
    for (int i = 0; i < sessions.length; i++) {
                
    if (sessions[i]!=null && !sessions[i].isValid()) {
                    expireHere
    ++;
                }
            }
            
    long timeEnd = System.currentTimeMillis();
            
    if(log.isDebugEnabled())
                 log.debug(
    "End expire sessions " + getName() + " processingTime " + (timeEnd - timeNow) + " expired sessions: " + expireHere);
            processingTime 
    += ( timeEnd - timeNow );

        }

    其中,Session.isValid()方法會(huì)做Session的清除工作.


    在org.apache.catalina.core.ContainerBase中,會(huì)啟動(dòng)一個(gè)后臺線程,跑一些后臺任務(wù),Session過期任務(wù)是其中之一:
    protected void threadStart() {

            
    if (thread != null)
                
    return;
            
    if (backgroundProcessorDelay <= 0)
                
    return;

            threadDone 
    = false;
            String threadName 
    = "ContainerBackgroundProcessor[" + toString() + "]";
            thread 
    = new Thread(new ContainerBackgroundProcessor(), threadName);
            thread.setDaemon(
    true);
            thread.start();

        }


    OVER :)

    posted on 2010-02-26 16:12 stone2083 閱讀(7058) 評論(4)  編輯  收藏 所屬分類: java

    Feedback

    # re: Tomcat(6.0.14) Session創(chuàng)建機(jī)制簡介 2010-03-05 17:21 小菜花

    也就是說session對象過多是沒法規(guī)避的?  回復(fù)  更多評論   

    # re: Tomcat(6.0.14) Session創(chuàng)建機(jī)制簡介 2010-03-07 15:30 stone2083

    @小菜花
    準(zhǔn)確地講,除非你的應(yīng)用完全不需要保存狀態(tài)(無狀態(tài)應(yīng)用),不然地話,只要有一個(gè)新的連接過來,web容器都需要?jiǎng)?chuàng)建Session概念,維護(hù)狀態(tài)信息.
    但是Session是什么?Session僅僅是一個(gè)概念:"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."--簡單地講,保存用戶狀態(tài)信息.
    所以說,我們完全可以根據(jù)應(yīng)用的需求,定制Session的實(shí)現(xiàn):
    a. Session保存到JVM內(nèi)容中--Tomcat默認(rèn)的實(shí)現(xiàn)
    b. Session保存到Cookie中--Cookie-Based Session
    c. Session保存到本地文件--Tomcat提供的非默認(rèn)實(shí)現(xiàn)之一
    d. Session保存到Cache Store中--比如常見的Memcached
    e. Session保存到數(shù)據(jù)庫中--比如保存到mysql數(shù)據(jù)庫session表,中間對于活躍的Session 緩存到cached中.
    ......
    那么,假如一個(gè)應(yīng)用有大量一次性不同用戶的請求(僅僅是一次性的,比如上述文章描述的場景),那么選擇c,d,e方案都能有效解決文中所描述的問題.  回復(fù)  更多評論   

    # re: Tomcat(6.0.14) Session創(chuàng)建機(jī)制簡介 2010-03-07 18:27 小菜花

    @stone2083
    恩,之前我也遇到這個(gè)問題,也是性能測試的時(shí)候發(fā)現(xiàn)內(nèi)存下不來,后來發(fā)現(xiàn)是session對象過多,我們在測試的時(shí)候有傳遞sessionid給服務(wù)器,后來沒找到為啥還是有過多session的原因,后來不了了之了,因?yàn)榫€上基本上不會(huì)出現(xiàn)這種情況  回復(fù)  更多評論   

    # re: Tomcat(6.0.14) Session創(chuàng)建機(jī)制簡介 2010-06-11 20:23 stone2083

    @小菜花
    理論上來說,傳遞jsessionid,只要value是一致的,服務(wù)端不會(huì)創(chuàng)建多份session.
    可以在測試環(huán)境下通過debug 或者 監(jiān)控工具,跟蹤下創(chuàng)建多份session的情況.  回復(fù)  更多評論   

    主站蜘蛛池模板: 久久久久亚洲AV片无码| 黄色视频在线免费观看| 亚洲国产精品SSS在线观看AV| 在线不卡免费视频| 无码国产精品一区二区免费模式 | 亚洲人6666成人观看| 91麻豆精品国产自产在线观看亚洲| 好男人视频在线观看免费看片 | 久久亚洲精品无码AV红樱桃| 亚洲精品乱码久久久久久蜜桃 | 亚洲国产精品综合福利专区| 亚洲国产精品无码久久久蜜芽| 亚洲AV无码不卡在线观看下载| 一二三四在线播放免费观看中文版视频 | 野花视频在线官网免费1| 国产成人精品日本亚洲网址| 亚洲综合无码一区二区| 狠狠色伊人亚洲综合成人| 亚洲国产精品成人久久蜜臀 | 亚洲色偷精品一区二区三区 | 免费看的成人yellow视频| 亚洲三级高清免费| aⅴ免费在线观看| 精品一区二区三区免费毛片爱| 在线观看肉片AV网站免费| 黄色网页在线免费观看| 精品国产呦系列在线观看免费| 免费无码午夜福利片 | 免费看一级做a爰片久久| 国产成人高清精品免费软件| 成人黄软件网18免费下载成人黄18免费视频 | 污网站在线观看免费| 极品美女一级毛片免费| 黄色a级免费网站| 一级毛片免费毛片毛片| 一区视频免费观看| 国产VA免费精品高清在线| 精品人妻系列无码人妻免费视频| eeuss影院www天堂免费| 国产性生大片免费观看性| 最新国产乱人伦偷精品免费网站 |