Ehcache 基本使用 以及 基于RMI集群搭建

   ehcache是一个很成熟的基于jvm内存的缓存框架,其效率是要比redis基于socket要高的,一般ehcache可以配合数据库做一个缓存中间件来减少数据库的访问压力。
   见过很多人包括我自己之前也有这样的疑问:ehcache比jvm的static 集合好在哪里。
   1、首先在存储大小方面 ehcache是和static map存储差不多的。稍微小一丢丢,算是个可忽略的优势
   2、ehcache 有自己的缓存管理策略,比如说缓存刷新时机,缓存大小,缓存过期策略等,这是比之static map显而易见的优点,使用static map 是不好控制缓存大小的,而ehcache 可以很轻松的控制 不用我们自己关心
   3、多项目缓存共享问题,其实redis在这里才是最好用的,但是个人觉得现在ehcache也有比较不错的集群管理了,而static map 也是无法做到的

进入正题

最最开始 添加依赖

	<dependency>
		<groupId>net.sf.ehcache</groupId>
		<artifactId>ehcache-core</artifactId>
		<version>2.6.11</version>
	</dependency>

首先说一下ehcache的基本使用
ehcache 存储的内容是一个Element ,这东西有个key 和value都是object类型的 其实和map差不多
首先想用它 分三层
第一层:CacheManager 这东西是通过读配置文件ehcache.xml读出来的
package是net.sf.ehcache 这里我使用的是2.6.x版本

CacheManager cacheManager = CacheManager.create(EhcacheManager.class.getClassLoader().getResource("ehcache.xml"));

第二层 Cache 说cache之前 先看一下配置文件了 上面提到的ehcache.xml是个什么呢

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">
    <diskStore path="java.io.tmpdir/Tmp_EhCache" />
    <defaultCache eternal="false"
                  maxElementsInMemory="1000"
                  overflowToDisk="false"
                  diskPersistent="false"
                  timeToIdleSeconds="0"
                  timeToLiveSeconds="600"
                  memoryStoreEvictionPolicy="LRU" />

    <!-- server1 的cacheManagerPeerProviderFactory配置 -->
    <cache name="articleCache"
           eternal="true"
           maxElementsInMemory="10000"
           overflowToDisk="false"
           diskPersistent="false"
           timeToIdleSeconds="0"
           timeToLiveSeconds="0"
           memoryStoreEvictionPolicy="LRU" >
    </cache>
</ehcache>

解释下每个元素的意思 网上太多了

diskStore

diskStore元素:制定一个路径,当EHCache把数据写到硬盘上的时候,
会把数据写到该目录下。user.home - 用户主目录;user.dir - 用户当前工作目录;
java.io.tmpdir - 默认临时文件路径。

defaultCache

设定缓存的默认数据过期策略。

cache

设定具体的命名缓存的数据过期策略。

name

缓存名称。通常为缓存对象的类名;

maxElementsInMemory

设置基于内存的缓存可存放对象的最大数目;

maxElementOnDisk

设置基于硬盘的缓存可存放对象的最大数目;

eternal

如果为true,表示对象永远不会过期,此时会忽略tiemToldleSeconds和timeToLiveSeconds属性
默认为false。

timeToldleSeconds

设置允许对象处于空闲状态的最长时间,以秒为单位。
当对象最近一次被访问后,如果处于空闲状态的时间超过了
timeToldleSeconds属性值,这个对象就会过期。
当对象过期,EHCache将把它从缓存中清空。只有当eternal属性为false.
该属性才有效。如果该属性的值为0,那么就表示该对象可以无限期地存于缓存中。
即缓存被创建后,最后一次访问时间到缓存失效之时,两者之间的间隔,单位为秒(s)

timeToLiveSeconds

必须大于timeToldleSeconds属性,才有意义;
当对象自从被存放到缓存中后,如果处于缓存中的时间超过了 timeToLiveSeconds属性值,
这个对象就会过期,EHCache将把它从缓存中清除;
即缓存自创建日期起能够存活的最长时间,单位为秒(s)

overflowToDisk

