为什么多级缓存

缓存的引入是现在大部分系统所必须考虑的

  • redis 作为常用中间件,虽然我们一般业务系统(毕竟业务量有限)不会遇到如下图 在随着 data-size 的增大和数据结构的复杂的造成性能下降,但网络 IO 消耗会成为整个调用链路中不可忽视的部分。尤其在 微服务架构中,一次调用往往会涉及多次调用 例如pig oauth2.0 的 client 认证

  • Caffeine 来自未来的本地内存缓存,性能比如常见的内存缓存实现性能高出不少详细对比

综合所述:我们需要构建 L1 Caffeine JVM 级别缓存 , L2 Redis 缓存。

设计难点

目前大部分应用缓存都是基于 Spring Cache 实现,基于注解(annotation)的缓存(cache)技术,存在的问题如下:

  • Spring Cache 仅支持 单一的缓存来源,即:只能选择 Redis 实现或者 Caffeine 实现,并不能同时使用。
  • 数据一致性:各层缓存之间的数据一致性问题,如应用层缓存和分布式缓存之前的数据一致性问题。
  • 缓存过期:Spring Cache 不支持主动的过期策略

业务流程

如何使用

    1. 引入依赖
<dependency>
<groupId>com.pig4cloud.plugin</groupId>
<artifactId>multilevel-cache-spring-boot-starter</artifactId>
<version>0.0.1</version>
</dependency>
    1. 开启缓存支持
@EnableCaching
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
    1. 目标接口声明 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

代码原理

    1. 自定义 CacheManager 多级缓存实现
public class RedisCaffeineCacheManager implements CacheManager {

	@Override
public Cache getCache(String name) {
Cache cache = cacheMap.get(name);
if (cache != null) {
return cache;
}
cache = new RedisCaffeineCache(name, stringKeyRedisTemplate, caffeineCache(), cacheConfigProperties);
Cache oldCache = cacheMap.putIfAbsent(name, cache);
log.debug("create cache instance, the cache name is : {}", name);
return oldCache == null ? cache : oldCache;
}
}
    1. 多级读取、过期策略实现
public class RedisCaffeineCache extends AbstractValueAdaptingCache {
protected Object lookup(Object key) {
Object cacheKey = getKey(key); // 1. 先调用 caffeine 查询是否存在指定的值
Object value = caffeineCache.getIfPresent(key);
if (value != null) {
log.debug("get cache from caffeine, the key is : {}", cacheKey);
return value;
} // 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);
}
return value;
}
}
    1. 过期策略,所有更新操作都基于 redis pub/sub 消息机制更新
public class RedisCaffeineCache extends AbstractValueAdaptingCache {
@Override
public void put(Object key, Object value) {
push(new CacheMessage(this.name, key));
} @Override
public ValueWrapper putIfAbsent(Object key, Object value) {
push(new CacheMessage(this.name, key));
} @Override
public void evict(Object key) {
push(new CacheMessage(this.name, key));
} @Override
public void clear() {
push(new CacheMessage(this.name, null));
} private void push(CacheMessage message) {
stringKeyRedisTemplate.convertAndSend(topic, message);
}
}
    1. MessageListener 删除指定 Caffeine 的指定值
public class CacheMessageListener implements MessageListener {

	private final RedisTemplate<Object, Object> redisTemplate;

	private final RedisCaffeineCacheManager redisCaffeineCacheManager;

