- Notifications
You must be signed in to change notification settings - Fork109
pig-mesh/multilevel-cache-spring-boot-starter
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
缓存的引入是现在大部分系统所必须考虑的
- redis 作为常用中间件,虽然我们一般业务系统(毕竟业务量有限)不会遇到如下图 在随着 data-size 的增大和数据结构的复杂的造成性能下降,但网络 IO 消耗会成为整个调用链路中不可忽视的部分。尤其在 微服务架构中,一次调用往往会涉及多次调用 例如pig oauth2.0 的 client 认证
- Caffeine 来自未来的本地内存缓存,性能比如常见的内存缓存实现性能高出不少详细对比。
综合所述:我们需要构建 L1 Caffeine JVM 级别内存 , L2 Redis 内存。
目前大部分应用缓存都是基于 Spring Cache 实现,基于注释(annotation)的缓存(cache)技术,存在的问题如下:
- Spring Cache 仅支持 单一的缓存来源,即:只能选择 Redis 实现或者 Caffeine 实现,并不能同时使用。
- 数据一致性:各层缓存之间的数据一致性问题,如应用层缓存和分布式缓存之前的数据一致性问题。
- 缓存过期:Spring Cache 不支持主动的过期策略
| 版本 | 支持 |
|---|---|
| 3.0.0 | 适配 SpringBoot3.x |
| 1.0.1 | 适配 SpringBoot2.x |
- 引入依赖
<dependency> <groupId>com.pig4cloud.plugin</groupId> <artifactId>multilevel-cache-spring-boot-starter</artifactId> <version>${lastVersion}</version></dependency>
- 开启缓存支持
@EnableCachingpublicclassApp {publicstaticvoidmain(String[]args) {SpringApplication.run(App.class,args);}}
- 目标接口声明 Spring Cache 注解
@Cacheable(value = "get",key = "#key")@GetMapping("/get")public String get(String key){ return "success";}为保证性能 redis 在 127.0.0.1 环路安装
- OS: macOS Mojave
- CPU: 2.3 GHz Intel Core i5
- RAM: 8 GB 2133 MHz LPDDR3
- JVM: corretto_11.jdk
| Benchmark | Mode | Cnt | Score | Units |
|---|---|---|---|---|
| 多级实现 | thrpt | 2 | 2716.074 | ops/s |
| 默认 redis | thrpt | 2 | 1373.476 | ops/s |
- 自定义 CacheManager 多级缓存实现
publicclassRedisCaffeineCacheManagerimplementsCacheManager {@OverridepublicCachegetCache(Stringname) {Cachecache =cacheMap.get(name);if (cache !=null) {returncache;}cache =newRedisCaffeineCache(name,stringKeyRedisTemplate,caffeineCache(),cacheConfigProperties);CacheoldCache =cacheMap.putIfAbsent(name,cache);log.debug("create cache instance, the cache name is : {}",name);returnoldCache ==null ?cache :oldCache;}}
- 多级读取、过期策略实现
publicclassRedisCaffeineCacheextendsAbstractValueAdaptingCache {protectedObjectlookup(Objectkey) {ObjectcacheKey =getKey(key);// 1. 先调用 caffeine 查询是否存在指定的值Objectvalue =caffeineCache.getIfPresent(key);if (value !=null) {log.debug("get cache from caffeine, the key is : {}",cacheKey);returnvalue;}// 2. 调用 redis 查询在指定的值value =stringKeyRedisTemplate.opsForValue().get(cacheKey);if (value !=null) {log.debug("get cache from redis and put in caffeine, the key is : {}",cacheKey);caffeineCache.put(key,value);}returnvalue;}}
- 过期策略,所有更新操作都基于 redis pub/sub 消息机制更新
publicclassRedisCaffeineCacheextendsAbstractValueAdaptingCache {@Overridepublicvoidput(Objectkey,Objectvalue) {push(newCacheMessage(this.name,key));}@OverridepublicValueWrapperputIfAbsent(Objectkey,Objectvalue) {push(newCacheMessage(this.name,key));}@Overridepublicvoidevict(Objectkey) {push(newCacheMessage(this.name,key));}@Overridepublicvoidclear() {push(newCacheMessage(this.name,null));}privatevoidpush(CacheMessagemessage) {stringKeyRedisTemplate.convertAndSend(topic,message);}}
- MessageListener 删除指定 Caffeine 的指定值
publicclassCacheMessageListenerimplementsMessageListener {privatefinalRedisTemplate<Object,Object>redisTemplate;privatefinalRedisCaffeineCacheManagerredisCaffeineCacheManager;@OverridepublicvoidonMessage(Messagemessage,byte[]pattern) {CacheMessagecacheMessage = (CacheMessage)redisTemplate.getValueSerializer().deserialize(message.getBody());cacheMessage.getCacheName(),cacheMessage.getKey());redisCaffeineCacheManager.clearLocal(cacheMessage.getCacheName(),cacheMessage.getKey());}}
https://github.com/pig-mesh/multilevel-cache-spring-boot-starter
About
spring cache 多级缓存扩展
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Contributors6
Uh oh!
There was an error while loading.Please reload this page.


