Ehcache食用指南

简介: 可以使用CacheConfigurationBuilder来创建cache配置,分别用heap() 和offheap()来指定堆存储和堆外存储配置,这两个方法都支持指定存储实例数或者存储空间的大小。上面代码中1指定最大存储2gb,2表最多存储10个实例,超过了就会用默认的LRU策略往下层淘汰。

最近我们有个服务的时延(Latency)略微上涨,gc时间上涨了一倍,dump出java堆(Heap)之后用Mat分析发现,有份cache数据占据了20%+的堆内存,拥有上千万个小对象。然而这部分数据只是部分逻辑会用到,所以它占据这么大的堆内空间显得有些不值,并且会影响到gc进而影响到服务的时延。

  当然也有一些其他数据也占用比较多的堆内空间,但做优化总是先拿大头开刀。 当然把这份数据去掉是不可能了,因为上面还承载着几个比较重要的业务逻辑。既然数据放到java 堆内影响gc,是否可以放到堆外?答案是肯定的,这也是我写这篇博客的目的。就是用Ehcahe把数据移动到堆外,ehcahe甚至可以把数据放到磁盘、放到远端服务器。


如何使用

首先是导入ehcache包,如果你用maven等包管理工具就很简单了,否则你就得手动下载jar,然后导入到你的项目里 。

 ehcache的使用也很简单,大概可以分为4步骤,和把大象关进冰箱一样简单。

 1. 创建cache manager

 2. 创建cache

 3. 使用

 4. 关闭cache

// 第一步 
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder() 
    .withCache("preConfigured",
        CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.heap(10))) 
    .build(); 
cacheManager.init(); 
//第二步
Cache<Long, String> preConfigured =
    cacheManager.getCache("preConfigured", Long.class, String.class); 
Cache<Long, String> myCache = cacheManager.createCache("myCache", 
    CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.heap(10)));
//第三步
myCache.put(1L, "da one!"); 
String value = myCache.get(1L); 
cacheManager.removeCache("preConfigured"); 
//第四步  
cacheManager.close(); 

上文代码中,build cacheManager时也同时创建了一个名为 “preConfigured"的cache,也可以在cacheManager创建完后再创建cache,比如后面的“myCache”。之后使用就如同使用普通的map一样。 但非常关键的一点,如果cache不再用了,要记得删掉,cacheManager也要及得及时close掉,否则容易导致内存泄露,为什么之后会说到。

2bc93536c0dd7cb95f956149770712a7_2019061614035519.png

 在createCache时,需要指定3个参数,分别是cache里key value的class,和一份存储配置ResourcePools。 这是因为ehcache支持多级存储(这也是它最大的特性),你可以配置部分数据优先存储在堆内,存不下就存堆外,再存不下可以存在磁盘。 所以它需要知道key和value的class,用来对K-V做序列化和反序列化,方便多层级之间数据传输。

 因为存在对象的序列化和反序列化,你就不得不考虑下性能问题,因为序列化和反序列化都是需要时间的。但所幸的是有个局部性法则让你不用太多担心。ehcache里默认cache策略是LRU,它优先把数据优先存堆(heap)里的,内存中存不下以及被LUR淘汰下来的数据会被ehcache序列化后存入堆外或者磁盘。LRU策略会逐步把低频使用的数据往下层存储淘汰,从而保证高频数据尽可能都在上层存储中。

 像上面ehcahe这种多层级的设计,可以再尽可能少的影响性能的情况下减少堆内内存的使用,也可以减少内存的使用。 但有个可能的风险点,java语言本身其实是不太希望用户使用堆外的空间的,因为堆外空间脱离的JVM的控制,JVM无法对其做GC,可能会有内存泄露的风险。ehcache不得不让用户去考虑内存空间释放的问题,虽然很简单调用下removeCahce()和close()就行,但依旧有内存泄露的风险。


多级存储

上面已经提到了Ehcache的多级存储,共支持4个级别的存储。


堆外

磁盘

集群

 如果分别使用上面四中存储,Ehcache提供一个个CacheConfigurationBuilder来创建相关配置。

CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, 
  ResourcePoolsBuilder.newResourcePoolsBuilder().offheap(2, MemoryUnit.GB)).build();  // 1
ResourcePoolsBuilder.newResourcePoolsBuilder().heap(10, EntryUnit.ENTRIES);     // 2
// or
ResourcePoolsBuilder.heap(10); 
// or
ResourcePoolsBuilder.newResourcePoolsBuilder().heap(10, MemoryUnit.MB); 