如果为true,表示当基于内存的缓存中的对象数目达到了maxElementsInMemory界限后
会把溢出的对象写到基于硬盘的缓存中。
注意,如果缓存的对象要写入到硬盘中的话,则该对象必须实现了Serializable接口才行(也就是序列化);

memoryStoreEvictionPolicy

缓存对象清除策略。
有三种:

   FIFO:first in first out
   先进先出。

   LFU:Less Frequently Used
   一直以来最少被使用策略,缓存元素有一个hit属性,hit(命中)值最小的将会被清除出缓存。

   LRU:least Recenly used
   最近最少被使用,缓存的元素有一个时间戳,当缓存的容量满了,
   而又需要腾出地方来缓存新的元素的时候,
   那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。

diskSpoolBufferSizeMB

写入磁盘的缓冲区大小。
由于diskSpoolBufferSizeMB在内部实际是以字节为单位,
所以最大值是Integer的最大值即2047.99…M,反正不到2G。
所以如果配置的超过2G,将会导致diskSpoolBufferSizeMB为负数,
在put时ehcache误以为磁盘缓存队列已满,每次都执行都会阻塞。

maxElementsOnDisk

在DiskStore(磁盘存储)中的最大对象数量,如为0,则没有限制

diskPersistent

是否disk store在虚拟机启动时持久化。默认为false

diskExpiryThreadIntervalSeconds

Ehcache后台线程专门做Ellment失效监测以及清除工作。
此值不宜设置过低,否则会导致清理线程占用大量CPU资源。
默认值是120秒。

clearOnFlush

当调用flush()是否清除缓存,默认是。

maxEntriesLocalHeap

堆内存中最大缓存对象数,0没有限制

然后java代码

Cache articleCache = cacheManager.getCache("articleCache")

这样就拿到了cache对象 就可以操作Element了
第三层 就是我们开始说的Element
主要就是cache中的一些方法 我只说一些比较常用的

//存储一个Element  这样就存储了一个key为1  value为2的Element
articleCache.put(new Element(1, 2));
//有存就有取  看一下 这里是通过Element 中的key 拿到Element自己
 Element element = articleCache.get(1);
 //通过element拿到value值  这里可以直接强制类型转换 转换成你要的 注意不要转错了就行
 Object objectValue = element.getObjectValue();
 Integer i = (Integer)element.getObjectValue();
//拿到所有的key
List keys = articleCache.getKeys();
//通过key集合拿对象   这里返回的map 是不是很奇怪,其实方便了你的使用map的key 就是 Element中的key  直接get就可以拿出来了
Map<Object, Element> all = articleCache.getAll(keys);

下面我说一下注意事项:
基于Java 传址不传值 的特性 从ehcache中取出来的对象 如果直接更改它的属性 ehcache中的对象会一样被改。因为取出来和里面的是同一个对象。包括放进List 再怎么怎么样 。除非自己再拷贝一个。注意浅拷贝和深拷贝 这里就不多说了

Springboot 有和ehcache 集成一套注解使用 个人觉得 本来也没那么麻烦。那个还要写表达式,使用也没这么灵活。所以我自己不喜欢用。

ehcache 集群的知识

某度一搜 差不多都是基于官网的翻译。那张官方图片已经不知道在几个地方见过了。
ehcache 集群有好几种实现方式,详情baidu 我这里直说基于RMI的,所以先说RMI是个啥。
RMI(Remote Method Invocation)中文名:远程方法调用,能够让在客户端Java虚拟机上的对象像调用本地对象一样调用服务端java 虚拟机中的对象上的方法。
基于RMI的配置有自动发现和手动发现 我这里直说手动的 自动的还没有尝试过。
因为这东西是JVM提供的,所以不需要任何其他 jar 可以直接使用
主要也是依赖于配置 几乎不需要任何代码侵入。 还是ehcache.xml

   <!-- 成员发现对象 cacheManagerPeerProviderFactory配置  -->
  <cacheManagerPeerProviderFactory
            class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
            properties="
        peerDiscovery=manual,  //手动发现
        remoteObjectPort=40003,  //监听端口,这个东西如果你开了防火墙,就得手动配置,并且这个端口加入白名单,如果没防火墙就不用了
        rmiUrls=//127.0.0.1:40002/articleCache     //监听谁的cache 配置对方的如果有多个 中间用  |   隔开

