论坛首页 Java企业应用论坛

分布式Session的一个实现.

浏览 22780 次
精华帖 (1) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2013-06-14  
本来一个Tomcat集群4台服务器工作的很好,随着访问量的增加本来的粘性Session方式的配置没办法很好的一碗水端平了.Session复制的话对于网络又是一个负担,所以才自己实现了一套利用Memcache的Session实现.

网上已经有很多这样的实现了,比如修改Tomcat的Manager的http://code.google.com/p/memcached-session-manager/.

但由于我这里还有其他的Servlet容器,所以也就没有使用完全自己实现了一套,现在运行在www.etnet.com.cn网站上.

从那开始呢....其他的Servlet容器我总不能再一一去实现吧。。。。最后还是决定使用过滤器来偷梁换柱了.

先是  CacheSessionFilter ,这个过滤器负责将普通的HttpServletRequest替换成我们自己的实现.

public class CacheSessionFilter extends BaseFilter {

    **
     * 替换原始的Request,修改为
     * com.etnetchina.servlet.wrapper.CacheSessionHttpServletReqeust。
     * 并根据是否新生成了Session来更新客户端的cookie.
     * 
     * @param request 请求。
     * @param response 响应。
     * @param chain 下一个过滤器。
     * @throws java.io.IOException
     * @throws javax.servlet.ServletException
     */
    public void doFilter(
            ServletRequest request,
            ServletResponse response,
            FilterChain chain)
            throws IOException, ServletException {
        logger.debugLog("CacheSessionFilter to work.");

        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        CacheSessionHttpServletReqeust cacheRequest =
                new CacheSessionHttpServletReqeust(
                httpRequest,
                httpResponse,
                filterConfig.getServletContext());
        cacheRequest.setSessionCookieName(sessionCookieName);
        cacheRequest.setMaxInactiveInterval(maxInactiveInterval);
        cacheRequest.setCookieDomain(cookieDomain);
        cacheRequest.setCookieContextPath(cookieContextPath);
        cacheRequest.setSessionAttributeListeners(sessionAttributeListeners);
        cacheRequest.setSessionListeners(sessionListeners);

        chain.doFilter(cacheRequest, httpResponse);

        CacheHttpSession cacheSession = cacheRequest.currentSession();
        if (cacheSession != null) {
            if (!cacheSession.synchronizationCache()) {
                WebUtil.failureCookie(
                        httpRequest,
                        httpResponse,
                        sessionCookieName,
                        cookieDomain,
                        cookieContextPath);
            }
        }
    }
}


这个过滤器的核心就是doFilter方法了,做了三件事.
第一是替换HttpServletRequest.
第二是如果Session失效,负责删除Cookie中的SessionId.
最后一件就是如果Session中的数据被改变了同步到缓存中.

现在重点是我们换上的CacheHttpServletRequest有什么用呢,很简单只是在应用调用getSession()方法时返回我们实现的Session.其核心的代码很简单,如下.
private HttpSession doGetSession(boolean create) {
        if (cacheSession != null) {
            //local,return.
            logger.debugLog("Session[{0}] was existed.", cacheSession.getId());
        } else {
            Cookie cookie = WebUtil.findCookie(this, getSessionCookieName());
            if (cookie != null) {

                logger.debugLog("Find session`s id from cookie.[{0}]",
                        cookie.getValue());

                cacheSession = buildCacheHttpSession(cookie.getValue(), false);
            } else {
                cacheSession = buildCacheHttpSession(create);
            }
        }

        if (cacheSession != null) {
            //dead?
            if (cacheSession.isInvalid()) {
                cacheSession.invalidate();
                cacheSession.synchronizationCache();
                cacheSession = buildCacheHttpSession(create);
            }

            if (cacheSession != null) {
                cacheSession.access();
            }
        }

        return cacheSession;
}


getSession()和getSession(boolean)方法实际调用的就是这个方法,为了减少创建的损耗在一次请求中利保只会创建一次.最后更新一下这个Session的最后访问时间.

每一次请求结束,都会进行一次缓存同步.由于每次讲求都会造成访问时间的更新,所以这个值是一直会被put到缓存中的.

启用只需要在web.xml做如下配置.

<filter>
        <description>修改默认的Session储存机制,改为使用某个缓存来储存。</description>
        <filter-name>CacheSessionFilter</filter-name>
        <filter-class>com.etnetchina.servlet.filter.session.CacheSessionFilter</filter-class>
        <init-param>
            <description>sessionId在Cookie中的名称</description>
            <param-name>sessionCookieName</param-name>
            <param-value>etnetsessionid</param-value>
        </init-param>
        <init-param>
            <description>Session的最大不活动时间(秒)</description>
            <param-name>maxInactiveInterval</param-name>
            <param-value>60</param-value>
        </init-param>
    </filter>


