码迷,mamicode.com
首页 > 系统相关 > 详细

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

时间:2016-08-25 21:31:16      阅读:360      评论:0      收藏:0      [点我收藏+]

标签:

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

<span style="font-family:SimHei;font-size:18px;"> <cacheManagerPeerProviderFactory
 class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"   properties="peerDiscovery=automatic, multicastGroupAddress=224.1.1.1,  multicastGroupPort=1000, timeToLive=32" />
</span>
   解析:

      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:   

<span style="font-family:SimHei;font-size:18px;">    <cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=automatic, multicastGroupAddress=224.1.1.1,
    	    multicastGroupPort=1000, timeToLive=32" />
<cacheManagerPeerListenerFactory
		class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
		properties="hostName=127.0.0.1,port=1000,socketTimeoutMillis=120000" />
<!-- 默认缓存 -->
	<defaultCache maxElementsInMemory="1000" eternal="true"
		timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"
		diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000"
		diskPersistent="true" diskExpiryThreadIntervalSeconds="120"
		memoryStoreEvictionPolicy="LRU">
	</defaultCache>
	
	<!-- demo缓存 -->
	<cache name="user" maxElementsInMemory="1000" eternal="false"
		timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"
		diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000"
		diskPersistent="false" diskExpiryThreadIntervalSeconds="120"
		memoryStoreEvictionPolicy="LRU">
		<cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" />
		<!-- 用于在初始化缓存,以及自动设置 -->
		<bootstrapCacheLoaderFactory  class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory" />
	</cache>
</span>
    

 Server2 -2000:       

<span style="font-family:SimHei;font-size:18px;"><cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=automatic, multicastGroupAddress=224.1.1.1,
    	    multicastGroupPort=1000, timeToLive=32" />
<cacheManagerPeerListenerFactory
		class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
		properties="hostName=127.0.0.1,port=2000,socketTimeoutMillis=120000" />
       	
	 <!-- 默认缓存 -->
	 <defaultCache maxElementsInMemory="1000" eternal="true"
		timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"
		diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000"
		diskPersistent="true" diskExpiryThreadIntervalSeconds="120"
		memoryStoreEvictionPolicy="LRU">
	 </defaultCache>
	
	
	<!-- demo缓存 -->
	<cache name="user" maxElementsInMemory="1000" eternal="false"
		timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"
		diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000"
		diskPersistent="false" diskExpiryThreadIntervalSeconds="120"
		memoryStoreEvictionPolicy="LRU">
		<cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" />
		<!-- 用于在初始化缓存,以及自动设置 -->
		<bootstrapCacheLoaderFactory  class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory" />
	</cache>
</span>

  手动配置:

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

   案例:

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

<span style="font-family:SimHei;font-size:18px;"><cacheManagerPeerProviderFactory 
		    class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory" 
		    properties="hostName=127.0.0.1,
		    port=2000,
		    socketTimeoutMillis=12000,
		    peerDiscovery=manual,
		    rmiUrls=//127.0.0.1:1000/user"
	 /> 
 <cacheManagerPeerListenerFactory
		class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
		properties="hostName=127.0.0.1,port=2000,socketTimeoutMillis=120000" />
<!-- demo缓存 -->
	<cache name="user" maxElementsInMemory="1000" eternal="false"
		timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"
		diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000"
		diskPersistent="false" diskExpiryThreadIntervalSeconds="120"
		memoryStoreEvictionPolicy="LRU">
		<cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" />
		<!-- 用于在初始化缓存,以及自动设置 -->
		<bootstrapCacheLoaderFactory  class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory" />
	</cache>


 如果想配置多个:rmiUrls=//127.0.0.1:1000/test1| rmiUrls=//127.0.0.1:1000/test2

下面是server2-1000的配置:
<cacheManagerPeerProviderFactory 
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory" 
properties="hostName=127.0.0.1,port=1000,socketTimeoutMillis=12000,
		    peerDiscovery=manual, rmiUrls=//127.0.0.1:2000/user"
		/>
<cacheManagerPeerListenerFactory
		class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
		properties="hostName=127.0.0.1,port=1000,socketTimeoutMillis=120000" />
<!-- demo缓存 -->
	<cache name="user" maxElementsInMemory="1000" eternal="false"
		timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"
		diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000"
		diskPersistent="false" diskExpiryThreadIntervalSeconds="120"
		memoryStoreEvictionPolicy="LRU">
		<cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" />
		<!-- 用于在初始化缓存,以及自动设置 -->
		<bootstrapCacheLoaderFactory  class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory" />
	</cache>