"
  />
  <!--监听对象  配置自己的  其中有自己的名字 自己的端口 连接超时时间等-->
  <cacheManagerPeerListenerFactory
            class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
            properties="hostName=127.0.0.1, port=40001,
            socketTimeoutMillis=2000"/>

这两个是放在 ehcache标签里面的
然后是放在cache标签里面的
<cache name="updateCache"
           eternal="true"
           maxElementsInMemory="10000"
           overflowToDisk="false"
           diskPersistent="false"
           timeToIdleSeconds="0"
           timeToLiveSeconds="0"
           memoryStoreEvictionPolicy="LRU" >
        <cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
                                   properties="replicateAsynchronously=true,
         replicatePuts=true,
         replicateUpdates=true,
         replicateUpdatesViaCopy=true,
         replicateRemovals=true"/>
        <!-- 用于在初始化缓存,以及自动设置 -->
        <!--<bootstrapCacheLoaderFactory class="net.sf.ehcache.bootstrap.BootstrapCacheLoaderFactory"/>-->
        <bootstrapCacheLoaderFactory
                class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"
                properties="bootstrapAsynchronously=true, maximumChunkSizeBytes=5000000"/>
    </cache>
<!-- 
   
   RMI缓存分布同步查找 class使用net.sf.ehcache.distribution.RMICacheReplicatorFactory
        这个工厂支持以下属性:
        replicatePuts=true | false – 当一个新元素增加到缓存中的时候是否要复制到其他的peers。默认是true。
        replicateUpdates=true | false – 当一个已经在缓存中存在的元素被覆盖时是否要进行复制。默认是true。
        replicateRemovals= true | false – 当元素移除的时候是否进行复制。默认是true。
        replicateAsynchronously=true | false – 复制方式是异步的还是同步的 指定为true时是异步的额,默认是true。
        replicatePutsViaCopy=true | false – 当一个新增元素被拷贝到其他的cache中时是否进行复制 指定为true时为复制,默认是true。
        replicateUpdatesViaCopy=true | false – 当一个元素被拷贝到其他的cache中时是否进行复制 指定为true时为复制,默认是true。
            asynchronousReplicationIntervalMillis=1000
-->

这个里面配置很简单 有几个我使用中总结需要注意的
1、由于RMI需要通知,所以你改了对象后 需要调用put方法 告诉ehcache 你改了它,什么不做不通知
2、同步和异步的问题,这里我本机实验,同步基于你对象的大小 所有需要同步的对象必须实现序列化,
序列化快自然就快。但是but 然而 如果 你配置的地址找不到人,rmiUrls=//127.0.0.1:40002/articleCache
这个东西,他会耗时很多 我本地是一个1s 注意是秒
这个底层实现 大约是这样的
启动时 会读取你这个配置放进一个map 每次 监听到有改动时遍历map 每个去通知 所以也就是不支持动态增减机器的
谁挂了仍然可以正常使用,注意失败log 是DUBUG级别的。
放一下所有两个配置文件 仅供参考

server1:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">
    <diskStore path="java.io.tmpdir/Tmp_EhCache" />
    <defaultCache eternal="false"
                  maxElementsInMemory="1000"
                  overflowToDisk="false"
                  diskPersistent="false"
                  timeToIdleSeconds="0"
                  timeToLiveSeconds="600"
                  memoryStoreEvictionPolicy="LRU" />

    <!-- server1 的cacheManagerPeerProviderFactory配置 -->
    <cacheManagerPeerProviderFactory
            class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
            properties="
        peerDiscovery=manual,
        remoteObjectPort=40003,
        rmiUrls=//127.0.0.1:40002/articleCache|//127.0.0.1:40002/commentCache

"
    />
    <cacheManagerPeerListenerFactory
            class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
            properties="hostName=127.0.0.1, port=40001,
            socketTimeoutMillis=2000"/>

    <cache name="articleCache"
           eternal="true"
           maxElementsInMemory="10000"
           overflowToDisk="false"
           diskPersistent="false"
           timeToIdleSeconds="0"
           timeToLiveSeconds="0"
           memoryStoreEvictionPolicy="LRU" >
        <cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
                                   properties="replicateAsynchronously=true,
         replicatePuts=true,
         replicateUpdates=true,
         replicateUpdatesViaCopy=true,
         replicateRemovals=true,