可以使用CacheConfigurationBuilder来创建cache配置,分别用heap() 和offheap()来指定堆存储和堆外存储配置,这两个方法都支持指定存储实例数或者存储空间的大小。上面代码中1指定最大存储2gb,2表最多存储10个实例,超过了就会用默认的LRU策略往下层淘汰。

 如果要使用磁盘存储,在cache创建是需要先指定存储的路径和文件名,使用示例如下。

PersistentCacheManager persistentCacheManager = CacheManagerBuilder.newCacheManagerBuilder() 
  .with(CacheManagerBuilder.persistence(new File(getStoragePath(), "myData"))) 
  .withCache("persistent-cache", CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
    ResourcePoolsBuilder.newResourcePoolsBuilder().disk(10, MemoryUnit.MB, true)) 
  )
  .build(true);
persistentCacheManager.close();

集群存储方式配置参考文档cluster cache

 这些存储策略可以随意组合,比如以下的使用方式都是支持的。


 - 堆 + 堆外

 - 堆 + 堆外 + 磁盘

 - 堆 + 堆外 + 集群

 - 堆 + 磁盘

 - 堆 + 集群

目录
相关文章
|
算法 数据挖掘 Python
【数据挖掘】层次聚类DIANA、AGNES算法讲解及实战应用(图文解释 超详细)
【数据挖掘】层次聚类DIANA、AGNES算法讲解及实战应用(图文解释 超详细)
1174 0
|
人工智能 API
【保姆级教程]】5分钟用阿里云百炼满血版DeepSeek, 手把手做一个智能体
阿里云推出手把手学AI直播活动,带你体验DeepSeek玩法。通过阿里云百炼控制台,用户可免费开通满血版R1模型,享受100w token免费额度。活动还包括实验步骤、应用开发教程及作业打卡赢好礼环节,提交优秀作品更有机会获得定制礼品。快来参与吧!
2801 0
|
11月前
|
数据采集 存储 JavaScript
如何利用 Puppeteer 的 Evaluate 函数操作网页数据
本文介绍如何使用Puppeteer结合代理IP技术,高效采集界面新闻等网站的文章标题和摘要。通过`evaluate`函数操作DOM,配合代理IP实现稳定的数据抓取。
197 0
|
Ubuntu Linux 数据安全/隐私保护
使用Cython库包对python的py文件(源码)进行加密,把python的.py文件生成.so文件并调用
本文介绍了在Linux系统(Ubuntu 18.04)下将Python源代码(`.py文件`)加密为`.so文件`的方法。首先安装必要的工具如`python3-dev`、`gcc`和`Cython`。然后通过`setup.py`脚本使用Cython将`.py文件`转化为`.so文件`,从而实现源代码的加密保护。文中详细描述了从编写源代码到生成及调用`.so文件`的具体步骤。此方法相较于转化为`.pyc文件`提供了更高的安全性。
1168 2
|
存储 算法 Java
List的魔法:如何在Java中实现高效有序存储
【6月更文挑战第17天】在Java中,List接口(如ArrayList和LinkedList)实现有序存储,便于高效检索和排序。ArrayList适合索引访问,而LinkedList擅长插入删除。Collections.sort()和Java 8的Stream API能进一步优化排序和操作。优先队列或平衡二叉搜索树等数据结构在特定场景下也能提升有序存储效率。
307 0
|
缓存 Java
ehcache.xml配置文件详解
ehcache.xml配置文件详解
|
存储 边缘计算 物联网
边缘计算的类型及应用概述
边缘计算将计算与存储推向网络边缘,提升响应速度,降低带宽需求。它涵盖边缘设备、边缘数据中心、边缘云及边缘服务器型计算,应用于智能家居、物联网、工业自动化和智能医疗等领域,实现低延迟、高效能与数据安全。随着技术发展,边缘计算在数字化转型中扮演关键角色。
|
Kubernetes Go Docker
Kubernetes容器生命周期 —— 钩子函数详解(postStart、preStop)
4.2 结论 • postStart不会挡住主进程的启动; • postStart的执行相对于容器主进程的执行是异步的,它会在容器start后立刻触发,并不能保证PostStart钩子在容器ENTRYPOINT指令执行完毕之前运行。 5、使用场景
517 0
|
人工智能 API
【AgentGPT】网页版的 Auto-GPT,让 AI 成为我们的生产力工具
【AgentGPT】网页版的 Auto-GPT,让 AI 成为我们的生产力工具