redis-缓存
0 目录

1 什么是缓存
缓存就是数据交换的缓冲区(称作Cache),是存储数据的临时地方,一般读写性能较高
1.1 作用
- 降低后端负载
- 提高读写效率,降低响应时间
1.2 成本
- 数据一致性成本
- 代码维护成本
- 运维成本
2 添加Redis缓存

- 即:在客户端和数据库之间加一层redis,这样就可以减轻数据库的压力。
3 缓存更新策略

3.1 具体业务场景
低一致性需求:使用内存淘汰机制。例如店铺类型的查询缓存
高一致性需求:主动更新,并以超时剔除作为兜底方案。例如店铺详情查询的缓存
3.2 主动更新策略
即:由缓存调用者在更新数据库的同时更新缓存。
3.2.1 注意点
- 删除还是更新缓存?
- 更新缓存:每次更新都更新缓存,无效写操作较多
- 删除缓存:更新数据库时让缓存失效,查询时再更新缓存(胜出)
- 如何保证缓存和数据库的操作的同时成功或失败?
- 更新缓存:每次更新都更新缓存,无效写操作较多
- 删除缓存:更新数据库时让缓存失效,查询时再更新缓存(胜出)
- 先操作缓存还是先操作数据库?
- 先操作数据库再删缓存,因为出现数据不一致的前提:1. 刚好缓存失效;2. 另一个线程写入时间在前一个线程查询数据库到写入缓存的几短时间内进行了更新操作
- 读操作:
- 缓存命中就返回
- 缓存没有命中查数据库,写入缓存同时设定超时时间
- 写操作:
- 先写数据库再删缓存
- 确保数据库和缓存操作的原子性
3.3 实现缓存和数据库的双写一致
在单体系统中,更新方法使用@Transactional对方法进行标记
4 缓存穿透
缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库

4.1 解决
缓存null值
布隆过滤
增强id的复杂度,避免被猜测id规律
做好数据的基础格式校验
加强用户权限校验
做好热点参数的限流
4.1.1 空值解决

步骤
- 当缓存没有命中的时候,查询数据库
- 判断数据库的数据是否存在
- 存在:将数据写入缓存同时返回
- 不存在:写入空值到缓存
1 | |
5 缓存雪崩
缓存雪崩是指同一时刻大量的缓存key同时失效或者redis服务宕机,导致大量请求到达数据库,带来巨大压力
5.1 解决
给不同的Key的TTL添加随机值
利用Redis集群提高服务的可用性
给缓存业务添加降级限流策略
给业务添加多级缓存
6 缓存击穿
缓存击穿问题也叫热点Key问题,就是一个被高并发访问并且缓存重建业务较复杂的key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击。

6.1 解决
前言:涉及到互斥锁,使用redis的一个命令:setnx
6.1.1 互斥锁解决

即:当第一个线程查询缓存的时候,没有实现命中,此时第一个线程开始获取互斥锁,当锁获取成功之后,开始查询数据库进行缓存的重建,查询完成之后写入缓存,最后释放锁

1 | |
6.1.2 逻辑过期解决
- 热点key需要先进行预热,将相关数据先放入缓存中,设定的过期时间不是redis的TTL,而是一个逻辑上认定会过期的时间

即:当缓存命中的时候,判断设定的缓存逻辑时间是否过期,如果没有,那么就直接返回数据信息;如果过期了,先尝试获取互斥锁,当获取到锁,如果获取锁失败了,将旧数据返回即可;如果获取锁成功,那么开启一个独立的线程进行查询数据库,写入缓存,以及设定逻辑过期时间,最后释放互斥锁。

1 | |
7 缓存工具类
需要满足以下4个要求:
- 任意Java对象序列化为json并存储在string类型的key中,并且可以设置TTL过期时间
- 将任意Java对象序列化为json并存储在string类型的key中,并且可以设置逻辑过期时间,用于处理缓存击穿问题
- 根据指定的key查询缓存,并反序列化为指定类型,利用缓存空值的方式解决缓存穿透问题
- 根据指定的key查询缓存,并反序列化为指定类型,需要利用逻辑过期解决缓存击穿问题
1 | |
redis-缓存
https://baijianglai.cn/redis-缓存/22e726666a0f/