集群环境中使用 EhCache 缓存系统

11 篇文章 0 订阅
3 篇文章 0 订阅

http://blog.csdn.net/tang06211015/article/details/52281551

 EhCache 缓存系统 :

    本章节将要介绍EhCache及EhCache实现分布式的一些解决方案、并针对于这些解决性方案做一个实现,后续将出一个提供项目模块化、服务化、插件化的VieMall快速开发平台,同时集成Dubbo服务化、Zookeeper(分布式调度/分布式配置管理服务)、Redis分布式缓存技术及Memcache/Ehcache 二级缓存切换、FastDFS分布式文件系统、ActiveMQ异步消息中间件、Solr搜索、Nginx负载均衡等分布式及读写分离、如果有时间可以深入分表分库(mycat /sharding-jdbc),并且将这每一项技术细化分析,一起来学习和分享。后续动态可以关注个人博客 http://www.viemall.cn/;  

EhCache 缓存系统简介:

   EhCache 是一个纯 Java 的进程内缓存框架,具有快速、精干等特点,是 hibernate 中默认的 CacheProvider。
 下图是 EhCache 在应用程序中的位置:

   

 EhCache 的主要特性有:

1.快速;

2.简单;

3.多种缓存策略;

4.缓存数据有两级:内存和磁盘,因此无需担心容量问题;

5.缓存数据会在虚拟机重启的过程中写入磁盘;

6.可以通过 RMI、可插入 API 等方式进行分布式缓存;

7.具有缓存和缓存管理器的侦听接口;

8.支持多缓存管理器实例,以及一个实例的多个缓存区域;

9.提供 Hibernate 的缓存实现;

10.等等 …   

     由于 EhCache 是进程中的缓存系统,一旦将应用部署在集群环境中,每一个节点维护各自的缓存数据,当某节点对缓存数据进行更新,这些更新的数据无法在其它节点中共享,这不仅会降低节点运行的效率,而且会导致数据不同步的情况发生。例如某个网站采用 A、B 两个节点作为集群部署,当 A 节点的缓存更新后,而 B 节点缓存尚未更新就可能出现用户在浏览页面的时候,一会是更新后的数据,一会是尚未更新的数据,尽管我们也可以通过 Session Sticky 技术来将用户锁定在某个节点上,但对于一些交互性比较强或者是非 Web 方式的系统来说,Session Sticky 显然不太适合。所以就需要用到 EhCache 的集群解决方案。

EhCache 从 1.7 版本开始,支持五种集群方案,分别是:
   • Terracotta
   • RMI
   • JMS
   • JGroups
   • EhCache Server

   

   本文主要介绍其中的三种最为常用集群方式,分别是 RMI、JGroups 以及 EhCache Server 。

   RMI 集群模式:

      RMI 是 Java 的一种远程方法调用技术,是一种点对点的基于 Java 对象的通讯方式。EhCache 从 1.2 版本开始就支持 RMI 方式的缓存集群。在集群环境中 EhCache 所有缓存对象的键和值都必须是可序列化的,也就是必须实现 java.io.Serializable 接口,这点在其它集群方式下也是需要遵守的。
下图是 RMI 集群模式的结构图:

      图 2. RMI 集群模式结构图:

       

      采用 RMI 集群模式时,集群中的每个节点都是对等关系,并不存在主节点或者从节点的概念,因此节点间必须有一个机制能够互相认识对方,必须知道其它节点的信息,包括主机地址、端口号等。EhCache 提供两种节点的发现方式:手工配置和自动发现。手工配置方式要求在每个节点中配置其它所有节点的连接信息,一旦集群中的节点发生变化时,需要对缓存进行重新配置。
