`
xiangxingchina
  • 浏览: 520287 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

基于memcached的SNA实现

阅读更多

系统要集群,使用SNA方案。
一、 缓存的处理
缓存要使用统一的缓存服务器,集中式缓存。
原先的实现采用ehcache。
在spring里的配置,以资源缓存为例:

Xml代码
  1. <!-- EhCache Manager -->   
  2.     < bean   id = "cacheManager"   class = "org.springframework.cache.ehcache.EhCacheManagerFactoryBean" >   
  3.         < property   name = "configLocation" >   
  4.             < value > classpath:ehcache.xml </ value >   
  5.         </ property >   
  6. </ bean >   
  7.   
  8. < bean   id = "resourceCacheBackend"   
  9.           class = "org.springframework.cache.ehcache.EhCacheFactoryBean" >   
  10.         < property   name = "cacheManager"   ref = "cacheManager" />   
  11.         < property   name = "cacheName"   value = "resourceCache" />   
  12.     </ bean >   
  13.   
  14.     < bean   id = "resourceCache"   
  15.           class = "com.framework.extcomponent.security.authentication.services.acegi.cache.EhCacheBasedResourceCache"   
  16.           autowire = "byName" >   
  17.         < property   name = "cache"   ref = "resourceCacheBackend" />   
  18.     </ bean >   
<!-- EhCache Manager -->
    <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
        <property name="configLocation">
            <value>classpath:ehcache.xml</value>
        </property>
</bean>

<bean id="resourceCacheBackend"
          class="org.springframework.cache.ehcache.EhCacheFactoryBean">
        <property name="cacheManager" ref="cacheManager"/>
        <property name="cacheName" value="resourceCache"/>
    </bean>

    <bean id="resourceCache"
          class="com.framework.extcomponent.security.authentication.services.acegi.cache.EhCacheBasedResourceCache"
          autowire="byName">
        <property name="cache" ref="resourceCacheBackend"/>
    </bean>

 

cacheManager负责对ehcache进行管理,初始化、启动、停止。
resourceCacheBackend负责实际执行缓存操作,put 、get、remove。
resourceCache实现具有业务语义的业务应用层面的缓存操作,内部调用resourceCacheBackend操作。

现在采用memcached。
关于客户端,采用文初封装的客户端,地址在http://code.google.com/p/memcache-client-forjava/
使用spring的FactoryBean进行二次封装。同理:
memcachedManager负责对memcached进行管理,初始化、启动、停止。
代码:

Java代码
  1. /**  
  2. * User: ronghao  
  3. * Date: 2008-10-14  
  4. * Time: 10:36:30  
  5. * 管理Memcached 的CacheManager  
  6. */   
  7. public   class  MemcachedCacheManagerFactoryBean  implements  FactoryBean, InitializingBean, DisposableBean {  
  8.   
  9.     protected   final  Log logger = LogFactory.getLog(getClass());  
  10.   
  11.     private  ICacheManager<IMemcachedCache> cacheManager;  
  12.   
  13.     public  Object getObject()  throws  Exception {  
  14.         return  cacheManager;  
  15.     }  
  16.   
  17.     public  Class getObjectType() {  
  18.         return   this .cacheManager.getClass();  
  19.     }  
  20.   
  21.     public   boolean  isSingleton() {  
  22.         return   true ;  
  23.     }  
  24.   
  25.     public   void  afterPropertiesSet()  throws  Exception {  
  26.         logger.info("Initializing Memcached CacheManager" );  
  27.         cacheManager = CacheUtil.getCacheManager(IMemcachedCache.class ,  
  28.                 MemcachedCacheManager.class .getName());  
  29.         cacheManager.start();  
  30.     }  
  31.   
  32.     public   void  destroy()  throws  Exception {  
  33.         logger.info("Shutting down Memcached CacheManager" );  
  34.         cacheManager.stop();  
  35.     }  
  36. }  
/**
* User: ronghao
* Date: 2008-10-14
* Time: 10:36:30
* 管理Memcached 的CacheManager
*/
public class MemcachedCacheManagerFactoryBean implements FactoryBean, InitializingBean, DisposableBean {

    protected final Log logger = LogFactory.getLog(getClass());

    private ICacheManager<IMemcachedCache> cacheManager;

    public Object getObject() throws Exception {
        return cacheManager;
    }

    public Class getObjectType() {
        return this.cacheManager.getClass();
    }

    public boolean isSingleton() {
        return true;
    }

    public void afterPropertiesSet() throws Exception {
        logger.info("Initializing Memcached CacheManager");
        cacheManager = CacheUtil.getCacheManager(IMemcachedCache.class,
                MemcachedCacheManager.class.getName());
        cacheManager.start();
    }

    public void destroy() throws Exception {
        logger.info("Shutting down Memcached CacheManager");
        cacheManager.stop();
    }
}
 


配置:

Xml代码
  1. < bean   id = "memcachedManager"   
  2.           class = "com.framework.extcomponent.cache.MemcachedCacheManagerFactoryBean" />   
<bean id="memcachedManager"
          class="com.framework.extcomponent.cache.MemcachedCacheManagerFactoryBean"/>
 


resourceCacheBackend负责实际执行缓存操作,put 、get、remove。
代码:

Java代码
  1. /**  
  2. * User: ronghao  
  3. * Date: 2008-10-14  
  4. * Time: 10:37:16  
  5. * 返回  MemcachedCache  
  6. */   
  7. public   class  MemcachedCacheFactoryBean  implements  FactoryBean, BeanNameAware, InitializingBean {  
  8.   
  9.     protected   final  Log logger = LogFactory.getLog(getClass());  
  10.   
  11.     private  ICacheManager<IMemcachedCache> cacheManager;  
  12.     private  String cacheName;  
  13.     private  String beanName;  
  14.     private  IMemcachedCache cache;  
  15.   
  16.     public   void  setCacheManager(ICacheManager<IMemcachedCache> cacheManager) {  
  17.         this .cacheManager = cacheManager;  
  18.     }  
  19.   
  20.     public   void  setCacheName(String cacheName) {  
  21.         this .cacheName = cacheName;  
  22.     }  
  23.   
  24.     public  Object getObject()  throws  Exception {  
  25.         return  cache;  
  26.     }  
  27.   
  28.     public  Class getObjectType() {  
  29.         return   this .cache.getClass();  
  30.     }  
  31.   
  32.     public   boolean  isSingleton() {  
  33.         return   true ;   
  34.     }  
  35.   
  36.     public   void  setBeanName(String name) {  
  37.         this .beanName=name;  
  38.     }  
  39.   
  40.     public   void  afterPropertiesSet()  throws  Exception {  
  41.         // If no cache name given, use bean name as cache name.   
  42.        if  ( this .cacheName ==  null ) {  
  43.         this .cacheName =  this .beanName;  
  44.     }  
  45.         cache = cacheManager.getCache(cacheName);  
  46.     }  
  47. }  
/**
* User: ronghao
* Date: 2008-10-14
* Time: 10:37:16
* 返回  MemcachedCache
*/
public class MemcachedCacheFactoryBean implements FactoryBean, BeanNameAware, InitializingBean {

    protected final Log logger = LogFactory.getLog(getClass());

    private ICacheManager<IMemcachedCache> cacheManager;
    private String cacheName;
    private String beanName;
    private IMemcachedCache cache;

    public void setCacheManager(ICacheManager<IMemcachedCache> cacheManager) {
        this.cacheManager = cacheManager;
    }

    public void setCacheName(String cacheName) {
        this.cacheName = cacheName;
    }

    public Object getObject() throws Exception {
        return cache;
    }

    public Class getObjectType() {
        return this.cache.getClass();
    }

    public boolean isSingleton() {
        return true; 
    }

    public void setBeanName(String name) {
        this.beanName=name;
    }

    public void afterPropertiesSet() throws Exception {
        // If no cache name given, use bean name as cache name.
       if (this.cacheName == null) {
		this.cacheName = this.beanName;
	}
        cache = cacheManager.getCache(cacheName);
    }
}
 


配置:

Xml代码
  1. < bean   id = "resourceCacheBackend"   
  2.           class = "com.framework.extcomponent.cache.MemcachedCacheFactoryBean" >   
  3.         < property   name = "cacheManager"   ref = "memcachedManager" />   
  4.         < property   name = "cacheName"   value = "memcache" />   
  5.     </ bean >   
<bean id="resourceCacheBackend"
          class="com.framework.extcomponent.cache.MemcachedCacheFactoryBean">
        <property name="cacheManager" ref="memcachedManager"/>
        <property name="cacheName" value="memcache"/>
    </bean>
 


resourceCache同上,替换新的实现类MemcachedBasedResourceCache即可。

二、 Session失效的处理
采用memcached作为httpsession的存储,并不直接保存httpsession对象,自定义SessionMap,SessionMap直接继承HashMap,保存SessionMap。

会话胶粘:未失败转发的情况下没必要在memcached保存的SessionMap和httpsession之间复制来复制去,眉来眼去。

利用memcached计数器保存在线人数。

系统权限采用了acegi,在acegi的拦截器链里配置snaFilter

Xml代码
  1. < bean   id = "filterChainProxy"   
  2.           class = "org.acegisecurity.util.FilterChainProxy" >   
  3.         < property   name = "filterInvocationDefinitionSource" >   
  4.             < value >   
  5.                 CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON  
  6.                 PATTERN_TYPE_APACHE_ANT  
  7.                 /**=snaFilter,httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,basicProcessingFilter,securityContextHolderAwareRequestFilter,exceptionTranslationFilter,filterInvocationInterceptor  
  8.             </ value >   
  9.         </ property >   
  10. </ bean >   
<bean id="filterChainProxy"
          class="org.acegisecurity.util.FilterChainProxy">
        <property name="filterInvocationDefinitionSource">
            <value>
                CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
                PATTERN_TYPE_APACHE_ANT
                /**=snaFilter,httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,basicProcessingFilter,securityContextHolderAwareRequestFilter,exceptionTranslationFilter,filterInvocationInterceptor
            </value>
        </property>
</bean>
 


注意需要配置在第一个。
snaFilter的职责:
1、 没有HttpSession时,创建HttpSession;
2、 创建Cookie保存HttpSession id;
3、 如果Cookie保存的HttpSession id与当前HttpSession id一致,说明是正常请求;
4、 如果Cookie保存的HttpSession id与当前HttpSession id不一致,说明是失败转发;失败转发的处理:
     4.1、根据Cookie保存的HttpSession id从memcached获取SessionMap;
     4.2、SessionMap属性复制到当前HttpSession;
     4.3、memcached删除SessionMap。
5、 判断当前请求url是否是登出url,是则删除SessionMap,在线人数减1.

代码:

Java代码
  1. public   void  doFilter(ServletRequest servletRequest, ServletResponse servletResponse,  
  2.                          FilterChain filterChain) throws  IOException, ServletException {  
  3.         final  HttpServletRequest hrequest = (HttpServletRequest) servletRequest;  
  4.         final  HttpServletResponse hresponse = (HttpServletResponse) servletResponse;  
  5.         String uri = hrequest.getRequestURI();  
  6.         logger.debug("开始SNA拦截-----------------"  + uri);  
  7.         HttpSession httpSession = hrequest.getSession();  
  8.         String sessionId = httpSession.getId();  
  9.         //如果是登出,则直接干掉sessionMap   
  10.         if  (uri.equals(logoutUrl)) {  
  11.             logger.debug("remove sessionmap:"  + sessionId);  
  12.             //在线人数减1   
  13.             getCache().addOrDecr("userCount" , 1 );  
  14.             getCache().remove(sessionId);  
  15.         } else  {  
  16.             String cookiesessionid = getSessionIdFromCookie(hrequest, hresponse);  
  17.             if  (!sessionId.equals(cookiesessionid)) {  
  18.                 createCookie(sessionId, hresponse);  
  19.                 SessionMap sessionMap = getSessionMap(cookiesessionid);  
  20.                 if  (sessionMap !=  null ) {  
  21.                     logger.debug("fail over--------sessionid:"  + sessionId +  "cookiesessionid:"  + cookiesessionid);  
  22.                     initialHttpSession(sessionMap, httpSession);  
  23.                     cache.remove(cookiesessionid);  
  24.                 }  
  25.             }  
  26.         }  
  27.         filterChain.doFilter(hrequest, hresponse);  
  28. }  
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
                         FilterChain filterChain) throws IOException, ServletException {
        final HttpServletRequest hrequest = (HttpServletRequest) servletRequest;
        final HttpServletResponse hresponse = (HttpServletResponse) servletResponse;
        String uri = hrequest.getRequestURI();
        logger.debug("开始SNA拦截-----------------" + uri);
        HttpSession httpSession = hrequest.getSession();
        String sessionId = httpSession.getId();
        //如果是登出,则直接干掉sessionMap
        if (uri.equals(logoutUrl)) {
            logger.debug("remove sessionmap:" + sessionId);
            //在线人数减1
            getCache().addOrDecr("userCount",1);
            getCache().remove(sessionId);
        } else {
            String cookiesessionid = getSessionIdFromCookie(hrequest, hresponse);
            if (!sessionId.equals(cookiesessionid)) {
                createCookie(sessionId, hresponse);
                SessionMap sessionMap = getSessionMap(cookiesessionid);
                if (sessionMap != null) {
                    logger.debug("fail over--------sessionid:" + sessionId + "cookiesessionid:" + cookiesessionid);
                    initialHttpSession(sessionMap, httpSession);
                    cache.remove(cookiesessionid);
                }
            }
        }
        filterChain.doFilter(hrequest, hresponse);
}
 



利用HttpSessionAttributeListener监听httpsession的属性变化,同步到memecached中的sessionmap。

Java代码
  1. public   void  attributeAdded(HttpSessionBindingEvent event) {  
  2.         HttpSession httpSession = event.getSession();  
  3.         String attrName = event.getName();  
  4.         Object attrValue = event.getValue();  
  5.         String sessionId = httpSession.getId();  
  6.         logger.debug("attributeAdded sessionId:"  + sessionId +  "name:"  + attrName +  ",value:"  + attrValue);  
  7.         SessionMap sessionMap = getSessionMap(sessionId);  
  8.         if  (sessionMap ==  null ){  
  9.             //在线人数加1   
  10.             getCache().addOrIncr("userCount" , 1 );  
  11.             sessionMap = new  SessionMap();  
  12.         }  
  13.         logger.debug("name:"  + attrName +  ",value:"  + attrValue);  
  14.         sessionMap.put(attrName, attrValue);  
  15.         getCache().put(sessionId, sessionMap);  
  16.     }  
  17.   
  18.     public   void  attributeRemoved(HttpSessionBindingEvent event) {  
  19.         HttpSession httpSession = event.getSession();  
  20.         String attrName = event.getName();  
  21.         String sessionId = httpSession.getId();  
  22.         logger.debug("attributeRemoved sessionId:"  + sessionId +  "name:"  + attrName);  
  23.         SessionMap sessionMap = getSessionMap(sessionId);  
  24.         if  (sessionMap !=  null ) {  
  25.             logger.debug("remove:"  + attrName);  
  26.             sessionMap.remove(attrName);  
  27.             getCache().put(sessionId, sessionMap);  
  28.         }  
  29.     }  
  30.   
  31.     public   void  attributeReplaced(HttpSessionBindingEvent event) {  
  32.         attributeAdded(event);  
  33.     }  
public void attributeAdded(HttpSessionBindingEvent event) {
        HttpSession httpSession = event.getSession();
        String attrName = event.getName();
        Object attrValue = event.getValue();
        String sessionId = httpSession.getId();
        logger.debug("attributeAdded sessionId:" + sessionId + "name:" + attrName + ",value:" + attrValue);
        SessionMap sessionMap = getSessionMap(sessionId);
        if (sessionMap == null){
            //在线人数加1
            getCache().addOrIncr("userCount",1);
            sessionMap = new SessionMap();
        }
        logger.debug("name:" + attrName + ",value:" + attrValue);
        sessionMap.put(attrName, attrValue);
        getCache().put(sessionId, sessionMap);
    }

    public void attributeRemoved(HttpSessionBindingEvent event) {
        HttpSession httpSession = event.getSession();
        String attrName = event.getName();
        String sessionId = httpSession.getId();
        logger.debug("attributeRemoved sessionId:" + sessionId + "name:" + attrName);
        SessionMap sessionMap = getSessionMap(sessionId);
        if (sessionMap != null) {
            logger.debug("remove:" + attrName);
            sessionMap.remove(attrName);
            getCache().put(sessionId, sessionMap);
        }
    }

    public void attributeReplaced(HttpSessionBindingEvent event) {
        attributeAdded(event);
    }
 



利用HttpSessionListener,sessionDestroyed事件时根据sessionid删除memcached里的sessionMap(如果存在)。不再担心httpsession的过期问题。

Java代码
  1. public   void  sessionDestroyed(HttpSessionEvent event) {  
  2.         HttpSession httpSession = event.getSession();  
  3.         String sessionId = httpSession.getId();  
  4.         logger.debug("session Removed sessionId:"  + sessionId);  
  5.         SessionMap sessionMap = getSessionMap(sessionId);  
  6.         if  (sessionMap !=  null ) {  
  7.             logger.debug("remove sessionmap:"  + sessionId);  
  8.             //在线人数减1   
  9.             getCache().addOrDecr("userCount" , 1 );  
  10.             getCache().remove(sessionId);  
  11.         }  
  12.     }  
public void sessionDestroyed(HttpSessionEvent event) {
        HttpSession httpSession = event.getSession();
        String sessionId = httpSession.getId();
        logger.debug("session Removed sessionId:" + sessionId);
        SessionMap sessionMap = getSessionMap(sessionId);
        if (sessionMap != null) {
            logger.debug("remove sessionmap:" + sessionId);
            //在线人数减1
            getCache().addOrDecr("userCount",1);
            getCache().remove(sessionId);
        }
    }
 



三、 文件保存的处理
和缓存类似,采用集中式的文件服务。对于linux,采用nfs。参考文档http://linux.vbird.org/linux_server/0330nfs.php#What_NFS_perm 。关键在于对权限的分配。
应用程序本身不用修改。

 

分享到:
评论

相关推荐

    基于memcached的云缓存ARCUS.zip

    Arcus 是一个基于 memcached 的云缓存,由 NAVER Corp 公司开发。 arcus-memcached 经过大幅度的修改,可以支持 NAVER 的功能和性能要求。Arcus 支持多种数据机构 (List, Set, B tree),除了支持基本的memcached ...

    基于Memcached的分布式Session共享插件设计源码

    该插件是一款基于Memcached的分布式Session共享解决方案源码,由21个文件组成,涵盖Java源代码、XML配置、项目结构等。支持Tomcat6及以上版本,旨在实现应用服务器集群间的Session共享,提高系统在分布式环境下的...

    C#使用memCached实现缓存

    C#使用memCached实现缓存 Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提供动态、数据库驱动网站的速度。...

    Tomcat基于memcached的session保持-nginx反代

    ### Tomcat 基于 Memcached 的 Session 保持与 Nginx 反向代理实现 在分布式系统中,为了提高应用的可用性和扩展性,通常会采用多台服务器集群部署的方式来提供服务。对于 Java Web 应用而言,Tomcat 是一个常见的...

    Memcached相关程序

    - Memcached通过将数据存储在内存中,实现了快速的数据检索,因为它避免了磁盘I/O操作。 2. **.NET 3.5中的Memcached支持**: - 在.NET环境中,我们可以使用各种库来与Memcached交互,如EnyimMemcached或...

    基于memcached client for java的cache封装

    本主题将深入探讨如何基于Java客户端对Memcached进行封装,以便更高效地在Java应用中使用它。 首先,我们需要理解Java中的Memcached客户端库,如spymemcached或xmemcached。这两个库都提供了与Memcached服务器通信...

    tomcat中Nginx+memcached实现session共享

    为了实现这一目标,我们可以结合Nginx反向代理服务器和memcached内存缓存系统来达到高效、可靠的Session共享。以下是对这个主题的详细阐述: 首先,让我们理解Session的概念。Session是Web应用程序用来跟踪用户状态...

    Nginx+Tomcat+Memcached实现tomcat集群和session共享

    通过以上步骤,我们构建了一个基于Nginx+Tomcat+Memcached的高可用Web服务集群,实现了Session的共享,提高了系统的扩展性和稳定性。在实际运营过程中,还需要关注监控、日志、安全等方面,确保系统的健康运行。

    tomcat8+memcached session共享

    1. `spymemcached-2.8.4.jar`:这是一个基于Java的Memcached客户端库,用于连接和操作Memcached服务器,处理session的存取操作。 2. `memcached-session-manager-1.8.3.jar`:这个库提供了session管理器,实现了将...

    j2ee项目使用filter和memcached实现session服务器

    在J2EE session管理中,Memcached可以作为集中式的session存储,替代默认的基于cookie或本地服务器内存的session存储方式。 实现步骤如下: 1. **配置Memcached服务器**:首先,你需要安装并运行一个Memcached服务...

    Go-MemcachedGoQueue是一个用Go语言写的基于memcached协议的消息队列

    Memcached Go Queue, 简称mgq, 是一个用Go语言写的,基于memcached协议的消息队列。其父亲mcq是最早应用于weibo的基础消息中间件,有着高性能,解耦的优点,使得其广泛应用于微博

    memcached部署监控培训文档基于java

    公司要求组织一个基于Java的memcached培训,整理了这个文档。里面有4个文件,包括memcached部署,memcached培训,监控工具memcache-top安装和daemontools安装。文档是基于word2013的,打不开的话,右键--属性--解锁

    memcached实现集群的session共享问题

    memcached实现集群的session共享问题,处理集群服务器情况下,memcached的session共享解决方案

    php实现的memcached队列类

    而PHP实现的Memcached队列类则是在这一基础上进行的扩展,它允许开发者创建并管理一个基于Memcached的队列,以支持并发操作和特定的队列策略。 首先,这个类提供了多进程并发写入和读取的能力。这意味着多个PHP进程...

    Memcached实例源码,基于.net的dll以及源码

    这个压缩包包含了基于.NET的Memcached实例源码和DLL,以及相关的PPT介绍,是学习和理解Memcached在.NET环境下的应用的宝贵资源。 首先,我们来详细了解一下Memcached的基本概念。Memcached是一个简单的键值存储系统...

    session共享 memcached-session-manager 1.9.6 jar

    `memcached-session-manager`是Java的一个库,用于在基于Tomcat的Web应用中实现基于Memcached的session共享,这在分布式环境中尤为重要。 标题中的"session共享 memcached-session-manager 1.9.6 jar"指的正是这个...

    memcached实现多个tomcat 共享一个session

    3. **修改web.xml配置**:在应用的web.xml中,配置session的管理器,使其使用memcached客户端,而不是默认的基于内存的session管理器。这通常涉及到设置session存储策略和相关参数。 4. **处理序列化与反序列化**:...

    基于memcached的Java Web应用session共享设计源码

    该项目为Java Web应用中的session共享设计,采用memcached作为后端存储,源码包含21个文件,涵盖10个Java类、5个XML配置文件、2个属性文件、1个Git忽略文件、1个LICENSE文件、1个Markdown文档和1个JSP页面。

    Memcached 分布式缓存实现原理简介

    Memcached的一个重要特性是其基于内存的存储方式,这使得数据读取速度非常快。 Memcached的分布式实现并不依赖于服务器之间的通信,而是依赖于客户端的算法。其中,最常用的分布式策略是“余数计算分散法”。客户端...

Global site tag (gtag.js) - Google Analytics