分布式EHCACHE系统,如何实现缓存数据同步?
这也是最常用的方式,配置简单,关键一点,各EHCACHE的节点配置都是一样的
例子:
spring 配置中调用的ehcache文件 <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> <property name="configLocation"> <value>classpath:ehcache_mc.xml</value> </property> </bean> <bean id="userCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean"> <property name="cacheManager"> <ref local="cacheManager"/> </property> <property name="cacheName"> <value>userCache</value> </property> </bean> |
ehcache_mc.xml:
<cache name="userCache" maxElementsInMemory="10000" maxElementsOnDisk="0" eternal="true" overflowToDisk="true" diskSpoolBufferSizeMB="20" memoryStoreEvictionPolicy="LFU" transactionalMode="off"> <cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" properties="replicateAsynchronously=true, replicatePuts=true, replicateUpdates=true,replicateUpdatesViaCopy= true, replicateRemovals= true " /> <cacheEventListenerFactory class="cn.com.gary.test.ehcache.EventFactory" /> <!-- 打印ehcache 动作日志 --> </cache> <cacheManagerPeerProviderFactory class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory" properties="peerDiscovery=automatic, multicastGroupAddress=230.0.0.1, multicastGroupPort=4446,timeToLive=255"/> <cacheManagerPeerListenerFactory class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"/>
|
原理:
这样当缓存改变时,ehcache会向230.0.0.1端口4446发RMI UDP组播包
这种组播方式的缺陷:
EHCACHE的组播做得比较初级,功能只是基本实现(比如简单的一个HUB,接两台单网卡的服务器,互相之间组播同步就没问题),
对一些复杂的环境(比如多台服务器,每台服务器上多地址,尤其是集群,存在一个集群地址带多个物理机,每台物理机又带多个虚拟站的子地址),就容易出现问题.
究其原因, 组播/广播转发是一个很复杂的过程. 简单的说, 一个组播缺省只能在一个网段内传输,不能跨网段.
举个简单的例子, PC机网卡的自动获取地址,还有WINDOWS里的网上邻居,都属于典型的广播服务,所以这些服务都是不能跨网段(跨路由)的,当然也不是完全不行,借助一些工具,比如CISCO路由器上的udp-broadcast helper,或者微软的netBIOS on Tcp/ip,就可以实现.
我们自己安装一些软件时,也经常遇到比如"将网卡的广播转发打开"之类的操作.
而在多网卡的主机,或同一网卡多IP的主机上,尽管地址可能是一个网段内的,但其实地址间已经存在跳数了(hop),其实就是从一个地址向另一个地址跳. 这时广播/组播就容易被阻断.
比如: 我们自己的WINDOWS上装一个VMWARE虚拟机,尽管IP地址是一个网段的,但因为虚拟机采用的桥模式不是标准的网桥模式(也可能是需要配置一下,但说实话懒得研究VMWARE了),所以广播/组播也经常出现不通的情况.
更何况在一些云计算的环境,集群的分布往往是跨网段的,甚至是跨地域的.这时更难以依赖这种初级的组播同步.
总之,分布式集群架构,建议EHCACHE改为PEER-2-PEER的同步方式.
其实就是每个节点和其他n-1个节点都建立TCP的P2P PEER.
下面是一个3节点的ehcache分布式部署:
节点1: spring 配置中调用的ehcache文件 <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> <property name="configLocation"> <value>classpath:ehcache_p2p_40001.xml</value> </property> </bean> <bean id="userCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean"> <property name="cacheManager"> <ref local="cacheManager"/> </property> <property name="cacheName"> <value>userCache</value> </property> </bean>
ehcache_p2p_40001.xml <cache name="userCache" maxElementsInMemory="10000" maxElementsOnDisk="0" eternal="true" overflowToDisk="true" diskSpoolBufferSizeMB="20" memoryStoreEvictionPolicy="LFU" transactionalMode="off"> <cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" properties="replicateAsynchronously=true, replicatePuts=true, replicateUpdates=true,replicateUpdatesViaCopy= true, replicateRemovals= true " /> <cacheEventListenerFactory class="cn.com.dwsoft.test.ehcache.EventFactory" /> </cache> <!--调用ehcache2的RMI--> <cacheManagerPeerProviderFactory class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory" properties="peerDiscovery=manual,rmiUrls=//192.168.0.251:40002/userCache|//192.168.0.251:40003/userCache"/>
<!--RMI监听40001端口--> <cacheManagerPeerListenerFactory class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory" properties="hostName=192.168.0.122,port=40001,socketTimeoutMillis=2000"/>
|
节点2: spring 配置中调用的ehcache文件 <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> <property name="configLocation"> <value>classpath:ehcache_p2p_40002.xml</value> </property> </bean> <bean id="userCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean"> <property name="cacheManager"> <ref local="cacheManager"/> </property> <property name="cacheName"> <value>userCache</value> </property> </bean>
ehcache_p2p_40002.xml <cache name="userCache" maxElementsInMemory="10000" maxElementsOnDisk="0" eternal="true" overflowToDisk="true" diskSpoolBufferSizeMB="20" memoryStoreEvictionPolicy="LFU" transactionalMode="off"> <cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" properties="replicateAsynchronously=true, replicatePuts=true, replicateUpdates=true,replicateUpdatesViaCopy= true, replicateRemovals= true " /> <cacheEventListenerFactory class="cn.com.dwsoft.test.ehcache.EventFactory" /> </cache>
<!--调用ehcache2的RMI--> <cacheManagerPeerProviderFactory class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory" properties="peerDiscovery=manual,rmiUrls=//192.168.0.122:40001/userCache|//192.168.0.251:40003/userCache"/>
<!--RMI监听40001端口--> <cacheManagerPeerListenerFactory class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory" properties="hostName=192.168.0.251,port=40002,socketTimeoutMillis=2000"/>
|
节点3: spring 配置中调用的ehcache文件 <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> <property name="configLocation"> <value>classpath:ehcache_p2p_40003.xml</value> </property> </bean> <bean id="userCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean"> <property name="cacheManager"> <ref local="cacheManager"/> </property> <property name="cacheName"> <value>userCache</value> </property> </bean>
ehcache_p2p_40003.xml <cache name="userCache" maxElementsInMemory="10000" maxElementsOnDisk="0" eternal="true" overflowToDisk="true" diskSpoolBufferSizeMB="20" memoryStoreEvictionPolicy="LFU" transactionalMode="off"> <cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" properties="replicateAsynchronously=true, replicatePuts=true, replicateUpdates=true,replicateUpdatesViaCopy= true, replicateRemovals= true " /> <cacheEventListenerFactory class="cn.com.dwsoft.test.ehcache.EventFactory" /> </cache>
<!--调用ehcache2的RMI--> <cacheManagerPeerProviderFactory class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory" properties="peerDiscovery=manual,rmiUrls=//192.168.0.122:40001/userCache|//192.168.0.251:40002/userCache"/>
<!--RMI监听40001端口--> <cacheManagerPeerListenerFactory class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory" properties="hostName=192.168.0.251,port=40003,socketTimeoutMillis=2000"/>
|
测试
节点1添加一条缓存条目
节点1日志: 2012-08-28 17:00:39,859 INFO CustomActionSupport.getParameter(188)-/admin/inputEntry.do? submit=提交&cachekey=mac1228&cachevalue=1228 2012-08-28 17:00:39,859 INFO TestAction.inputEntry(97)-mac1228:1228 2012-08-28 17:00:39,875 INFO CacheEvent.log(65)-in notifyElementPut[ key = mac1228, value=1228, version=1, hitCount=0, CreationTime = 1346144439875, LastAccessTime = 1346144439875 ] 2012-08-28 17:00:39,875DEBUG ServletDispatcherResult.debug(57)-Forwarding to location /index.jsp |
节点2日志: 2011-09-22 14:25:51,262 INFO CacheEvent.log(65)-in notifyElementPut[ key = mac1228, value=1228, version=1, hitCount=0, CreationTime = 1346144440000, LastAccessTime = 1316672751253 ] |
节点3日志: 2011-09-22 14:25:51,198 INFO CacheEvent.log(65)-in notifyElementPut[ key = mac1228, value=1228, version=1, hitCount=0, CreationTime = 1346144440000, LastAccessTime = 1316672751198 ] |
|
节点2添加一条缓存条目
节点1日志: 2012-08-28 16:54:55,890 INFO CacheEvent.log(65)-in notifyElementPut[ key = mac25181904, value=25181904, version=1, hitCount=0, CreationTime = 1316672407000, LastAccessTime = 1346144095890 ] |
节点2日志: 2011-09-22 14:20:06,041 INFO CustomActionSupport.getParameter(188)-/admin/inputEntry.do? submit=提交&cachekey=mac25181904&cachevalue=25181904 2011-09-22 14:20:06,042 INFO TestAction.inputEntry(97)-mac25181904:25181904 2011-09-22 14:20:06,050DEBUG ServletDispatcherResult.debug(57)-Forwarding to location /index.jsp |
节点3日志: 2011-09-22 14:20:06,568 INFO CacheEvent.log(65)-in notifyElementPut[ key = mac25181904, value=25181904, version=1, hitCount=0, CreationTime = 1316672407000, LastAccessTime = 1316672406568 ] |
|
总结:
上面说了,组播方式同步不可靠.
P2P方式其实也存在不可靠的地方.这就是P2P要求每个节点的EHCACHE要指向其他的N-1个节点,
当在云环境,或集群域下, 多个子节点部署项目都是被自动发布的,这时很难做到不同节点有不同的配置,因为自动发布,配置往往都是相同的,这样P2P就很难实现.
总之,这种同步型应用是很难适应大规模分布式部署的,还是建议采用一些集中软件比如MEMCACHED.
相关推荐
Ehcache 自带了一些默认的分布式缓存插件实现,这些插件可以满足大部分应用的需要。如果需要使用其他的插件那就需要自己开发了,开发者可以通过查看 distribution 包里的源代码及 JavaDoc 来实现它。
Ehcache 是一种广泛使用的开源 Java 分布式缓存。主要面向通用缓存,Java EE 和轻量级容器。它具有内存和磁盘存储,缓存加载器,缓存扩展,缓存异常处理程序,一个 gzip 缓存 servlet 过滤器,支持 REST 和 SOAP api...
java ehcache分布式缓存实例 RMI方式实现.
介绍ehcache做jvm缓存,ehcache做分布式缓存,redis做分布式缓存,redis分片集群,redis哨兵,redis基本数据,redis主从复制,redis和ehcache的二级缓存,redis雪崩效应,redis缓存穿透(整个环境搭建基于Centos,代码...
主要讲解下encache的原理、分布式缓存集群环境配置、与在spring中的使用
NULL 博文链接:https://wiselyman.iteye.com/blog/2114715
Ehcache分布式缓存入门案例demo,简单易用上手快,帮助您快速解决应用中的单体缓存问题,提高系统响应速度。
超好的东西,分布式缓存所需配置都在里面,感谢为我们翻译的大牛~~
ehcache集群
-- 如果有多台机子的话,可以考虑部署redis分布式缓存.. --> </bean> <!-- 用户授权信息Cache, 采用EhCache,需要的话就配置上此信息 --> <bean id="shiroEhcacheManager" class="org.apache.shiro.cache....
Ehcache是Java语言编写使用最广的分布式缓存。本套课程讲解全新的Ehcache?3.1版本,内容全面实用。涵盖缓存分层、缓存过期和剔除策略、缓存层序列化、多种缓存使用模式、事件监听器、XA事务、分布式缓存集群。
可以通过RMI、可插入API等方式进行分布式缓存7. 具有缓存和缓存管理器的侦听接口8. 支持多缓存管理器实例,以及一个实例的多个缓存区域9. 提供Hibernate的缓存实现10. 等等 标签:缓存
【EhCache】Java缓存框架使用EhCache结合Spring AOP ... 可以通过RMI、可插入API等方式进行分布式缓存。 6. 具有缓存和缓存管理器的侦听接口 。 7. 支持多缓存管理器实例,以及一个实例的多个缓存区域 等特点。
springboot搭建ehcache+redis的二级缓存
EhCache 是一个纯Java的进程内缓存框架,... 可以通过RMI、可插入API等方式进行分布式缓存7. 具有缓存和缓存管理器的侦听接口8. 支持多缓存管理器实例,以及一个实例的多个缓存区域9. 提供Hibernate的缓存实现10. 等等
Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。它具有内存和磁盘存储,缓存加载器,缓存扩展,缓存异常处理程序,一个gzip缓存servlet过滤器,支持REST和SOAP api等特点
此文可借鉴作为分布式缓存中间件实现方案
异步复制与同步复制 以及ehcache的小tips和我的配置
java ehcache terracotta 集群, 分布式缓存配置
jvcache是一个简单的基于vertx的库,用于使ehcahe等本地缓存与redis等分布式缓存保持同步。 尽管您可以扩展以支持您选择的其他缓存框架,但它内置了ehcache和redis实现。 它写于2016年。CacheEventBus ...