由于 RMI 是 Java 中内置支持的技术,因此使用 RMI 集群模式时,无需引入其它的 Jar 包,EhCache 本身就带有支持 RMI 集群的功能。使用 RMI 集群模式需要在 ehcache.xml 配置文件中定义cacheManagerPeerProviderFactory 节点。假设集群中有两个节点,分别对应的 RMI 绑定信息是:
    

    自动方式:

      自动发现方式使用tcp广播来建立和包含一个广播组,它的特征是最小配置和对成员组的自动添加和管理。没有那个服务器是有优先级的。对等点每一秒中向广播组发送心跳,如果一个对等点在五秒钟内没发送过来,则此对等点将会被删除,如果有新的,则会被加入集群。 

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <cacheManagerPeerProviderFactory  
  2.  class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"   properties="peerDiscovery=automatic, multicastGroupAddress=224.1.1.1,  multicastGroupPort=1000, timeToLive=32" />  
    解析:

      peerDiscovery 方式:atutomatic 为自动 ;mulicastGroupAddress 广播组地址:230.0.0.1;mulicastGroupPort 广播组端口:40001;timeToLive 搜索某个网段上的缓存:0是限制在同一个服务器,1是限制在同一个子网,32是限制在同一个网站,64是限制在同一个region,128是同一块大陆,还有个256,我就不说了;hostName:主机名或者ip,用来接受或者发送信息的接口。同时组播地址可以指定 D 类 IP 地址空间,范围从 224.0.1.0 到 238.255.255.255 中的任何一个地址。

    如下是详细的配置:

     Server1- 1000:   

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <cacheManagerPeerProviderFactory  
  2. class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"  
  3. properties="peerDiscovery=automaticmulticastGroupAddress=224.1.1.1,  
  4.             multicastGroupPort=1000timeToLive=32/>  
  5. <cacheManagerPeerListenerFactory  
  6.         class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"  
  7.         properties="hostName=127.0.0.1,port=1000,socketTimeoutMillis=120000" />  
  8. <!-- 默认缓存 -->  
  9.     <defaultCache maxElementsInMemory="1000" eternal="true"  
  10.         timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"  
  11.         diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000"  
  12.         diskPersistent="true" diskExpiryThreadIntervalSeconds="120"  
  13.         memoryStoreEvictionPolicy="LRU">  
  14.     </defaultCache>  
  15.       
  16.     <!-- demo缓存 -->  
  17.     <cache name="user" maxElementsInMemory="1000" eternal="false"  
  18.         timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"  
  19.         diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000"  
  20.         diskPersistent="false" diskExpiryThreadIntervalSeconds="120"  
  21.         memoryStoreEvictionPolicy="LRU">  
  22.         <cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" />  
  23.         <!-- 用于在初始化缓存,以及自动设置 -->  
  24.         <bootstrapCacheLoaderFactory  class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory" />  
  25.     </cache>  
    

 Server2 -2000:       

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <cacheManagerPeerProviderFactory  
  2. class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"  
  3. properties="peerDiscovery=automaticmulticastGroupAddress=224.1.1.1,  
  4.             multicastGroupPort=1000timeToLive=32/>  
  5. <cacheManagerPeerListenerFactory  
  6.         class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"  
  7.         properties="hostName=127.0.0.1,port=2000,socketTimeoutMillis=120000" />  
  8.           
  9.      <!-- 默认缓存 -->  
  10.      <defaultCache maxElementsInMemory="1000" eternal="true"  
  11.         timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"  
  12.         diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000"  
  13.         diskPersistent="true" diskExpiryThreadIntervalSeconds="120"  
  14.         memoryStoreEvictionPolicy="LRU">  
  15.      </defaultCache>  
  16.       
  17.       
  18.     <!-- demo缓存 -->  
  19.     <cache name="user" maxElementsInMemory="1000" eternal="false"  
  20.         timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"  
  21.         diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000"  
  22.         diskPersistent="false" diskExpiryThreadIntervalSeconds="120"  
  23.         memoryStoreEvictionPolicy="LRU">  
  24.         <cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" />  
  25.         <!-- 用于在初始化缓存,以及自动设置 -->  
  26.         <bootstrapCacheLoaderFactory  class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory" />  
  27.     </cache>  

  手动配置:

    手动成员发现需要给监听器配置ip地址和端口。任何成员不能在运行的时候添加和移除。手动的成员发现推荐在组播不能实现的时候使用,比如集群的路由不允许发送组播报文的时候。你也可以单向的缓存数据同步,比如让server2可以同步server1的数据,但sever1不能同步server2的。
配置手动发现成员时需要配置cacheManagerPeerProviderFactory的如下属性
      peerDiscovery=manual
      rmiUrls=//server:port/cacheName, ...
      rmiUrls是缓存成员的列表,但是不包括自己,也就是被配置的这台服务器的地址。

   案例:

     比如你的集群里有server1和server2两台服务器,你希望同步 user
     下面是server1-2000的配置:
   

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <cacheManagerPeerProviderFactory   
  2.             class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"   
  3.             properties="hostName=127.0.0.1,  
  4.             port=2000,  
  5.             socketTimeoutMillis=12000,  
  6.             peerDiscovery=manual,  
  7.             rmiUrls=//127.0.0.1:1000/user"  
  8.      />   
  9.  <cacheManagerPeerListenerFactory  
  10.         class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"  
  11.         properties="hostName=127.0.0.1,port=2000,socketTimeoutMillis=120000" />  
  12. <!-- demo缓存 -->  
  13.     <cache name="user" maxElementsInMemory="1000" eternal="false"  
  14.         timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"  
  15.         diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000"  
  16.         diskPersistent="false" diskExpiryThreadIntervalSeconds="120"  
  17.         memoryStoreEvictionPolicy="LRU">  
  18.         <cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" />  
  19.         <!-- 用于在初始化缓存,以及自动设置 -->  
  20.         <bootstrapCacheLoaderFactory  class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory" />  
  21.   
  22.   
  23.  如果想配置多个:rmiUrls=//127.0.0.1:1000/test1| rmiUrls=//127.0.0.1:1000/test2  
  24.   
  25. 下面是server2-1000的配置:  
  26. <cacheManagerPeerProviderFactory   
  27. class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"   
  28. properties="hostName=127.0.0.1,port=1000,socketTimeoutMillis=12000,  
  29.             peerDiscovery=manualrmiUrls=//127.0.0.1:2000/user"  
  30.         />  
  31. <cacheManagerPeerListenerFactory  
  32.         class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"  
  33.         properties="hostName=127.0.0.1,port=1000,socketTimeoutMillis=120000" />  
  34. <!-- demo缓存 -->  
  35.     <cache name="user" maxElementsInMemory="1000" eternal="false"  
  36.         timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"  
  37.         diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000"  
  38.         diskPersistent="false" diskExpiryThreadIntervalSeconds="120"  
  39.         memoryStoreEvictionPolicy="LRU">  
  40.         <cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" />  
  41.         <!-- 用于在初始化缓存,以及自动设置 -->  
  42.         <bootstrapCacheLoaderFactory  class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory" />  
  43.     </cache> 

 JGroups 集群模式:

    Jgroups入门与实践
                   

    EhCache 从 1.5. 版本开始增加了 JGroups 的分布式集群模式。与 RMI 方式相比较, JGroups 提供了一个非常灵活的协议栈、可靠的单播和多播消息传输,主要的缺点是配置复杂以及一些协议栈对第三方包的依赖。
