1 cacheManager 的构建
Spring + Ehcache的配置
在Spring项目中只要注入cacheManager即可。
注:如果您想使用持久化机制,就需要提供一个磁盘存储的位置给CacheManagerBuilder.persistence这个方法,另外在使用的过程中,你还需要定义一个磁盘使用的资源池。
Ehcache集群简介
从Ehcache1.2版本开始,Ehcache就可以使用分布式的缓存了,从 1.7版本开始,开始支持共五种集群方案,分别是:
Terracotta
RMI
JMS
JGroups
EhCache Server
其中有三种上最为常用集群方式,分别是 RMI、JGroups 以及 EhCache Server 。
其实我们在使用Ehcache分布式缓存的过程中,主要是以缓存插件的方式使用,如果我们想根据自己的需要使用分布式缓存那就需要自己开发来定制化,在后面我们会发现其实Ehcache提供的分布式缓存并不是非常好用,有不少问题存在,所以对缓存数据一致性比较高的情况下,使用集中式缓存更合适,比如Redis、Memcached等。
Ehcache集群的基本概念
1 成员发现(Peer Discovery)
Ehcache集群概念中有一个cache组,每个cache都是另一个cache的peer,并不像Redis或者其他分布式组件一样有一个主的存在,Ehcache并没有主Cache,可是那如何知道集群中的其他缓存都有谁呢?这个就是成员发现。
Ehcache提供了二种机制来实现成员发现功能,分别是手动发现和自动发现。
手动发现
在Ehcache的配置文件中指定cacheManagerPeerProviderFactory元素的class属性为net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory。这就需要自己去配置IP地址和端口号。
自动发现
自动的发现方式用TCP广播机制来确定和维持一个广播组。它只需要一个简单的配置可以自动的在组中添加和移除成员。在集群中也不需要什么优化服务器的知识,这是默认推荐的。
成员每秒向群组发送一个“心跳”。如果一个成员 5秒种都没有发出信号它将被群组移除。如果一个新的成员发送了一个“心跳”它将被添加进群组。
任何一个用这个配置安装了复制功能的cache都将被其他的成员发现并标识为可用状态。
要设置自动的成员发现,需要指定ehcache配置文件中
Spring配置
对每个需要同步的cache配置
CacheReplicators
每个要进行同步的cache都需要设置一个用来向CacheManager的成员复制消息的缓存事件监听器。这个工作要通过为每个cache的配置增加一个cacheEventListenerFactory元素来完成。
RMI集群的原理:当缓存改变时,ehcache会向组播IP地址和端口号发送RMI UDP组播包。
缺陷:Ehcache的组播做得比较初级,功能只是基本实现(比如简单的一个HUB,接两台单网卡的服务器,互相之间组播同步就没问题),对一些复杂的环境(比如多台服务器,每台服务器上多地址,尤其是集群,存在一个集群地址带多个物理机,每台物理机又带多个虚拟站的子地址),就容易出现问题。
11.3、使用Ehcache的瓶颈是什么
1、缓存漂移(Cache Drift):每个应用节点只管理自己的缓存,在更新某个节点的时候,不会影响到其他的节点,这样数据之间可能就不同步了。
2、数据库瓶颈(Database Bottlenecks ):对于单实例的应用来说,缓存可以保护数据库的读风暴;但是,在集群的环境下,每一个应用节点都要定期保持数据最新,节点越多,要维持这样的情况对数据库的开销也越大。
11.4、实际工作中如何使用Ehcache
在实际工作中,我更多是将Ehcache作为与Redis配合的二级缓存。
第一种方式:
注:这种方式通过应用服务器的Ehcache定时轮询Redis缓存服务器更同步更新本地缓存,缺点是因为每台服务器定时Ehcache的时间不一样,那么不同服务器刷新最新缓存的时间也不一样,会产生数据不一致问题,对一致性要求不高可以使用。
第二种方式:
注:
通过引入了MQ队列,使每台应用服务器的Ehcache同步侦听MQ消息,这样在一定程度上可以达到准同步更新数据,通过MQ推送或者拉取的方式,但是因为不同服务器之间的网络速度的原因,所以也不能完全达到强一致性。基于此原理使用Zookeeper等分布式协调通知组件也是如此。
总结:
1、使用二级缓存的好处是减少缓存数据的网络传输开销,当集中式缓存出现故障的时候,Ehcache等本地缓存依然能够支撑应用程序正常使用,增加了程序的健壮性。另外使用二级缓存策略可以在一定程度上阻止缓存穿透问题。
源码分析
Ehcahe存放内存是经过如下几步:
1.put一个数据进memoryStore
2.checkCapacit容量
3.如果达到上限则启用淘汰策略
4.查找淘汰策略
5.选择合适的淘汰算法
6.返回节点数据