Java本地缓存技术选型(Guava Cache、Caffeine、EhCache)

前言对一个java开发者而言,提到缓存,第一反应就是Redis。利用这类缓存足以解决大多数的性能问题了,我们也要知道,这种属于remote cache(分布式缓存),应用的进程和缓存的进程通常分布在不同的服务器上,不同进程之间通过RPC或HTTP的方式通信。这种缓存的优点是缓存和应用服务解耦,支持大数据量的存储,缺点是数据要经过网络传输,性能上会有一定损耗。

与分布式缓存对应的是本地缓存,缓存的进程和应用进程是同一个,数据的读写都在一个进程内完成,这种方式的优点是没有网络开销,访问速度很快。缺点是受JVM内存的限制,不适合存放大数据。

本地缓存常用技术本地缓存和应用同属于一个进程,使用不当会影响服务稳定性,所以通常需要考虑更多的因素,例如容量限制、过期策略、淘汰策略、自动刷新等。常用的本地缓存方案有:

Guava CacheCaffeineEhCache基于Guava Cache实现本地缓存Guava是Google团队开源的一款 Java 核心增强库,包含集合、并发原语、缓存、IO、反射等工具箱,性能和稳定性上都有保障,应用十分广泛。Guava Cache支持很多特性:

支持最大容量限制支持两种过期删除策略(插入时间和访问时间)支持简单的统计功能基于LRU算法实现引入依赖

代码语言:javascript代码运行次数:0运行复制

com.google.guava

guava

18.0

​简单的示例:

代码语言:javascript代码运行次数:0运行复制public class GuavaCacheTest {

public static void main(String[] args) throws Exception {

//创建guava cache

Cache loadingCache = CacheBuilder.newBuilder()

//cache的初始容量

.initialCapacity(5)

//cache最大缓存数

.maximumSize(10)

//设置写缓存后n秒钟过期

.expireAfterWrite(17, TimeUnit.SECONDS)

//设置读写缓存后n秒钟过期,实际很少用到,类似于expireAfterWrite

//.expireAfterAccess(17, TimeUnit.SECONDS)

.build();

String key = "key";

// 往缓存写数据

loadingCache.put(key, "v");

// 获取value的值,如果key不存在,调用collable方法获取value值加载到key中再返回

String value = loadingCache.get(key, new Callable() {

@Override

public String call() throws Exception {

return getValueFromDB(key);

}

});

// 删除key

loadingCache.invalidate(key);

}

private static String getValueFromDB(String key) {

return "v";

}

}

​CaffeineCaffeine 是基于 JAVA 8 的高性能缓存库。并且在 Spring5 (Springboot 2.x) 后,Spring 官方放弃了 Guava,而使用了性能更优秀的 Caffeine 作为默认缓存组件。

代码语言:javascript代码运行次数:0运行复制

com.github.ben-manes.caffeine

caffeine

2.5.5

​使用Caffeine:

代码语言:javascript代码运行次数:0运行复制public class CaffeineCacheTest {

public static void main(String[] args) throws Exception {

//创建guava cache

Cache loadingCache = Caffeine.newBuilder()

//cache的初始容量

.initialCapacity(5)

//cache最大缓存数

.maximumSize(10)

//设置写缓存后n秒钟过期

.expireAfterWrite(17, TimeUnit.SECONDS)

//设置读写缓存后n秒钟过期,实际很少用到,类似于expireAfterWrite

//.expireAfterAccess(17, TimeUnit.SECONDS)

.build();

String key = "key";

// 往缓存写数据

loadingCache.put(key, "v");

// 获取value的值,如果key不存在,获取value后再返回

String value = loadingCache.get(key, CaffeineCacheTest::getValueFromDB);

// 删除key

loadingCache.invalidate(key);

}

private static String getValueFromDB(String key) {

return "v";

}

}

​相比Guava Cache来说,Caffeine无论从功能上和性能上都有明显优势。同时两者的API类似,使用Guava Cache的代码很容易可以切换到Caffeine,节省迁移成本。

EhCacheEhCache是一个纯Java的进程内缓存框架,具有快速、精干的特点。注意的这里的关键字进程,基于进程的缓存直觉告诉我们效率肯定要高一些,因为它直接在进程之内进行操作,但不同应用之间缓存的共享可能就会有问题。

EhCache是Hibernate中默认的CacheProvider,Spring Boot也对其进行了支持,Spring中提供的缓存抽象也支持对EhCache缓存框架的绑定,而且支持基于注解的方式来使用。因此,EhCache是一款被广泛使用的基于Java的高速缓存框架,使用起来也非常方便。

EhCache提供了多种缓存策略,主要分为内存和磁盘两级,是一款面向通用缓存、Java EE和轻量级容器的缓存框架。

代码语言:javascript代码运行次数:0运行复制

org.ehcache

ehcache

3.8.0

​使用EhCache

代码语言:javascript代码运行次数:0运行复制public class EncacheTest {

public static void main(String[] args) throws Exception {

// 声明一个cacheBuilder

CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()

.withCache("encacheInstance", CacheConfigurationBuilder

//声明一个容量为20的堆内缓存

.newCacheConfigurationBuilder(String.class,String.class, ResourcePoolsBuilder.heap(20)))

.build(true);

// 获取Cache实例

Cache myCache = cacheManager.getCache("encacheInstance", String.class, String.class);

// 写缓存

myCache.put("key","v");

// 读缓存

String value = myCache.get("key");

// 移除换粗

cacheManager.removeCache("myCache");

cacheManager.close();

}

}

​总结从易用性角度,Guava Cache、Caffeine和EhCache都有十分成熟的接入方案,使用简单。从功能性角度,Guava Cache和Caffeine功能类似,都是只支持堆内缓存,Encache相比功能更为丰富从性能上进行比较,Caffeine最优、GuavaCache次之,EhCache最差(下图是三者的性能对比结果)img总体来说,对于本地缓存的方案中,个人比较推荐Caffeine,性能上遥遥领先。真实的业务工程中,建议使用Caffeine作为本地缓存,另外使用Redis或者memcache作为分布式缓存,构造多级缓存体系,保证性能和可靠性。

Copyright © 2022 破界远征沙盒工坊 All Rights Reserved.