主流缓存框架调研 - Guava/Caffeine/EhCache/JetCache...

Spring Cache
Spring Cache 是 Spring 提供的一整套的缓存解决方案。虽然它本身并没有提供缓存的实现,但是它提供了一整套的接口和代码规范、配置、注解等,这样它就可以整合各种缓存方案了,比如 Redis、Ehcache,我们也就不用关心操作缓存的细节。
https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#cache

特性

  1. 基于AOP与方法级注解实现自动缓存操作, 不需要手动进行缓存的写入与清除操作
  2. 官方提供了多种开箱即用的缓存实现(EhCache / Redis / Caffeine / Map 等), 也支持自定义缓存实现

解读

SpringCache是 spring-context 中的一个缓存抽象, 它主要封装一套注解:@Cacheable, @CacheEvict, @CachePut, @Caching, @CacheConfig, 配合Spring的AOP能力, 对接口层面的缓存提供了统一的规范, 并实现了切面中的复杂逻辑, 但是它底层并没有实现具体的缓存逻辑, 需要集成其他缓存框架来使用, 底层只需要实现他的 Cache 接口即可.
总的来说, Spring Cache并非是一个缓存框架, 但却是一个比较好的缓存框架扩展. 可以配合其他缓存框架来使用, 使得缓存框架无需自己去实现AOP与自定义注解这块功能
 

Guava Cache

GuavaCache是 Google 开源的一级缓存框架, 可以理解为 ConcurrentHashMap 的增强版, 使其适合用来作为一个缓存集合
https://github.com/google/guava/wiki/CachesExplained

特性

  1. 基于ConcurrentHashMap, 支持高并发下的线程安全, 性能也做了优化
  2. 提供CacheBuilder, 简化缓存操作对象的创建, 支持设置自定义的CacheLoader用来加载数据至缓存
  3. 使用软引用与弱引用机制, 保障GC安全
  4. 支持key移除监听, 支持同步监听与异步监听, 在key移除后执行一些逻辑
  5. 支持多个缓存清除策略: 存活时间 / 最大容量 / 主动清除 / 软弱引用
  6. 支持获取指定缓存集合的命中率等指标

解读

GuavaCache的出现其实是简化了日常的本地缓存使用方式, 在这之前, 我们想要做本地缓存一般都是基于HashMap等方式自行封装缓存操作工具, 自己维护 缓存策略 / 淘汰策略, 性能不没有保障, 内存泄漏的风险也很高, 而 GuavaCache 帮大家将这些封装打包起来了, 还支持了许多额外的扩展功能, 最终提供一个开箱即用的缓存工具包, 用户不需要再去关心里面的实现细节, 内存/性能问题也得到了保障
总的来说, GuavaCache是一个十分优秀的轻量级的本地缓存框架, 可以直接使用
 

Caffeine

Caffeine 是以 GuavaCache 为原型而开发的一个本地缓存框架, 相对GuavaCache, 它有更高的性能与命中率, 更强大的功能, 更灵活的配置方式

特性

  1. 具备GuavaCache几乎所有特性, 并提供了适配器, 方便Guava用户迁移至Caffeine, 两者差异见: https://github.com/ben-manes/caffeine/wiki/Guava-zh-CN
  2. 通过异步维护/异步通知/异步刷新等方式, 达到了极致的读写性能
  3. 实现了JSR-107 JCache接口API

解读

我们可以将Caffeine看做是GuavaCache的升级版, 它主要在性能和命中率上碾压了Guava, 这有两方面造成, 一是Caffeine将所有阻塞读写的操作全部通过ForkJoinPool实现异步处理, 二是Caffeine优化了缓存淘汰算法(Window LRU), 除此之外, 在一些细节的实现逻辑上, Caffeine也做了一定的调整, 比如: 替换通知 / null值处理 / 统计方式.
总的来说, 如果说你想使用GuavaCache, 那你可以先考虑下Caffeine
 

J2Cache

J2Cache是 OSChina 开源的一个两级缓存框架, 采用固定的 一级 + 二级缓存 的模式, 从一开始就是为了解决两级缓存一致性的问题
https://gitee.com/ld/J2Cache

特性

  1. 当二级缓存更改或失效时, 自动通知节点清除一级缓存 (支持RedisPubsub/MQ/JGroup等方式)
  2. 支持集成多种一二级缓存, 如: Caffeine/EhCache/Redis/Memcache等, 或自定义缓存实现
  3. 实现了 SpringCache 的扩展, 以及 mybatis/hibernate/session/springboot 的适配