	@Override
public void onMessage(Message message, byte[] pattern) {
CacheMessage cacheMessage = (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

https://gitee.com/log4j/pig

项目推荐: Spring Cloud 、Spring Security OAuth2的RBAC权限管理系统 欢迎关注

「性能提升」扩展 Spring Cache 支持多级缓存的更多相关文章

  1. 【开源项目系列】如何基于 Spring Cache 实现多级缓存(同时整合本地缓存 Ehcache 和分布式缓存 Redis)

    一.缓存 当系统的并发量上来了,如果我们频繁地去访问数据库,那么会使数据库的压力不断增大,在高峰时甚至可以出现数据库崩溃的现象.所以一般我们会使用缓存来解决这个数据库并发访问问题,用户访问进来,会先从 ...

  2. 基于Spring Cache实现二级缓存(Caffeine+Redis)

    一.聊聊什么是硬编码使用缓存? 在学习Spring Cache之前,笔者经常会硬编码的方式使用缓存. 我们来举个实际中的例子,为了提升用户信息的查询效率,我们对用户信息使用了缓存,示例代码如下: @A ...

  3. 【Spring】17、spring cache 与redis缓存整合

    spring cache,基本能够满足一般应用对缓存的需求,但现实总是很复杂,当你的用户量上去或者性能跟不上,总需要进行扩展,这个时候你或许对其提供的内存缓存不满意了,因为其不支持高可用性,也不具备持 ...

  4. 品味Spring Cache设计之美

    最近负责教育类产品的架构工作,两位研发同学建议:"团队封装的Redis客户端可否适配Spring Cache,这样加缓存就会方便多了" . 于是边查阅文档边实战,收获颇丰,写这篇文 ...

  5. Spring 3.1新特性之三:Spring对声明式缓存的支持

    一.概述: Spring 3.1 引入了激动人心的基于注释(annotation)的缓存(cache)技术,它本质上不是一个具体的缓存实现方案(例如EHCache 或者 OSCache),而是一个对缓 ...

  6. Spring Boot中的缓存支持(一)注解配置与EhCache使用

    Spring Boot中的缓存支持(一)注解配置与EhCache使用 随着时间的积累,应用的使用用户不断增加,数据规模也越来越大,往往数据库查询操作会成为影响用户使用体验的瓶颈,此时使用缓存往往是解决 ...

  7. Spring Cache 带你飞(二)

    接着上一篇讲了 Spring Cache 如何被 Spring Aop 代理加载对应的代码,以及何如注入相关界面逻辑. Spring Cache 带你飞(一) 本篇我们围绕两个要点展开: 一个数据是如 ...

  8. Spring Cache抽象详解

    缓存简介 缓存,我的理解是:让数据更接近于使用者:工作机制是:先从缓存中读取数据,如果没有再从慢速设备上读取实际数据(数据也会存入缓存):缓存什么:那些经常读取且不经常修改的数据/那些昂贵(CPU/I ...

  9. 基于Redis的Spring cache 缓存介绍

    目录 Cache API及默认提供的实现 demo 依赖包安装 定义实体类.服务类和相关配置文件 Cache注解 启用Cache注解 @CachePut @CacheEvict @Cacheable ...

随机推荐

  1. React 函数式组件的 Ref 和子组件访问(useImperativeHandle)

    引入:如何调用函数式组件内部的方法 对于 React 中需要强制修改子组件的情况,React 提供了 Refs 这种解决办法,使得我们可以操作底层 DOM 元素或者自定的 class 组件实例.除此之 ...

  2. Python算法_爬楼梯(08)

    假设你正在爬楼梯.需要 n 阶你才能到达楼顶. 每次你可以爬 1 或 2 个台阶.你有多少种不同的方法可以爬到楼顶呢? 注意:给定 n 是一个正整数. 示例 1: 输入: 2输出: 2解释: 有两种方 ...

  3. Python算法_整数反转(02)

    给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转. 示例 1: 输入: 123输出: 321 示例 2: 输入: -123输出: -321 示例 3: 输入: 120 输出: 2 ...

  4. 别再人云亦云了!!!你真的搞懂了RDD、DF、DS的区别吗?

    几年前,包括最近,我看了各种书籍.教程.官网.但是真正能够把RDD.DataFrame.DataSet解释得清楚一点的.论据多一点少之又少,甚至有的人号称Spark专家,但在这一块根本说不清楚.还有国 ...

  5. 解决java POI导入Excel超时问题

    由于要导入大量数据,后台会耗费很长时间,导致超时. 本项目前端request.js中设定的超时时间为150s. const service = axios.create({ baseURL: base ...

  6. oracle 导入导出dmp

    exp 用户名/密码@地址:端口/serviceName file=D:\710.dmp exp test710/test710@192.168.15.134:1521/doit file=D:\71 ...

  7. MySQL全面瓦解23:MySQL索引实现和使用

    MySQL索引实现 上一篇我们详细了解了B+树的实现原理(传送门).我们知道,MySQL内部索引是由不同的引擎实现的,主要包含InnoDB和MyISAM这两种,并且这两种引擎中的索引都是使用b+树的结 ...

  8. WPF -- 一种圆形识别方案

    本文介绍一种圆形的识别方案. 识别流程 判断是否为封闭图形: 根据圆的方程,取输入点集中的1/6.3/6.5/6处的三个点,求得圆的方程,获取圆心及半径: 取点集中的部分点,计算点到圆心的距离与半径的 ...

  9. LeetCode-133克隆图(图的遍历+深拷贝概念)

    克隆图 LeetCode-133 使用一个map来存储已经遍历的结点,这个存起来的结点必须是新new的才符合题意 /* // Definition for a Node. class Node { p ...

  10. AI在出行场景的应用实践:路线规划、ETA、动态事件挖掘…

    ​前言:又到春招季!作为国民级出行服务平台,高德业务快速发展,大量校招/社招名额开放,欢迎大家投递简历,详情见文末.为帮助大家更了解高德技术,我们策划了#春招专栏#的系列文章,组织各业务团队的高年级同 ...