JGroups 也提供了基于 TCP 的单播 ( Unicast ) 和基于 UDP 的多播 ( Multicast ) ,对应 RMI 的手工配置和自动发现。使用单播方式需要指定其它节点的主机地址和端口,下面是两个节点.

    单播方式配置:                              

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <cacheManagerPeerProviderFactory  
  2.         class="net.sf.ehcache.distribution.jgroups.JGroupsCacheManagerPeerProviderFactory"  
  3.         properties="connect=TCP(bind_addr=127.0.0.1;bind_port=1000):  
  4.                             TCPPING(initial_hosts=127.0.0.1[1000],127.0.0.1[2000];port_range=1;timeout=5000;num_initial_members=2):  
  5.                             MERGE2(min_interval=3000;max_interval=5000):  
  6.                             FD_ALL(interval=5000;timeout=20000):  
  7.                             FD(timeout=5000;max_tries=48;):  
  8.                             VERIFY_SUSPECT(timeout=1500):  
  9.                             pbcast.NAKACK(retransmit_timeout=100,200,300,600,1200,2400,4800;discard_delivered_msgs=true):  
  10.                             pbcast.STABLE(stability_delay=1000;desired_avg_gossip=20000;max_bytes=0):  
  11.                             pbcast.GMS(print_local_addr=true;join_timeout=5000)"  
  12.         propertySeparator="::" />

  使用多播方式配置如下:            

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <!-- EhCache 的 Groups 集群模式还有另外一种节点发现方式,   
                  就是通过多播( multicast )来维护集群中的所有有效节点。  
                  这也是最为简单而且灵活的方式,与手工模式不同的是,  
                  每个节点上的配置信息都相同,大大方便了节点的部署,  
                  集群启动时会自动发现同一局域网的缓存服务器  
      以jgroups 多播方式配置集群,自动发现集节点 -->
  2.   
  3. <cacheManagerPeerProviderFactory  
  4.         class="net.sf.ehcache.distribution.jgroups.JGroupsCacheManagerPeerProviderFactory"  
  5.         properties="connect=UDP(mcast_addr=224.1.1.1;mcast_port=45678;ip_ttl=32;mcast_send_buf_size=120000;mcast_recv_buf_size=80000):   
  6.         PING(timeout=2000;num_initial_members=2):   
  7.         MERGE2(min_interval=5000;max_interval=10000):   
  8.         FD_SOCK:VERIFY_SUSPECT(timeout=1500):   
  9.         pbcast.NAKACK(retransmit_timeout=3000):   
  10.         UNICAST(timeout=5000):   
  11.         pbcast.STABLE(desired_avg_gossip=20000):   
  12.         FRAG:   
  13.         pbcast.GMS(join_timeout=5000;print_local_addr=true)"  
  14.         propertySeparator="::" />  
    从上面的配置来看,JGroups 的配置要比 RMI 复杂得多,但也提供更多的微调参数,有助于提升缓存数据复制的性能。详细的 JGroups 配置参数的具体意义可参考 JGroups 的配置手册。

   JGroups 方式对应缓存节点的配置信息如下:                  

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <!-- demo缓存   
  2.        replicateAsynchronously  对象同步是否异步完成,默认为true。如果比较紧急就设为false。 在一致性时间性要求不强的时候,设为异步可大大提供性能,因为它是异步立即返回的,而且可以批量提交。   
  3.        replicateUpdatesViaCopy 是否将对象变更复制到所有节点,还是只是发送一个失效信息,让对方该缓存失效,当对方需要该缓存时重新计算载入。   
  4. 默认为true。鉴于对象复制的消耗挺大的,又有锁的问题,而且对方也未必需要该对象,所以此属性建议设为false。如果业务上真的需要设为true时,就可考虑使用Terracotta了。   
  5.        replicatePuts、replicateUpdates、replicateRemovals  增删改是否同步,默认都为true。但因为我们前面选择了失效算法,所以replicatePuts 要设为false。   
  6.     -->  
  7.     <cache name="user" maxElementsInMemory="1000" eternal="false"  
  8.         timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"  
  9.         diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000"  
  10.         diskPersistent="false" diskExpiryThreadIntervalSeconds="120"  
  11.         memoryStoreEvictionPolicy="LRU">  
  12.         <cacheEventListenerFactory  
  13.             class="net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory"  
  14.             properties="replicateAsynchronously=truereplicatePuts=true,  
  15.         replicateUpdates=truereplicateUpdatesViaCopy=falsereplicateRemovals=true/>  
  16.         <!-- 用于在初始化缓存,以及自动设置 -->  
  17.         <bootstrapCacheLoaderFactory  
  18.             class="net.sf.ehcache.distribution.jgroups.JGroupsBootstrapCacheLoaderFactory" />  
  19.     </cache>  

   使用组播方式的注意事项:

    使用 JGroups 需要引入 JGroups 的 Jar 包以及 EhCache 对 JGroups 的封装包 ehcache-jgroupsreplication-xxx.jar 。
在一些启用了 IPv6 的电脑中,经常启动的时候报如下错误信息:
java.lang.RuntimeException: the type of the stack (IPv6) and the user supplied addresses (IPv4) don't match: /231.12.21.132.
解决的办法是增加 JVM 参数:-Djava.NET.preferIPv4Stack=true。如果是 Tomcat 服务器,可在 catalina.bat 或者 catalina.sh 中增加如下环境变量即可:
    SET CATALINA_OPTS=-Djava.Net.preferIPv4Stack=true

 EhCache Server:

    与前面介绍的两种集群方案不同的是, EhCache Server 是一个独立的缓存服务器,其内部使用 EhCache 做为缓存系统,可利用前面提到的两种方式进行内部集群。对外提供编程语言无关的基于 HTTP 的 RESTful 或者是 SOAP 的数据缓存操作接口。