解读

J2Cache与其说是一个缓存框架, 不如说它是一个缓存纽带, 它自己是没有实现任何缓存能力的, 它最主要的作用就是通过 JGroup/MQ 等方式实现了各个实例间本地缓存的一致性问题, 所以具体一级缓存用什么实现, 二级缓存用什么实现, 都需要额外集成. 其次需要注意的是, 这个开源项目已经3年多没有维护了, 并且其中的依赖项也长期未更新, 想要拿来投入生产使用还是有一些困难的
总的来说, J2Cache的初衷与我们目前的需求相同, 是为了实现实例间缓存数据一致性而产生, 不过该项目已经长期不维护, 如果需要拿来使用, 必然需要进行一番二开与优化
 

EhCache

EhCache是一个轻量级开源的缓存框架, Hibernate使用的默认缓存框架就是EhCache, 它支持多种缓存模型, 将缓存管理在 堆内 / 堆外 / 磁盘 / 远程 多地.
https://github.com/ehcache/ehcache3

特性

  1. 实现了JSR107的规范, 并支持无缝集成 SpringCache/Hibernate/Tomcat等
  2. 轻量级核心, 除slf4j外无其他依赖
  3. 支持 堆内内存 / 堆外内存 / 磁盘 / 远程缓存服务 三层存储
  4. 支持多种缓存模型: 独立缓存 / 分布式缓存 / 复制式缓存 , 具体描述如下:
    1. 独立缓存: 每个应用实例在本地维护缓存, 意味着在其中一个实例中修改了缓存, 会导致与其他实例的缓存信息不一致
    2. 分布式缓存: 每个应用实例本地维护少量热点缓存, 并有一个远程缓存服务端来管理更多的缓存信息, 本地缓存未命中时则请求远程服务获取缓存信息, 这解决了缓存空间的问题, 但也无法保证实例间的本地缓存一致性
  1. 复制式缓存: 通过引入第三方事件通知机制(rmi/jgroup/jms等), 来同步各个实例间的本地缓存(包含内存/硬盘), 这意味着每个实例都需要维护一份完整的缓存数据在内存/硬盘中, 开销不小, 并且大数据量下的频繁变更也容易导致各实例间的数据不致性

解读

EhCache是一个非常老牌的缓存框架了, 它可以说是缓存全家桶, 从本地内存缓存到硬盘缓存到远程缓存服务一整套全部自己实现, 与其说他是一个框架, 他更像是一个企业级应用缓存解决方案以及实现, 但是查看其官方网站, 便被EhCache的庞大体系所震惊.
总的来说, 虽然EhCache核心包极度轻量, 但过于复杂的配置与使用方式项使得在项目开发中难以灵活运用, 况且其大部分功能在实际开发场景中难有用武之地, 如缓存落盘等
 

JetCache

JetCache 是阿里开源的通用缓存访问框架, 它统一了多级缓存的访问方式, 封装了类似于SpringCache的注解, 以及GuavaCache类似的Builder, 来简化项目中使用缓存的难度
https://github.com/alibaba/jetcache/blob/master/introduce_CN.md

特性

  1. 提供统一的, 类似jsr-107风格的API访问Cache, 并可通过注解创建并配置Cache实例
  2. 提供类似SpringCache风格的注解, 实现声明式的方法缓存, 并支持TTL和两级缓存
  3. 支持缓存自动刷新与家在保护, 防止高并发下缓存未命中时打爆数据库
  4. 支持缓存的统计指标

解读

我认为JetCache的定位与SpringCache类似, 它没有去实现具体的缓存实现, 而是对现有的缓存框架进行抽象, 并提供统一的访问入口, 而且JetCache提供了比SpringCache更强大的接口缓存注解, 除此之外, 还提供了CacheBuilder / 缓存对象注解, 可以说将开发过程中所有使用缓存的场景都覆盖到了, 属于开发效率型框架
总的来说, JetCache不是缓存实现, 而是可以用来在现有缓存框架基础上简化使用的工具, 甚至可以与SpringCache一起使用, 是一个值得尝试的框架
posted @ 2021-12-15 21:16  EEEEET  阅读(7262)  评论(0编辑  收藏  举报