zoukankan      html  css  js  c++  java
  • memcached session

    一、需求背景

    一般的 servlet 容器(如 tomcat, resin 等)实现的 javax.servlet.http.HttpSession 的可见性都仅局限于一个 web 应用程序内,即使运行在同一个 JVM 里两个不同的 web 应用之间也不可共享 session 信息。通常情况下,我们可以考虑把会话状态信息保存在数据库中或者构建一个分布式 session 服务。 Memcached-session-0.9.jar (命名为 0.9 的原因是没有经过全面测试,但基本够用)是利用memcached 作为 session 服务器构建的一个分布式可共享 sesssion 解决方案。 Memcached-session 中的信息能够被多个共享顶级域名的 web 应用所共享(注:由于 memcached-session 的 sessionid 也是借助于 cookie 的,为防止 cookie 跨域的问题,必须要求各个 web 应用在相同的顶级域名下。 对于,要跨顶级域名的多个 web 应用程序共享 session 的问题,需要解决 cookie 跨域的问题,通常的做法是通过重定向的方式让 sessionid 在第三方的一个域上生成,详细情况可参考《 SSO(UserID 方式 )SP 与 SSO 之间的通信接口 V0.1.doc 》设计文档)。

    二、使用步骤

    ( 1 )安装 memcached 服务端并启动在默认端口 11211 ,可以选择 windows 或 linux 版本

           注:所有的会话信息都以 SessionID 到 SessionObject (本身也是个类似 Map 的数据结构)键值对形式保存在 memcached 服务器端,各个 web 应用程序再通过 memcached 客户端来访问。这一点跟信息保存在数据库服务器上,各应用程序再通过 SQL 客户端来访问是一个道理。

    ( 2 )获取 memcached-session-0.9.jar 包,将该包及其依赖的 java_memcached_release_1.5.jar 和 commons-logging-1.0.4.jar 导入 WEB-INF/lib 目录下

           注: memcached-session-0.9.jar 依赖于 java_memcached_release_1.5.jar ( memcached 服务器的 java 客户端)和commons-logging-1.0.4.jar ( apache 的日志组件)

    ( 3 )编辑 memcached.properties 配置文件,以保证 memcached 客户端能够正确地访问 memcached 服务端。

    注: memcached-session-0.9.jar 是依据 classpath 去寻找 memcached.properties 配置文件的,所以必须保证memcached.properties 配置文件在 classpath 的根路径下,而且名称必须是 memcached.properties 。

    样例

    servers=127.0.0.1:11211,10.10.41.186:11211   (多个服务器之间用“ , ”隔开)

    init-connection = 10

    min-connection = 5

    max-connection = 20

    maint-sleep-millis = 30

    active-check = true

    failover = true

    nagle = false

    ( 4 )在 web.xml 中配置 MemcachedFilter ,以替换 sevlet 容器自有的 HttpSession 实现。

    <filter>

                  <display-name>MemcachedFilter</display-name>

                  <filter-name>MemcachedFilter</filter-name>

                  <filter-class>com.umpay.session.MemcachedFilter <!-- [if !supportAnnotations]-->[lw1] <!-- [endif]-->  </filter-class>

                  <init-param>

                         <param-name>uuidCookieName <!-- [if !supportAnnotations]-->[lw2] <!-- [endif]-->  </param-name>

                         <param-value>uuid</param-value>

                  </init-param>

                  <init-param>

                         <param-name>uuidCookieDomain</param-name>

                         <param-value></param-value>

                  </init-param>

                  <init-param>

                         <param-name>uuidCookiePath</param-name>

                         <param-value>/</param-value>

                  </init-param>

                  <init-param>

                         <param-name>uuidCookieMaxAge <!-- [if !supportAnnotations]-->[lw3] <!-- [endif]-->  </param-name>

                         <param-value>-1</param-value>

                  </init-param>

           </filter>

           <filter-mapping>

                  <filter-name>MemcachedFilter</filter-name>

                  <url-pattern>/* <!-- [if !supportAnnotations]-->[lw4] <!-- [endif]-->  </url-pattern>

           </filter-mapping>

    ( 5 )透明地使用 MemcachedSession

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

           int c = 1;

           String count = (String)request.getSession() . <!-- [if !supportAnnotations]-->[lw5] <!-- [endif]-->  getAttribute( FLAG );

           if (count != null ) {

               c = Integer.parseInt (count)+1;

           }

           request.getSession().setAttribute( FLAG , c+ "" );

           request.getSession().setAttribute( "LastIP" , request.getRemoteAddr());

          

           PrintWriter writer = response.getWriter();

          

           request.getSession().setMaxInactiveInterval(8);

           writer.write( "MaxInactiveInterval = " + request.getSession().getMaxInactiveInterval()+ " second" );writer.println();

          

           writer.write( "you accessed this page at time " + c);writer.println();

           writer.write( "SESSIONID = " + request.getSession().getId());writer.println();

           writer.println();

          

           Enumeration<String> attrs = request.getSession().getAttributeNames();

           while (attrs.hasMoreElements()) {

               String key = attrs.nextElement();

               writer.write( "AttrEnum ->" +key+ "=" +request.getSession().getAttribute(key));

               writer.println();

           }

          

           writer.println();

           writer.write( "CreationTime = " + new Date(request.getSession().getCreationTime()));

           writer.println();

           writer.write( "LastAccessedTime = " + new Date(request.getSession().getLastAccessedTime()));

           writer.println();

          

        }

    三、报文分析

    ( 1 )初次访问时

    请求报文:

    (Request-Line)       GET /MemSession/counter HTTP/1.1

    Host localhost:8080

    User-Agent     Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5

    Accept    text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

    Accept-Language   zh-cn,zh;q=0.5

    Accept-Encoding    gzip,deflate

    Accept-Charset      gb2312,utf-8;q=0.7,*;q=0.7

    Keep-Alive      300

    Connection     keep-alive

    Cache-Control max-age=0

    响应报文:

    (Status-Line)   HTTP/1.1 200 OK

    Server     Apache-Coyote/1.1

    Set-Cookie    uuid=532b 3c 0b-c78e-4c2f-81fa-295ab9a57acf; Domain=""; Path=/ <!-- [if !supportAnnotations]-->[lw6] <!-- [endif]--> 

    Set-Cookie      JSESSIONID=2560E054058B509381421BB017D 8A 418; Path=/MemSession <!-- [if !supportAnnotations]-->[lw7] <!-- [endif]--> 

    Content-Length      272

    Date Fri, 19 Jun 2009 05:22:02 GMT

    (响应包体内容)

    MaxInactiveInterval = 8 second

    you accessed this page at time 1

    SESSIONID = 532b3c0b-c78e-4c2f-81fa-295ab9a57acf

    AttrEnum ->LastIP=127.0.0.1

    AttrEnum ->SessionCounter=1

    CreationTime = Fri Jun 19 13:22:11 CST 2009

    LastAccessedTime = Fri Jun 19 13:22:14 CST 2009

    ( 2 )再次访问时

    请求报文:

    (Request-Line)       GET /MemSession/counter HTTP/1.1

    Host localhost:8080

    User-Agent     Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5

    Accept    text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

    Accept-Language   zh-cn,zh;q=0.5

    Accept-Encoding    gzip,deflate

    Accept-Charset      gb2312,utf-8;q=0.7,*;q=0.7

    Keep-Alive      300

    Connection     keep-alive

    Cookie    JSESSIONID=2560E054058B509381421BB017D8A418; uuid=532b 3c 0b-c78e-4c2f-81fa-295ab9a57acf <!-- [if !supportAnnotations]-->[lw8] <!-- [endif]--> 

    Cache-Control max-age=0

    响应报文:

    (Status-Line)   HTTP/1.1 200 OK

    Server     Apache-Coyote/1.1

    Content-Length      272

    Date Fri, 19 Jun 2009 05:22:11 GMT

    (响应包体内容)

    MaxInactiveInterval = 8 second

    you accessed this page at time 2

    SESSIONID = 532b3c0b-c78e-4c2f-81fa-295ab9a57acf

    AttrEnum ->LastIP=127.0.0.1

    AttrEnum ->SessionCounter=2

    CreationTime = Fri Jun 19 13:22:11 CST 2009

    LastAccessedTime = Fri Jun 19 13:22:14 CST 2009

    四、 FAQ

    ( 1 ) web 应用程序重启, MemcachedSession 信息会不会丢失呀?

          

    答:不会, MemcachedSession 信息是保存在 Memcached 服务端的,各个 web 应用只是通过 memcached-session-0.9.jar 去访问 Memcached 服务端。只有 Memcached 服务端重启时,信息才会丢失。

    ( 2 )服务端 MemcachedSession 的过期时间如何设置?

           答:在 web.xml 的 com.umpay.session.MemcachedFilter 的 initParam 初始化配置时通过

    <init-param>

                  <param-name>uuidCookieMaxAge</param-name>

                  <param-value>-1</param-value>

    </init-param>

    可以配置,该配置对所有客户端生效;

    也可以对某个浏览器专门使用 request.getSession().setMaxInactiveInterval(8); 来设置特定的超时时间。在实现机制上, memcached-session-0.9.jar 会在从 memcached 服务端取回数据时,依据系统当前时间 - 最后一次访问时间来判断 MemcachedSession 是否过期,如果过期,此时才删除服务端的数据。也就是说只有当数据已经过期,并且浏览器触发该数据的访问时 MemcachedSession 才会从服务端真的删除,否则只有让 memcached 自己删除。

    <!-- [if !supportAnnotations]-->
    <!-- [endif]-->
    <!-- [if !supportAnnotations]-->
    <!-- [endif]--><!-- [if !supportAnnotations]--> <!-- [endif]-->

     <!-- [if !supportAnnotations]-->[lw1] <!-- [endif]--> Memcached-session-0.9.jar 中的组件,并在 init-param 中配置该组件的初始化参数

    <!-- [if !supportAnnotations]-->
    <!-- [endif]-->
    <!-- [if !supportAnnotations]-->
    <!-- [endif]--><!-- [if !supportAnnotations]--> <!-- [endif]-->

     <!-- [if !supportAnnotations]-->[lw2] <!-- [endif]--> memcachedSession 的 sessionid 也是基于 cookie 的,且 sessionid 的生成规则是UUID 。

    <!-- [if !supportAnnotations]-->
    <!-- [endif]-->
    <!-- [if !supportAnnotations]-->
    <!-- [endif]--><!-- [if !supportAnnotations]--> <!-- [endif]-->

     <!-- [if !supportAnnotations]-->[lw3] <!-- [endif]--> 指定服务端 sessionid 失效时间,其中 >0 表示在指定时间(秒)后失效; =0 表示永远不失效; <0 默认 30 分钟后失效。

    <!-- [if !supportAnnotations]-->
    <!-- [endif]-->
    <!-- [if !supportAnnotations]-->
    <!-- [endif]--><!-- [if !supportAnnotations]--> <!-- [endif]-->

     <!-- [if !supportAnnotations]-->[lw4] <!-- [endif]--> 指定对哪些 url 请求的自有 HttpSession 被 MemcachedSession 替换掉。

    <!-- [if !supportAnnotations]-->
    <!-- [endif]-->
    <!-- [if !supportAnnotations]-->
    <!-- [endif]--><!-- [if !supportAnnotations]--> <!-- [endif]-->

     <!-- [if !supportAnnotations]-->[lw5] <!-- [endif]--> 获取的 Session 实现实例实际是 com.umpay.session.MemcachedSession ,采用的是装饰器模式给偷梁换柱了。

    <!-- [if !supportAnnotations]-->
    <!-- [endif]-->
    <!-- [if !supportAnnotations]-->
    <!-- [endif]--><!-- [if !supportAnnotations]--> <!-- [endif]-->

     <!-- [if !supportAnnotations]-->[lw6] <!-- [endif]--> 用户自己定义的 MemcachedSession 对应的 uuid

    <!-- [if !supportAnnotations]-->
    <!-- [endif]-->
    <!-- [if !supportAnnotations]-->
    <!-- [endif]--><!-- [if !supportAnnotations]--> <!-- [endif]-->

     <!-- [if !supportAnnotations]-->[lw7] <!-- [endif]--> Servlet 容器自有的 SessionID

    <!-- [if !supportAnnotations]-->
    <!-- [endif]-->
    <!-- [if !supportAnnotations]-->
    <!-- [endif]--><!-- [if !supportAnnotations]--> <!-- [endif]-->

     <!-- [if !supportAnnotations]-->[lw8] <!-- [endif]--> 浏览器在再次访问同一域下的 URL 时,主动把先前下发的 uuid 的 cookie 信息包裹在请求报文中,以便服务端依据该 ID 匹配 MemcachedSession 对象。

    <!-- [if !supportAnnotations]-->
    <!-- [endif]-->
  • 相关阅读:
    【搜索】【并查集】Codeforces 691D Swaps in Permutation
    【模拟】Codeforces 691C Exponential notation
    【模拟】Codeforces 691B s-palindrome
    【模拟】Codeforces 691A Fashion in Berland
    【贪心】HDU 5783 Divide the Sequence
    【动态规划】HDU 5791 Two
    【中途相遇法】【STL】BAPC2014 K Key to Knowledge (Codeforces GYM 100526)
    【线段树】BAPC2014 E Excellent Engineers (Codeforces GYM 100526)
    【扩展欧几里得】BAPC2014 I Interesting Integers (Codeforces GYM 100526)
    【最大流】BAPC2014 A Avoiding the Apocalypse (Codeforces GYM 100526)
  • 原文地址:https://www.cnblogs.com/chenzhao/p/2355855.html
Copyright © 2011-2022 走看看