Redis 与 DB 更新一致性问题
缓存更新策略
1. 内存淘汰
- 说明:不用自己维护,利用 Redis 的内存淘汰机制,当内存不足时自动淘汰部分数据,下次查询时更新缓存
- 一致性:差
- 维护成本:无
2. 超时剔除
- 说明:给缓存数据添加 TTL 时间,到期后自动删除缓存,下次查询更新缓存
- 一致性:一般
- 维护成本:低
3. 主动更新
-
说明:编写业务逻辑,在修改数据库同时,更新缓存
-
一致性:好
-
维护成本:高
缓存更新策略 - 主动更新策略
- 缓存调用方更新数据库同时更新缓存
- 使用 Cannel 等中间件订阅 binlog 更新缓存
- 使用异步线程 / 消息队列异步更新缓存达到最终一致性
删除缓存 VS 更新缓存
- 更新缓存:每次更新数据时都更新缓存,无效写操作较多
- 删除缓存:更新数据库时删除缓存,查询时再更新缓存 - 推荐
缓存和 DB 写入顺序
- 先删除缓存,后更新数据库
- 延迟双删:更新完数据库值以后,先 sleep 一小段时间,再进行一次缓存删除操作。
- 先更新数据库,后删除缓存(推荐)
先删除缓存,再更新数据库
缓存击穿
什么是缓存击穿
缓存击穿问题也叫热点key问题,指的是一个被高并发访问并且缓存重建业务比较复杂的key失效后,大量的请求并发访问会在瞬间给数据库带来巨大的冲击
解决方案
- 设置热点 key 永不失效
- 逻辑过期:缓存重建完成前返回旧值,异步线程重建缓存
- 优点:线程无需等待,性能好
- 缺点:一致性较差、
- 互斥锁
- 优点:一致性强
- 缺点:线程需要等待,性能受影响
缓存穿透
什么是缓存穿透
缓存穿透是指要访问的数据既不在 Redis 缓存中,也不在数据库中,这样缓存永远都不会生效,如果应用持续有大量请求访问数据,就会给数据库带来巨大压力
发生缓存穿透的原因
- 业务层误操作:缓存中的数据和数据库中的数据被误删除,所以缓存和数据库中都没有数据。
- 恶意攻击:专门访问数据库中没有的数据。
解决方案
方案一:缓存空值或缺省值 + TTL 过期
- 优点:实现简单、维护方便
- 缺点:
- 额外的内存消耗
- 可能造成短期的不一致
方案二:使用布隆过滤器
布隆过滤器是如何工作
布隆过滤器由一个初值都为 0 的 bit 数组和 N 个哈希函数组成,可以用来快速判断某个数据是否存在。
当我们要把某个数据标记存在时(例如,数据已被写入数据库),布隆过滤器会通过三个操作完成标记:
- 使用 N 个哈希函数,分别计算这个数据的哈希值,得到 N 个哈希值。
- 把这 N 个哈希值对 bit 数组的长度取模,得到每个哈希值在数组中的对应位置。
- 把对应位置的 bit 位设置为 1,这就完成了在布隆过滤器中标记数据的操作。
当需要查询某个数据时,执行上述计算过程,先得到这个数据在 bit 数组中对应的 N 个位置。接着,查看 bit 数组中这 N 个位置上的 bit 值,只要这 N 个 bit 值有一个不为 1,这就表明布隆过滤器没有对该数据做过标记,所以,查询的数据一定不存在。
布隆过滤器的一些问题
- 布隆过滤器会有误判:由于采用固定bit的数组,使用多个哈希函数映射到多个bit上,有可能会导致两个不同的值都映射到相同的一组bit上。虽然有误判,但对于业务没有影响,无非就是还存在一些穿透而已,但整体上已经过滤了大多数无效穿透请求。
- 布隆过滤器误判率和空间使用的计算:误判本质是因为哈希冲突,降低误判的方法是增加哈希函数 + 扩大整个bit数组的长度,但增加哈希函数意味着影响性能,扩大数组长度意味着空间占用变大,所以使用布隆过滤器,需要在误判率和性能、空间作一个平衡,具体的误判率是有一个计算公式可以推导出来的(比较复杂)。但我们在使用开源的布隆过滤器时比较简单,通常会提供2个参数:预估存入的数据量大小、要求的误判率,输入这些参数后,布隆过滤器会有自动计算出最佳的哈希函数数量和数组占用的空间大小,直接使用即可。
- 布隆过滤器可以放在缓存和数据库的最前面:把Redis当作布隆过滤器时(4.0提供了布隆过滤器模块,4.0以下需要引入第三方库),当用户产生业务数据写入缓存和数据库后,同时也写入布隆过滤器,之后当用户访问自己的业务数据时,先检查布隆过滤器,如果过滤器不存在,就不需要查询缓存和数据库了,可以同时降低缓存和数据库的压力。
- Redis实现的布隆过滤器bigkey问题:Redis布隆过滤器是使用String类型实现的,存储的方式是一个bigkey,建议使用时单独部署一个实例,专门存放布隆过滤器的数据,不要和业务数据混用,否则在集群环境下,数据迁移时会导致Redis阻塞问题。
方案三:前端入口过滤掉非法流量
缓存雪崩
什么是缓存雪崩
缓存雪崩是指同一时间段大量的缓存同时失效或者 Redis 宕机,导致大量请求到达数据库,给数据库带来巨大压力
解决方案
-
给缓存数据的过期时间加上小的随机数,避免同时过期
-
构建 Redis 缓存高可靠集群,避免了由于缓存实例宕机而导致的缓存雪崩问题。
-
给缓存业务添加服务降级、服务熔断、请求限流等策略
参考
黑马程序员Redis入门到实战教程,全面透析redis底层原理+redis分布式锁+企业解决方案+redis实战
极客时间 - Redis 核心技术与实战