各缓存的特性对比
本文仅针对在 Java 开发中,常用的缓存方案进行对比,并整理阅读到的、较有帮助的博文。
本文不对缓存的基本作用、各缓存的使用、部署方式进行说明。
文章后部分给出了 Spring 中,多级缓存的一种实现思路,欢迎参考!
存储方式 | 分布式 | 部署方式 | 特点/适用场景 | |
---|---|---|---|---|
内存 | JVM 内存 | × | JDK自带 | 这里指 ConcurrentHashMap。需要手动管理缓存。缓存使用场景较简单的场景。 |
Caffeine | JVM 内存 | × | jar 包 | 采用比 Guava 更优的算法,显著提升读写性能、命中率。据说是新时代的本地缓存,对 Guava API 有良好的支持 |
Guava | JVM 内存 | × | jar 包 | 由 Google 提供。类似 ConcurrentHashMap 的实现,但提供了更多 API,更灵活的失效、回收策略。 |
Ehcache | JVM 内存+磁盘 | 支持 | jar 包 | 使用分布式时,支持同步、共享比较麻烦,通常用于单机,单机时性能很好 |
memcached | 内存 | 客户端实现 | 独立部署 | 无持久化,值只支持 String,适合频繁读、较少修改的场景,对大 Value 支持友好 |
redis | 内存+磁盘 | 支持 | 独立部署 | 对集群方案、分布式部署有完善的支持;对持久化、容灾有完善的方案;性能很优秀,并支持复杂的 KV 类型存储 |
levelDB | 存储引擎(内存+磁盘) | 作为存储引擎提供支持 | jar 包 | 由 Google 提供。轻量存储引擎,提供缓存操作 API,可以理解为简化的 RocksDB (TiDB 的底层实现),但是仅引入 levelDB 时,不支持分布式 |
上述缓存均开源,且社区都很活跃
主要参考(重点)
本地缓存的进化
部分缓存的比较
- Caffeine高性能设计剖析
- 缓存那些事:介绍了几种常见缓存的使用场景。
- memcached 的分布式缓存介绍了 memcached 如何实现分布式缓存,一致性算法。
- 既生 Redis 何生 LevelDB ?主要讲解了 Redis 的痛点,LevelDB 提出的解决,以及 LevelDB 的地位
在 Springboot 中,建立并使用多级缓存
这里给出一种设计方案,仅供参考。
也可用作 Spring 自动配置与缓存实现参考
实现效果
通过配置文件调整缓存各层的关系,仅需编写缓存实现部分代码,编写统一的注入方法即可完成自动装配,由 Spring 容器管理多级缓存。
配置文件:
cache:
layers:
# 越靠上的越接近 DB,编号越小
- redis
- guava
业务(单测)代码:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = XxxApplication.class)
public class MultiStringCacheTest {
// 这个是最终实现的多级缓存对外接口的 Bean
// 配置正确后,注入后,直接使用对应接口即可
@Autowired
private MultiStringCache multiStringCache;
@Test
public void setTest() {
// 基本的设置、读取接口测试
String key1 = "key1";
String val1 = "val1";
multiStringCache.set(key1, val1);
Assert.assertEquals(multiStringCache.getCache(key1), val1);
}
}
设计、原理
-
缓存层级设计
- 由 MultiStringCache 统一管理各级缓存,为方便管理,这里要求每一层缓存都必须是 AbstractStringCacheLayer 的子类
- CacheLayer 规定了缓存层的基本接口
- AbstractStringCacheLayer 对 CacheLayer 部分方法进行了简单实现,并提供了针对对象与 Json 互转的方法,拓展了非 String 值类型的支持。
- RedisCacheLayer, GuavaCacheLayer 是缓存层的具体实现。
-
配置方式设计
- 由 MultiCacheProperties 读取配置文件中缓存相关的配置信息
- 由 MultiCacheConfiguration 对配置进行解释,通过内部类,使用反射调用工厂方法将各层缓存的 Bean 注册到 Spring 容器,最后将 MultiStringCache 的 Bean 注册到容器。
- CacheLayerBuilder 提供各层缓存构造的工厂方法,根据对应前缀构造指定的缓存层。
-
使用方法
- 复用图中除 RedisCacheLayer, GuavaCacheLayer 的全部类。
- 按照业务需要,编写自己的缓存层;缓存层必须继承 AbstractStringCacheLayer 方法。
- 按照上文配置文件中描述的方式进行配置。
- 在业务代码中直接使用(自动注入),提供的接口可以参考代码,有必要的注释,可以自行拓展。
完整代码样例
注意,该样例中提供的实现属于 demo,仅在单元测试的若干个测试用例中实现了二级缓存的全部特性,仅供参考学习。
样例代码:file-case: 多级缓存实现部分
该项目近期可能会继续更新,如果链接失效,可以留言提醒更新。