Redian新闻
>
缓存之美 —— 如何选择合适的本地缓存?

缓存之美 —— 如何选择合适的本地缓存?

公众号新闻


作者:京东云开发者-京东保险 郭盼

链接:https://my.oschina.net/u/4090830/blog/10768446

1、简介

小编最近在使用系统的时候,发现尽管应用已经使用了 redis 缓存提高查询效率,但是仍然有进一步优化的空间,于是想到了比分布式缓存性能更好的本地缓存,因此对领域内常用的本地缓存进行了一番调研,有早期的 Guava 缓存、在 Guava 上进一步传承的 Caffine 以及自称在 Java 中使用最广泛的 EhCache,那么我们该怎么选择适合自己应用的缓存呢,小编下面会简单介绍,并将以上缓存进行一个对比,希望帮助大家选择最适合自己系统的本地缓存。

2、Guava 缓存简介

Guava cache 是 Google 开发的 Guava 工具包中一套完善的 JVM 本地缓存框架,底层实现的数据结构类似于 ConcurrentHashMap,但是进行了更多的能力拓展,包括缓存过期时间设置、缓存容量设置、多种淘汰策略、缓存监控等,下面简单介绍下这些功能及其使用方式。

2.1、缓存过期时间设置

Guava 的过期时间设置有基于创建时间和最后一次访问时间两种策略.
(1) 基于创建时间
通过对比缓存记录的插入时间来判断,比如设置过期时间为 5 分钟,不管中间有没有访问,到时过期。
public Cache<String, String> createCache() {    
return CacheBuilder.newBuilder()
.expireAfterWrite(5L, TimeUnit.MINUTES)
.build();
}

(2) 基于过期时间

通过对比最近最后一次的访问时间,比如设置 5 分钟,每次访问之后都会刷新过期时间为 5 分钟,只有持续 5 分钟没有被访问到才会过期。

public Cache<String, String> createCache() {    
return CacheBuilder.newBuilder()
.expireAfterAccess(5L, TimeUnit.MINUTES)
.build();
}

2.2、缓存容量和淘汰策略设置

Guava cache 是内存型缓存,有内存溢出风险,因此需要设置缓存的最大存储上限,通过缓存的条数或每条缓存的权重来判断是否达到了设定阈值,当缓存的数据量达到设定阈值之后,Guava cache 支持使用 FIFO 和 LRU 的策略对缓存记录采取淘汰的措施。
(1)限制缓存记录条数
public Cache<String, User> createCache() {    
return CacheBuilder.newBuilder()
.maximumSize(100L)
.build();
}

(2)限制缓存记录权重

public Cache<String, User> createCache() {    
return CacheBuilder.newBuilder()
.maximumWeight(100L)
.weigher((key, value) -> (int) Math.ceil(instrumentation.getObjectSize(value) / 1024L))
.build();
}
使用限制缓存记录权重时要先计算 weight 的 value 对象的字节数,每 1kb 字节作为一个权重,对比限制缓存记录,我们就能将缓存的总占用限制在 100kb 左右。

2.3 缓存监控

缓存记录的加载和命中情况是评价缓存处理能力的重要指标,Guava cache 提供了 stat 统计日志对这两个指标进行了统计,我们只需要在创建缓存容器的时候加上 recordStats 就可以开启统计。
public Cache<String, User> createCache() {    
return CacheBuilder.newBuilder()
.recordStats()
.build();
}

2.4 Guava cache 的优劣势和适用场景

优劣势:Guava cache 通过内存处理数据,具有减少 IO 请求,读写性能快的优势,但是受内存容量限制,只能处理少量数据的读写,还有可能对本机内存造成压力,并且在分布式部署中,会存在不同机器节点数据不一致的情况,即缓存漂移。
适用场景:读多写少,对数据一致性要求不高的场景。

3、Caffeine 简介

Caffeine 同样是 Google 开发的,是在 Guava cache 的基础上改良而来的,底层设计思路、功能和使用方式与 Guava 非常类似,但是各方面的性能都要远远超过前者,可以看做是 Guava cache 的升级版,因此,之前使用过 Guava cache,也能够很快的上手 Caffeine,下面是 Caffeine 和 Guava cache 的缓存创建对比,基本可以无门槛过渡。
public Cache<String, String> createCache() {
return Caffeine.newBuilder()
.initialCapacity(1000)
.maximumSize(100L)
.expireAfterWrite(5L, TimeUnit.MINUTES)

.recordStats()
.build();
}


public Cache<String, String> createCache() {    
return CacheBuilder.newBuilder()
.initialCapacity(1000)
.maximumSize(100L)
.expireAfterWrite(5L, TimeUnit.MINUTES)
.recordStats()
.build();
}
那么 Caffeine 底层又做了哪些优化,才能让其性能高于 Guava cache 呢?主要包含以下三点:

3.1、对比 Guava cache 的性能主要优化项