</span><span style="font-family: SimHei; font-size: 18px; background-color: rgb(255, 255, 255);">   </span>

 JGroups 集群模式:

    Jgroups入门与实践
                   

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

    单播方式配置:                              

<span style="font-family:SimHei;font-size:18px;">  <cacheManagerPeerProviderFactory
		class="net.sf.ehcache.distribution.jgroups.JGroupsCacheManagerPeerProviderFactory"
		properties="connect=TCP(bind_addr=127.0.0.1;bind_port=1000):
							TCPPING(initial_hosts=127.0.0.1[1000],127.0.0.1[2000];port_range=1;timeout=5000;num_initial_members=2):
							MERGE2(min_interval=3000;max_interval=5000):
							FD_ALL(interval=5000;timeout=20000):
							FD(timeout=5000;max_tries=48;):
							VERIFY_SUSPECT(timeout=1500):
							pbcast.NAKACK(retransmit_timeout=100,200,300,600,1200,2400,4800;discard_delivered_msgs=true):
							pbcast.STABLE(stability_delay=1000;desired_avg_gossip=20000;max_bytes=0):
							pbcast.GMS(print_local_addr=true;join_timeout=5000)"
		propertySeparator="::" /></span>

  使用多播方式配置如下:            

<span style="font-family:SimHei;font-size:18px;">             EhCache 的 Groups 集群模式还有另外一种节点发现方式,
              就是通过多播( multicast )来维护集群中的所有有效节点。
              这也是最为简单而且灵活的方式,与手工模式不同的是,
              每个节点上的配置信息都相同,大大方便了节点的部署,
              集群启动时会自动发现同一局域网的缓存服务器
              以jgroups 多播方式配置集群,自动发现集节点
<cacheManagerPeerProviderFactory
        class="net.sf.ehcache.distribution.jgroups.JGroupsCacheManagerPeerProviderFactory"
        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): 
        PING(timeout=2000;num_initial_members=2): 
        MERGE2(min_interval=5000;max_interval=10000): 
        FD_SOCK:VERIFY_SUSPECT(timeout=1500): 
        pbcast.NAKACK(retransmit_timeout=3000): 
        UNICAST(timeout=5000): 
        pbcast.STABLE(desired_avg_gossip=20000): 
        FRAG: 
        pbcast.GMS(join_timeout=5000;print_local_addr=true)"
        propertySeparator="::" />
</span>
   从上面的配置来看,JGroups 的配置要比 RMI 复杂得多,但也提供更多的微调参数,有助于提升缓存数据复制的性能。详细的 JGroups 配置参数的具体意义可参考 JGroups 的配置手册。

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

<span style="font-family:SimHei;font-size:18px;"><!-- demo缓存 
	   replicateAsynchronously  对象同步是否异步完成,默认为true。如果比较紧急就设为false。 在一致性时间性要求不强的时候,设为异步可大大提供性能,因为它是异步立即返回的,而且可以批量提交。 
	   replicateUpdatesViaCopy 是否将对象变更复制到所有节点,还是只是发送一个失效信息,让对方该缓存失效,当对方需要该缓存时重新计算载入。 
默认为true。鉴于对象复制的消耗挺大的,又有锁的问题,而且对方也未必需要该对象,所以此属性建议设为false。如果业务上真的需要设为true时,就可考虑使用Terracotta了。 
	   replicatePuts、replicateUpdates、replicateRemovals  增删改是否同步,默认都为true。但因为我们前面选择了失效算法,所以replicatePuts 要设为false。 
	-->
	<cache name="user" maxElementsInMemory="1000" eternal="false"
		timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"
		diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000"
		diskPersistent="false" diskExpiryThreadIntervalSeconds="120"
		memoryStoreEvictionPolicy="LRU">
		<cacheEventListenerFactory
			class="net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory"
			properties="replicateAsynchronously=true, replicatePuts=true,
        replicateUpdates=true, replicateUpdatesViaCopy=false, replicateRemovals=true" />
		<!-- 用于在初始化缓存,以及自动设置 -->
		<bootstrapCacheLoaderFactory
			class="net.sf.ehcache.distribution.jgroups.JGroupsBootstrapCacheLoaderFactory" />
	</cache>
</span>

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

    使用 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/

    



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

标签:

原文地址:http://blog.csdn.net/tang06211015/article/details/52281551

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!