Redis 缓存问题
Redis 缓存问题
缓存穿透
问题描述
缓存穿透指:
当请求传递到后端服务器时,会先查询Redis 缓存中是否存在该 key 值,不存在,则会请求db 去查询。
当发生程序被攻击时,出现大量空值的key 会去请求,以拖垮服务器查询,导致程序崩溃。
解决方法
- 缓存空值
- 布隆过滤器(key 校验)
缓存空值
将数据库中查询为空的key 也存储在缓存中,当再次查询时,则可以避免查询数据库。
缓存空值会出现两个问题:
- 空值缓存,会占用更多空间,需要设置较短的过期时间。(若是攻击,会很麻烦)
- 缓存和存储的数据会有一段时间不一致,有业务影响。
布隆过滤器
原理
利用 k 个哈希函数,对元素进行计算
根据哈希值,将位数据组对应的下标置为1
当需要查询时,重复过程
1
,若查询对应位数据下标不全为1,则不存在,全为1,则存在
优点:
数据空间小,不用存储数据本身
缺点:
- 元素可以添加到集合中,不能删除
- 匹配结果是“
绝对不在集合中
”,并不能保证匹配成功的值已经在集合中- 当集合快满时,即接近预估最大容量时,误报的概率会变大
- 数据占用空间放大
缓存击穿
问题描述
当单个热点key 的缓存数据,****刚好过了有效时间,此时大量请求涌入,会导致数据查询流量大增,数据库可能崩溃。
解决方法
- 互斥锁
- 热点数据永不过期
互斥锁
当第一个数据库查询请求发起后,就将缓存中该数据上锁;
此时其他查询该缓存的请求,被阻塞等待;
当第一个请求完成,然后更新缓存,释放锁;
其他查询请求后续可以查询到。
注意:互斥锁可以避免某一个热点,但实际情况里往往是一批。
将缓存的过期时间,设置为随机值,会降低这一概率。
热点数据永不过期
从缓存层面,确实没有设置过期时间,也就是物理不过期
从功能层面,每一个value 都有对应逻辑时间,过期后,单独重新构建。
注意:在重新构建期间,可能会出现数据不一致的情况。
比较:
- 互斥锁
- 存在死锁和阻塞风险
- 较好的降低后端负载,一致性比较好
- 永远不过期
- 数据不一致情况
- 代码复杂度会增大
缓存雪崩
问题描述
指缓存中大量的数据同时过期,导致大量请求在短时间内直接到达数据库,对数据库造成巨大压力。
解决方法
- 过期时间分散
- 缓存预热
- 限流降级
过期时间分撒
使用 expire 命令设置过期时间,引入随机过期时间机制
缓存预热
使用 CacheWarmer 等工具在系统启动前预热缓存
限流降级
使用限流算法控制访问数据库的请求速率,当缓存失效导致请求过多时,进行降级处理。
工具:
Hystrix
、Sentinel
等
参考文章
硬核 | Redis 布隆(Bloom Filter)过滤器原理与实战 - 知乎 (zhihu.com)