(1)异步策略
Guava cache 在读操作中可能会触发淘汰数据的清理操作,虽然自身也做了一些优化来减少读的时候的清理操作,但是一旦触发,就会降低查询效率,对缓存性能产生影响。而在 Caffeine 支持异步操作,采用异步处理的策略,查询请求在触发淘汰数据的清理操作后,会将清理数据的任务添加到独立的线程池中进行异步操作,不会阻塞查询请求,提高了查询性能。
(2)ConcurrentHashMap 优化
Caffeine 底层都是通过 ConcurrentHashMap 来进行数据的存储,因此随着 Java8 中对 ConcurrentHashMap 的调整,数组 + 链表的结构升级为数组 + 链表 + 红黑树的结构以及分段锁升级为 syschronized+CAS,降低了锁的粒度,减少了锁的竞争,这两个优化显著提高了 Caffeine 在读多写少场景下的查询性能。
(3)新型淘汰算法 W-TinyLFU
传统的淘汰算法,如 LRU、LFU、FIFO,在实际的缓存场景中都存在一些弊端,如 FIFO 算法,如果缓存使用的频率较高,那么缓存数据会一直处在进进出出的状态,间接影响到缓存命中率。LRU 算法,在批量刷新缓存数据的场景下,可能会将其他缓存数据淘汰掉,从而带来缓存击穿的风险。LFU 算法,需要保存缓存记录的访问次数,带来内存空间的损耗。
因此,Caffeine 引入了 W-TinyLFU 算法,由窗口缓存、过滤器、主缓存组成。缓存数据刚进入时会停留在窗口缓存中,这个部分只占总缓存的 1%,当被挤出窗口缓存时,会在过滤器汇总和主缓存中淘汰的数据进行比较,如果频率更高,则进入主缓存,否则就被淘汰,主缓存被分为淘汰段和保护段,两段都是 LRU 算法,第一次被访问的元素会进入淘汰段,第二次被访问会进入保护段,保护段中被淘汰的元素会进入淘汰段,这种算法实现了高命中率和低内存占用。更详细的解释可以参考论文:https://arxiv.org/pdf/1512.00727.pdf

3.2、Caffeine 的优劣势和适用场景

优势:对比 Guava cache 有更高的缓存性能,劣势:仍然存在缓存漂移的问题;JDK 版本过低无法使用
适用场景:1、适用场景:读多写少,对数据一致性要求不高的场景;2、纯内存缓存,JDK8 及更高版本中,追求比 Guava cache 更高的性能。

4、Ehcache 简介

Guava cache 和 Caffeine 都是 JVM 缓存,会受到内存大小的制约,最新的 Ehcache 采用堆内缓存 + 堆外缓存 + 磁盘的方式,打破了这一制约。堆内缓存就是被 JVM 管理的那一部分缓存,而堆外缓存,就是在内存中另外在开辟一块不被 JVM 管理的部分。堆外缓存这部分既可以享受内存的高速读写能力,而且又避免的 JVM 频繁的 GC,缺点是需要自行清理数据。
下面是 Ehcache 缓存的创建,指定了堆内、堆外缓存和磁盘缓存的大小。
ResourcePoolsBuilder.newResourcePoolsBuilder()
.heap(20, MemoryUnit.MB)
.offheap(10, MemoryUnit.MB)
.disk(5, MemoryUnit.GB);


为了解决缓存漂移的问题,Ehcache 支持通过集群的方式,实现了分布式节点之间的数据互通。关于 Ehcache 的集群策略,后续文章再详细阐述。

5、不同本地缓存对比

框架命中率速度回收算法使用难度集群适用场景
Guava cache第三LRU、LFU、FIFO不支持读多写少,允许少量缓存偏移
Caffeine第一W-TinyLFU不支持读多写少,允许少量缓存偏移,能用 Caffeine 就别用 Guava cache
Ehcache第二LRU、LFU、FIFO支持分布式系统中对数据一致性要求高


END



AI 领域大佬欢聚一堂 跳起科目三



这里有最新开源资讯、软件更新、技术干货等内容

点这里 ↓↓↓ 记得 关注✔ 标星⭐ 哦~

微信扫码关注该文公众号作者

戳这里提交新闻线索和高质量文章给我们。
相关阅读
加拿大TOP1多伦多大学,7大学院如何选择?【广州美国中心活动】模拟初选:美国如何选择其候选人,1月20日,星期六,下午2:30-4:00(2:00 开始入场)本地缓存之王,Caffeine 保姆级教程奥司他韦、阿比多尔、玛巴洛沙韦,三者有何区别?临床该如何选择?母婴代理商选择合作品牌和门店的标准是?台湾大选蓝白合与统计误差创业者入局AI,如何选择方向?|亮马桥会客室卫生间瓷砖如何选择?不光要好看,这3点也很关键!【装修干货】Sora大火!AI成各顶级名校新晋爆火专业!下一代留学生该如何选择专业?想知道ta是不是合适的结婚对象|赶紧抓住这个最后机会AI 浪潮下程序员的生存之道|直播预告抄底资金在行动!沪深300ETF份额暴增365亿......投资者该如何选择?【资讯】Livret A存满之后,闲置资金可以往哪存?是走是留?加拿大移民以真实体验揭示生存之道,华人有话说...博士毕业后,我为何选择去当中学教师?Heart:对于非ST段抬高型急性冠脉综合征,早期介入vs标准治疗如何选择?你的医嘱可能下错了?糖尿病患者需要喝饮料?!BMJ(IF=106)发现糖尿病患者合适的饮料摄入量增加与死亡率降低相关美高申请干货 | 如何选择适合你的美国寄宿高中?这个摄影师该点赞:高端大气上档次涨价去库存?汪芳教授:他汀药这么多种,如何选择呢?少踩雷!教你如何为孩子选择合适的科普书2023年第三季度移民统计出炉:机遇挑战并存,未来移民英国如何选择?新能源内卷时代如何生存?加州富人大迁徙!洛杉矶失宠,富人们为何选择离开?揭示新兴居住地的魅力!红色日记 永放光芒 5.1-31第118章 中秋宫宴清华大学副教授,为何选择成为军队文职人员?30万都找不到合适的留学顾问了?魔都妈花十几万早申Top10已下车……甲流、乙流抗病毒药物如何选择?看看最新指南怎么说!今日最佳:东北司机生存之道。腹泻患者如何选择治疗药物?别只会开蒙脱石散经验大放送|我为何选择工作,而不是二战,一个普通 211 一战人大应统 384 分失败生的心声Redis缓存与Mysql如何保证双写一致中国外交新耻辱/王剑误判猜鹿为马
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。