下面是 EhCache Server 提供的对缓存数据进行操作的方法:

  OPTIONS /{cache}}

获取某个缓存的可用操作的信息。

  HEAD /{cache}/{element}

获取缓存中某个元素的 HTTP 头信息,例如:

   curl --head  http://localhost:8080/ehcache/rest/sampleCache2/2

EhCache Server 返回的信息如下:

HTTP/1.1 200 OK 

X-Powered-By: Servlet/2.5 

Server: GlassFish/v3 

Last-Modified: Sun, 27 Jul 2008 08:08:49 GMT 

ETag: "1217146129490"

Content-Type: text/plain; charset=iso-8859-1 

Content-Length: 157 

Date: Sun, 27 Jul 2008 08:17:09 GMT

  GET /{cache}/{element}

读取缓存中某个数据的值。

  PUT /{cache}/{element}

写缓存。

由于这些操作都是基于 HTTP 协议的,因此你可以在任何一种编程语言中使用它,例如 Perl、PHP 和 Ruby 等等。

下图是 EhCache Server 在应用中的架构

     图 3. EhCache Server 应用架构图:

       

    EhCache Server 同时也提供强大的安全机制、监控功能。在数据存储方面,最大的 Ehcache 单实例在内存中可以缓存 20GB。最大的磁盘可以缓存 100GB。通过将节点整合在一起,这样缓存数据就可以跨越节点,以此获得更大的容量。将缓存 20GB 的 50 个节点整合在一起就是 1TB 了。

额外补充:

  ehcache.xml 属性说明:

    属性解释:
    必须属性:
        name:设置缓存的名称,用于标志缓存,惟一
        maxElementsInMemory:在内存中最大的对象数量
        maxElementsOnDisk:在DiskStore中的最大对象数量,如为0,则没有限制
        eternal:设置元素是否永久的,如果为永久,则timeout忽略
        overflowToDisk:是否当memory中的数量达到限制后,保存到Disk
    可选的属性:
        timeToIdleSeconds:设置元素过期前的空闲时间
        timeToLiveSeconds:设置元素过期前的活动时间
        diskPersistent:是否disk store在虚拟机启动时持久化。默认为false
        diskExpiryThreadIntervalSeconds:运行disk终结线程的时间,默认为120秒
        memoryStoreEvictionPolicy:缓存满了之后的淘汰算法
    缓存子元素:
      cacheEventListenerFactory:注册相应的的缓存监听类,用于处理缓存事件,如put,remove,update,和expire
      bootstrapCacheLoaderFactory:指定相应的BootstrapCacheLoader,用于在初始化缓存,以及自动设置。

同步的属性说明:

 RMI缓存分布同步查找 class使用net.sf.ehcache.distribution.RMICacheReplicatorFactory 
 Jroups缓存同步查找 class使用 net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory
 这个工厂支持以下属性:
 replicatePuts=true | false – 当一个新元素增加到缓存中的时候是否要复制到其他的peers。默认是true。
 replicateUpdates=true | false – 当一个已经在缓存中存在的元素被覆盖时是否要进行复制。默认是true。
 replicateRemovals= true | false – 当元素移除的时候是否进行复制。默认是true。
 replicateAsynchronously=true | false – 复制方式是异步的指定为true时,还是同步的,指定为false时。默认是true。
 replicatePutsViaCopy=true | false – 当一个新增元素被拷贝到其他的cache中时是否进行复制指定为true时为复制,默认是true。
 replicateUpdatesViaCopy=true | false – 当一个元素被拷贝到其他的cache中时是否进行复制指定为true时为复制,默认是true。
 asynchronousReplicationIntervalMillis=1000

 原文地址及个人源码地址: http://www.dczou.com/viemall/209.html

 参考资料:http://www.ibm.com/developerworks/cn/java/j-lo-ehcache/


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值