缓存润滑剂J2Cache

Posted 58无线技术

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了缓存润滑剂J2Cache相关的知识,希望对你有一定的参考价值。

什么是缓存

缓存就是数据交换的数据缓冲区,会首先从缓存汇总查询数据,有则直接执行,缓存中没有则逐级查询数据,在计算机内的缓存结构是这样的。
图1-计算机通用缓存结构

越在顶层的缓存设备越昂贵,速度越快,反之越在底层的价格越便宜,速度越慢。

为什么要使用缓存

缓存的使用是来源于人类的梦想,一个事物从无到有避免不了大量人力物力的开销,然而优良传统和现实环境对我们的鞭策,时时提醒着我们做事要多快好省,站点接口的响应速度、服务器的稳定性、数据的真实性,这一系列的参数就像紧箍咒一样,促使我们去使用技术去完善优化我们的应用。在日常开发中,缓存也就成为了必不可少的元素, Redis、Memcache、Ehcache、Caffeine 、SpringCache、guava cache等等,总有那么几个是你耳熟能详的,诸多成熟的缓存框架在应用的使用中也是五花八门,目前缓存的类型一般有 两种:
  1. 内存缓存(如 Ehcache)—速度快,进程内可用

  2. 集中式缓存(如 Redis)—可同时为多节点提供服务


现阶段基础的缓存架构:
缓存润滑剂J2Cache

图2-基础缓存架构

这样的缓存架构在平常服务正常运行起来不会有什么问题,平静如水。但是某些”临界“时,问题就逐一浮出水面了。


  1. 在使用本地缓存时,应用的冷启动,应用集群节点在重启时会清空本地缓存数据,导致缓存雪崩。
  2. 本地缓存数据无法在应用的集群共享。
  3. 在使用集中缓存时,由于大量节点通过缓存获取数据,数据吞吐量过大,导致网卡被打满,响应能力大大下降。


当本地缓存无法解决缓存雪崩和缓存共享问题时,我们自然就想到了使用Redis这类集中式缓存。但是当应用处于峰值由于QPS飙升,基数过于庞大,即使你本身传输的数据量并不大,也会导致Redis服务器的网卡被打满,但本身服务器的内存等资源不会发生过多的变化。这是我们又想到了服务器的扩展性,我们可以加机器,变成Redis集群,升级每一台机器的网卡为千兆网卡、万兆网卡。但是成本也会成倍甚至指数级别的增长。

缓存润滑剂J2Cache
图3-J2Cache架构


J2Cache就在这样一个矛盾的环境下诞生了,为了解决Redis网卡流量的问题,使用成熟优秀的内存缓存框架(Ehcache、Caffeine)作为应用的一级缓存,使用Redis作为二级缓存,在一级缓存过滤掉大量的请求,确保二级缓存Redis的访问次数可以降到最低。那么Redis网卡流量的问题解决了,那么J2Cache的缓存数据更新时每一个节点一级缓存是如何保持一致性的呢?


J2Cache 目前提供两种节点间数据同步的方案 —— Redis Pub/Sub 和 JGroups(目前云主机暂不支持) 。当某个节点的缓存数据需要更新时,J2Cache 会通过 Redis 的消息订阅机制或者是 JGroups 的组播来通知集群内其他节点。当其他节点收到缓存数据更新的通知时,它会清掉自己内存里的数据,然后重新从 Redis 中读取最新数据。


缓存润滑剂J2Cache
图4-J2Cache数据读取流程


缓存润滑剂J2Cache
图5-J2Cache数据更新流程


J2Cache中的Region

Redis、Caffeine、Guava Cache 是都没有 Region 这样的概念,特别是 Redis 是一个大哈希表,更没有这个概念。在实际的缓存场景中,不同的数据会有不同的 TTL 策略,例如有些缓存数据可以永不失效,而有些缓存我们希望是 30 分钟的有效期,有些是 60 分钟等不同的失效时间策略。在 Redis 我们可以针对不同的 key 设置不同的 TTL 时间。但是一般的 Java 内存缓存框架(如 Caffeine、Guava Cache 等),它没法为每一个 key 设置不同 TTL,因为这样管理起来会非常复杂,而且会检查缓存数据是否失效时性能极差。所以一般内存缓存框架会把一组相同 TTL 策略的缓存数据放在一起进行管理。J2Cache作为两者的桥梁需要兼容两者的特性。J2Cache 默认使用 Caffeine 作为一级缓存,其配置文件位于 caffeine.properties 中。一个基本使用场景如下:


缓存润滑剂J2Cache
上面的配置定义了三个缓存 Region ,分别是:
  1. 默认缓存,大小是 1000 个对象,TTL 是 30 分钟;
  2. users 缓存,大小是 2000 个对象,TTL 是 10 分钟;
  3. blogs 缓存,大小是 5000 个对象,TTL 是 1 个小时;

例如我们可以用 users 来存放用户对象的缓存,用 blogs 来存放博客对象缓存,两种的 TTL 是不同的。而 default 是当我们调用如下方法时:

如果我们传入的 region 参数(假设为:region1)没有在 caffeine.properties 中定义的话,那 J2Cache 会自动创建一个名为 region1 的缓存 Region,其配置和 default 的配置一致。


所以要用好缓存首先要确保以下几点:


  1. 根据业务规划好不同的 region 来存放不同的缓存数据;
  2. 根据实际情况确定每个 region 的缓存数据数量和 TTL 时间;
  3. 尽量必要未经定义直接使用一个全新的 region (避免使用 default 数据);


总结:
J2Cache并没有在缓存这一领域进行更深的开拓与研究,相比之下更像是一个缓存中间件的润滑剂,注重于解决实实在在的问题,把现存的优秀框架融合在一起去解决现实开发中棘手的困难。作为国内最大的开源社区之一OSChina使用J2Cache运行至今,稳定性也是毋庸置疑的,而且J2Cache作为一个开源项目社区也是非常活跃,每隔几天就会有代码更新。更值得一提的是这次Redis6公布的新特性中携带了客户端缓存策略,实现机制也基本上差别不大,红薯大神表示丝毫不慌。到底是Redis6的新客户端缓存性能更优呢还是J2Cache的策略更完善呢?我们拭目以待!

以上是关于缓存润滑剂J2Cache的主要内容,如果未能解决你的问题,请参考以下文章

springboot-cache缓存和J2cache二级缓存框架(带点漫画)

哪种缓存效果高?开源一个简单的缓存组件j2cache

开源工具 | 11月开源项目推荐

基于内存和 Redis 的两级 Java 缓存框架

pyinstaller 打包文件(包括使用管理员模式)

你知道影响润滑油性能作用的因素都有哪些吗?