还可以有以下参数可配置
cookieDomain为存放cookie的域设置。默认为null.
cookieContextPath为存放cookie的路径。如果不设置将使用默认的contextPath.
sessionAttributeListeners 为HttpSessionAttributeListener监听器实现类全限定名,多个名称以","分隔.
sessionListeners 为HttpSessionListener监听器实现类的全限定名,多个名称以","分隔.

<filter-mapping>
        <filter-name>CacheSessionFilter</filter-name>
        <url-pattern>/*</url-pattern>
</filter-mapping>

加上一个过滤器就行了.

最后我提供上完整的源代码,有兴趣的可以提提自己的建议.代码是提供了OSCache和XMemCached的包装实现.
上传的压缩包是一个Netbeans的项目,如果你用的是Eclipse那么直接导入就可以了.
   发表时间:2013-06-15   最后修改:2013-06-15
引用
每一次请求结束,都会进行一次缓存同步.由于每次讲求都会造成访问时间的更新,所以这个值是一直会被put到缓存中的.
给个建议: 只有当用户操作attribute时 同步 缓存  其他情况一律如5分钟更新一次(更新时间戳)[可以加个本地缓存,这不需要每次都从远程取session了]。 还有如游客 也无需同步。目前我使用这个来保存session信息。

https://github.com/zhangkaitao/es/blob/master/web/src/main/java/org/apache/shiro/session/mgt/eis/OnlineSessionDAO.java
0 请登录后投票
   发表时间:2013-06-16  
分布式Session
0 请登录后投票
   发表时间:2013-06-16  
和淘宝的搞法简直一模一样
0 请登录后投票
   发表时间:2013-06-16  
liyebing 写道
和淘宝的搞法简直一模一样

淘宝人写的
0 请登录后投票
   发表时间:2013-06-17  
jinnianshilongnian 写道
引用
每一次请求结束,都会进行一次缓存同步.由于每次讲求都会造成访问时间的更新,所以这个值是一直会被put到缓存中的.
给个建议: 只有当用户操作attribute时 同步 缓存  其他情况一律如5分钟更新一次(更新时间戳)[可以加个本地缓存,这不需要每次都从远程取session了]。 还有如游客 也无需同步。目前我使用这个来保存session信息。

https://github.com/zhangkaitao/es/blob/master/web/src/main/java/org/apache/shiro/session/mgt/eis/OnlineSessionDAO.java

您的这个开源项目是搞什么用的呢?
0 请登录后投票
   发表时间:2013-06-17  
kiven 写道
jinnianshilongnian 写道
引用
每一次请求结束,都会进行一次缓存同步.由于每次讲求都会造成访问时间的更新,所以这个值是一直会被put到缓存中的.
给个建议: 只有当用户操作attribute时 同步 缓存  其他情况一律如5分钟更新一次(更新时间戳)[可以加个本地缓存,这不需要每次都从远程取session了]。 还有如游客 也无需同步。目前我使用这个来保存session信息。

https://github.com/zhangkaitao/es/blob/master/web/src/main/java/org/apache/shiro/session/mgt/eis/OnlineSessionDAO.java

您的这个开源项目是搞什么用的呢?

项目开发脚手架  
0 请登录后投票
   发表时间:2013-06-17  
session 在缓存服务器之间是如何同步的?
0 请登录后投票
   发表时间:2013-06-17  
https://code.google.com/p/memcached-session-filter/
  • 大小: 325.1 KB
  • 大小: 315.8 KB
  • 大小: 77.7 KB
  • 大小: 153.4 KB
  • 大小: 144.7 KB
  • 大小: 42.7 KB
  • 大小: 42.7 KB
0 请登录后投票
   发表时间:2013-06-17  
jinnianshilongnian 写道
引用
每一次请求结束,都会进行一次缓存同步.由于每次讲求都会造成访问时间的更新,所以这个值是一直会被put到缓存中的.
给个建议: 只有当用户操作attribute时 同步 缓存  其他情况一律如5分钟更新一次(更新时间戳)[可以加个本地缓存,这不需要每次都从远程取session了]。 还有如游客 也无需同步。目前我使用这个来保存session信息。

https://github.com/zhangkaitao/es/blob/master/web/src/main/java/org/apache/shiro/session/mgt/eis/OnlineSessionDAO.java



对,现在只有Session中的属性被修改时才会同步缓存,但是这个访问时间暂时还是每次请求结束都会PUT一下缓存.

因为我们的应用里面会对Session的最后访问时间进行检测做一下业务判断,以后我会增加一个开关如果不需要最后访问时间的精准那么可以考虑异步的积累到一定时间再去更新一次等.

我觉得放到Session里的东西,放太大的东西这本身就是个问题了吧?(个人意见)
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics