Redis 缓存异常、应对策略

Redis 缓存异常、应对策略
最新回答
知海無涯

2021-05-01 22:04:36

Redis 缓存异常主要包括缓存和数据库不一致、雪崩、击穿、穿透四种情况,以下是具体异常及应对策略:

缓存和数据库不一致
  • 问题描述:包含两种情况,一是缓存中有数据且与数据库中的值相同,二是缓存中没有数据,最新值在数据库中。读写缓存若要保证数据一致,需采用同步直写策略并结合事务机制保证更新原子性;对数据一致性要求不高的场景,可使用异步写回策略。只读缓存在新增数据时符合第二种情况,但在删改数据时,无论操作缓存还是数据库,只要有一项失败,就会产生数据不一致问题。此外,大量并发请求时,应用可能读到不一致数据,根据删改缓存、数据库的先后顺序,分为先操作缓存和先操作数据库两种情况。
  • 应对策略

    操作失败导致的不一致:引入重试机制,将数据暂存到消息队列中。无论哪项操作失败,都从消息队列中重新读取这些值,再次进行删除或更新。若删改成功,则把数据从消息队列中去除,避免重复操作;多次重试仍然失败,需业务层面预警排查解决。

    并发请求导致的不一致:采用“延迟双删”操作保证先操作缓存后操作数据库的数据一致性。代码示意如下:

redis.delKey(X)db.update(X)Thread.sleep(N)redis.delKey(X)
  • 具体情况与应对措施总结

雪崩
  • 问题描述:指大量应用请求无法在 Redis 缓存中处理,到达数据库层面,导致数据库压力激增。原因主要有两个,一是缓存中有大量数据同时过期,二是 Redis 缓存实例挂了。
  • 应对策略

    大量数据同时过期

    微调过期时间:对于同一批数据设置不同的过期时间,如通过随机数延迟过期等。

    降级处理:非核心数据请求直接返回空或错误等预置信息,核心数据在未命中缓存时访问数据库。

    Redis 缓存实例挂了

    熔断:拒绝缓存客户端的请求,保护数据库,防止整个系统崩溃,直到 Redis 缓存实例恢复正常。但此方法对业务应用的影响范围大。

    限流:允许部分请求到达 Redis 缓存,无法命中再访问数据库,减轻数据库压力。相对于熔断,影响范围稍微缩小。

    预防措施:构建 Redis 缓存高可靠集群,尽量避免事故发生。

击穿
  • 问题描述:指针对某个热点数据的请求,无法在缓存中处理,大量访问该数据的请求发送到后端数据库,导致数据库压力激增并影响其他请求。

  • 应对策略:对于访问特别频繁的热点数据,不设置过期时间,全部在缓存中进行处理。
穿透
  • 问题描述:指要访问的数据既不在 Redis 缓存中,也不在数据库中,导致请求压力落到数据库,缓存失去作用。通常是由于业务数据被误删除或恶意攻击访问导致。

  • 应对策略

    缓存空值或缺省值:针对穿透的数据,在 Redis 中缓存一个空值或是和业务层协商确定的缺省值,避免大量请求发送给数据库。

    布隆过滤器:由一个初值都为 0 的 bit 数组和 N 个哈希函数组成。数据入库时进行标记,过程如下:

    使用 N 个哈希函数,分别计算这个数据的哈希值,得到 N 个哈希值。

    把这 N 个哈希值对 bit 数组的长度取模,得到每个哈希值在数组中的对应位置。

    把对应位置的 bit 位设置为 1,完成在布隆过滤器中标记数据的操作。当查询某个数据时,按照哈希函数的计算结果,查看 bit 数组中这 N 个位置上的 bit 值,只要有一个不为 1,就表明布隆过滤器没有对该数据做过标记。当缓存穿透发生时,布隆过滤器的快速检测特性可以帮数据库阻挡大部分压力。

    前端请求过滤:在请求入口前端进行合法性检测,把恶意的请求(如请求参数不合理、非法值或请求字段不存在)直接过滤掉。

预防式方案总结
  • 雪崩:合理地设置数据过期时间,以及搭建高可靠缓存集群。
  • 击穿:在缓存访问非常频繁的热点数据时,不要设置过期时间。
  • 穿透:提前在入口前端实现恶意请求检测,或者规范数据库的数据删除操作,避免误删除。