【精品】JDK17下使用Ehcache3

【精品】JDK17下使用Ehcache3,第1张

Ehcache简介

Ehcache 是一个开源的高性能缓存,拥有很高的拓展性和伸缩性,广泛使用各种 Java 项目中(如 Hibernate 默认使用 Ehcache作为二级缓存),在目前基于 Java 的缓存方案里,几乎是性能最高的实现。

Ehcache 官网:http://www.ehcache.org
Ehcache 3.X 技术文档:http://www.ehcache.org/documentation/

Ehcache架构:
Ehcache的特点:

  • 缓存数据有三级:内存、堆外缓存Off-Heap、Disk缓存,因此无需担心容量问题。还可以通过RMI、可插入API等方式进行分布式缓存。
  • 缓存数据会在虚拟机重启的过程中写入磁盘,持久化。
  • 具有缓存和缓存管理器的侦听接口。
  • 支持多缓存管理器实例,以及一个实例的多个缓存区域。

Ehcache3支持堆、堆外、磁盘以及集群缓存;除了堆之外的三种缓存,缓存的键值对必须支持序列化和反序列化。我们在使用的时候,可以单独使用任意一个。

  • heap :堆上存储,利用Java的堆上RAM内存来存储缓存条目。该层使用与Java应用程序相同的堆内存
  • off-heap: 堆外内存,大小仅受可用RAM限制。不受Java垃圾回收(GC)的约束。与堆上存储相比,它速度较慢,因为在存储和重新访问JVM堆时必须将数据移入和移出JVM堆。
  • disk:利用磁盘(文件系统)存储缓存条目。存储空间充足,但比基于RAM的存储要慢得多。对于所有使用磁盘存储的应用程序,建议使用快速专用磁盘来优化吞吐量。
  • clustered:群集存储,该数据存储是远程服务器上的缓存。

使用

  • 常被查询、最重要、数据量较小的数据存放在堆缓存,不用担心JVM的重启,有持久化机制;
  • 常被查询、数据量中等的数据存放在堆外缓存,几个G就好了,不用担心服务器的重启,有持久化机制;
  • 不常用、大量的数据、但又不想占用数据库IO的数据,放在Disk缓存,容量自便;

如果要使用多个层,则必须遵守一些约束条件:

  • 必须始终有堆内存
  • disk和clusterd不能同时存在
  • 层的大小应采用金字塔式的大小,即,金字塔较高的层配置为使用的内存比下方较低的层少。

可能出现的层组合:

  • heap + offheap
  • heap + offheap + disk
  • heap + offheap + clustered
  • heap + disk
  • heap + clustered

注意:

  • 将值放入高速缓存时,它会直接进入最低层,比如heap + offheap + disk直接会存储在disk层。
  • 当获取一个值,从最高层获取,如果没有继续向下一层获取,一旦获取到,会向上层推送,同时上层存储该值。
小知识:堆外缓存
堆外缓存(off-heap)既是独立的进程缓存,又是JVM堆外的系统缓存。JVM堆是非常宝贵的,如果占用过大会带来GC性能问题,堆外缓存很好的解决了这个问题。现在服务器内存越来越大,而磁盘缓存的io性能又比较低,off-heap缓存就是折中的方案,既保证了高速性能,又可以有一定的容量。off-heap缓存性能的占用主要是序列化、反序列化的过程。一旦对象被序列化,在返回Java堆的时候必需反序列化才可以使用。这是一笔较大的性能开销。但off-heap还是要比本地磁盘、网络存储、RDBMS数据库IO等记录数据的系统要快的多。还应指出的是,序列化/反序列化的性能开销远没有很多用户想象的那么大。off-heap已经针对字节缓冲区做了优化,本身也包含一些优化机制,可以对使用标准Java序列化的对象进行优化,能使复杂Java对象的性能提升两倍,使byte数组的性能提升四倍。
示例

备注:由于JDK17的原因,xml配置方式使用Ehcache会报各种莫名其妙的问题,基本上没有研究的意义,所以下面示例只讲了Java代码的方式。