replicateAsynchronously=false"/>
        <!-- 用于在初始化缓存,以及自动设置 -->
        <!--<bootstrapCacheLoaderFactory class="net.sf.ehcache.bootstrap.BootstrapCacheLoaderFactory"/>-->
        <bootstrapCacheLoaderFactory
                class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"
                properties="bootstrapAsynchronously=true, maximumChunkSizeBytes=5000000"/>
    </cache>



    <cache name="commentCache"
           eternal="false"
           maxElementsInMemory="50000"
           overflowToDisk="false"
           diskPersistent="false"
           timeToIdleSeconds="0"
           timeToLiveSeconds="0"
           memoryStoreEvictionPolicy="LRU" >
        <cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
                                   properties="replicateAsynchronously=true,
         replicatePuts=true,
         replicateUpdates=true,
         replicateUpdatesViaCopy=true,
         replicateRemovals=true "/>
        <!-- 用于在初始化缓存,以及自动设置 -->
        <!--<bootstrapCacheLoaderFactory class="net.sf.ehcache.bootstrap.BootstrapCacheLoaderFactory"/>-->
        <bootstrapCacheLoaderFactory
                class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"
                properties="bootstrapAsynchronously=true, maximumChunkSizeBytes=5000000"/>
    </cache>
</ehcache>

server2:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">
    <diskStore path="java.io.tmpdir/Tmp_EhCache" />
    <defaultCache eternal="false"
                  maxElementsInMemory="1000"
                  overflowToDisk="false"
                  diskPersistent="false"
                  timeToIdleSeconds="0"
                  timeToLiveSeconds="600"
                  memoryStoreEvictionPolicy="LRU" />

    <!-- server1 的cacheManagerPeerProviderFactory配置 -->
    <cacheManagerPeerProviderFactory
            class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
            properties="
        peerDiscovery=manual,
        remoteObjectPort=40004,
        rmiUrls=//127.0.0.1:40001/articleCache|//127.0.0.1:40001/commentCache"
    />

    <cacheManagerPeerListenerFactory
            class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
            properties="hostName=127.0.0.1, port=40002,
            socketTimeoutMillis=2000"/>

    <cache name="articleCache"
           eternal="true"
           maxElementsInMemory="10000"
           overflowToDisk="false"
           diskPersistent="false"
           timeToIdleSeconds="0"
           timeToLiveSeconds="0"
           memoryStoreEvictionPolicy="LRU" >
        <cacheEventListenerFactory
                class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
                properties="replicateAsynchronously=true,
        replicatePuts=true,
        replicateUpdates=true,
        replicateUpdatesViaCopy=true,
         replicateAsynchronously=true,
        replicateRemovals=true "/>
        <!-- 用于在初始化缓存,以及自动设置 -->
        <!--<bootstrapCacheLoaderFactory class="net.sf.ehcache.bootstrap.BootstrapCacheLoaderFactory"/>-->
        <bootstrapCacheLoaderFactory
                class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"
                properties="bootstrapAsynchronously=true">
        </bootstrapCacheLoaderFactory>
    </cache>
    <cache name="commentCache"
           eternal="false"
           maxElementsInMemory="50000"
           overflowToDisk="false"
           diskPersistent="false"
           timeToIdleSeconds="0"
           timeToLiveSeconds="0"
           memoryStoreEvictionPolicy="LRU" >
        <cacheEventListenerFactory
                class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
                properties="replicateAsynchronously=true,
        replicatePuts=true,
        replicateUpdates=true,
        replicateUpdatesViaCopy=true,
         replicateAsynchronously=true,
        replicateRemovals=true "/>
        <!-- 用于在初始化缓存,以及自动设置 -->
        <!--<bootstrapCacheLoaderFactory class="net.sf.ehcache.bootstrap.BootstrapCacheLoaderFactory"/>-->
        <bootstrapCacheLoaderFactory
                class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"
               >
        </bootstrapCacheLoaderFactory>
    </cache>
</ehcache>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值