Maven依赖:
<dependency>
    <groupId>org.ehcachegroupId>
    <artifactId>ehcacheartifactId>
    <version>3.10.0version>
dependency>
<dependency>
    <groupId>javax.cachegroupId>
    <artifactId>cache-apiartifactId>
    <version>1.1.1version>
dependency>
测试代码一:创建CacheManager的同时指定Cache
@Test
public void fun1() {
    CacheManager manager = CacheManagerBuilder.newCacheManagerBuilder()
            .withCache("myCache", CacheConfigurationBuilder.newCacheConfigurationBuilder(Integer.class, String.class, ResourcePoolsBuilder.heap(100).build()))
            .build(true);

    //通过别名获取缓存
    Cache<Integer, String> cache = manager.getCache("myCache", Integer.class, String.class);

    cache.put(1001, "haha");

    String value = cache.get(1001);
    System.out.println(value);

    // 移除一个给定的Cache,CacheManager不仅会删除它对Cache的引用,而且还会关闭它。
    manager.removeCache("myCache");
    // 关闭CacheManager提供的所有临时资源。
    manager.close();
}

在cacheManager中检索Cache,需要通过别名、键类型,值类型。比如,要获得第2步中声明的缓存,您需要它的别名=“myCache”,keyType=Integer.class和valueType = String.class。出于类型安全考虑,我们要求键和值类型都要传递。如果这些和我们期望的不同CacheManager将会在应用程序生命周期的早期抛出一个ClassCastException这可以保护缓存免受随机类型的污染。
put()方法用来往Cache中添加内容,其中:第一个参数是键,第二个参数是值。键和值类型必须是与在cacheconfig容器中定义的类型相同的类型。另外,键必须是惟一的,并且只与一个值相关联。
get(key)方法用来从缓存中检索值。它只需要一个参数,这个参数是键,然后返回与该键关联的值。如果没有与该键相关联的值,则返回null。

测试代码二:
@Test
public void fun2() {
    CacheManager manager = CacheManagerBuilder.newCacheManagerBuilder()
            .build(true);

    //创建Cache实例
    CacheConfigurationBuilder<Integer, String> builder = CacheConfigurationBuilder.newCacheConfigurationBuilder(Integer.class, String.class,
            ResourcePoolsBuilder.heap(10)  //堆内缓存,速度最快
                    .offheap(2, MemoryUnit.MB)  // 堆外内存,速度低于 heap,但是高于 disk
            // .disk(1, MemoryUnit.GB)   //磁盘缓存,速度最低,相对于 heap和off-heap,disk可以分配大量资源空间
    ).withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(10)));

    Cache<Integer, String> cache = manager.createCache("myCache", builder);
    //写缓存
    cache.put(1001, "xixi");
    //读缓存
    String value = cache.get(1001);
    System.out.println(value);

    manager.removeCache("myCache");
    //关闭资源
    manager.close();
}
测试代码三:将数据缓存到本地硬盘上
@Test
public void fun4() {
    CacheManager manager = CacheManagerBuilder
            .persistence("d:/CacheData")    //硬盘缓存文件位置
            .builder(CacheManagerBuilder.newCacheManagerBuilder())
            .build();
    manager.init();

    //创建Cache实例
    CacheConfigurationBuilder<Integer, String> builder = CacheConfigurationBuilder.newCacheConfigurationBuilder(Integer.class, String.class,
            ResourcePoolsBuilder.heap(10));

    Cache<Integer, String> cache = manager.createCache("myCache", builder);
    //写缓存
    cache.put(1001, "xixi");
    //读缓存
    String value = cache.get(1001);
    System.out.println(value);

    manager.removeCache("myCache");
    //关闭资源
    manager.close();
}
测试代码四:
@Test
public void fun3() {
    UserManagedCache<Integer, String> cache = UserManagedCacheBuilder.newUserManagedCacheBuilder(Integer.class, String.class)
            .build(false);
    cache.init();

    //写
    cache.put(11, "aa");
    //读
    String value = cache.get(11);
    System.out.println(value);

    cache.close();
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/741049.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-28
下一篇 2022-04-28

发表评论

登录后才能评论

评论列表(0条)

保存