Featured image of post Redis 缓存问题

Redis 缓存问题

🌨️ 缓存雪崩

为了保证缓存中数据与数据库中的数据的一致性,通常 Redis 中数据会设置过期时间。如果(1)缓存层在同一时间有大量数据失效,或者 (2)Redis 由于某些情况宕机,导致所有请求全部访问数据库,造成数据库宕机。

💡 解决办法:

  • 🧩 给数据随机设置过期时间

  • 🧩 互斥锁,只有一个请求会到数据库上,并会重建缓存

  • 🧩 双 Key 策略,有不同的 Key,但有相同的 Value

    • 主 Key:设置过期时间
    • 备 Key:不设置过期时间
    • 当主 Key 过期后,大量请求到达时直接返回备 Key,并通知后台线程,重建主 Key
  • 🧩 设置 Key 永不过期,后台更新缓存(内存不够时可能被内存淘汰策略淘汰)

    • 后台线程定时更新 或 定时检测是否失效,进行重建
    • 业务上发现被淘汰,通过消息队列通知重建

⚡ 缓存击穿

缓存中某个热点 Key 数据过期了,此时有大量请求访问该数据,导这些请求全部都落到了数据库上,导致数据库宕机。

💡 解决办法:

  • 🧩 互斥锁,只有一个请求会到数据库上,并重建缓存

  • 🧩 热点数据永不过期(内存不够时可能被内存淘汰策略淘汰),后台线程更新缓存

🌪️ 缓存穿透

请求的数据既不存在于缓存中,也不存在于数据库中,有大量这样的请求,不会命中缓存,直接访问数据库,导致数据库压力非常大。

可能是由于(1)业务误操作 或 (2)黑客的故意攻击

💡 解决办法:

  • 🧩 缓存默认值,后续的请求直接返回该默认值

  • 🧩 布隆过滤器,当布隆过滤器返回 0 时,说明数据一定不在数据库中

  • 🧩 非法请求限制,在业务层判断查询条件,如果是恶意请求直接拒绝

🔥 热点 Key 重建

当热点缓存失效的瞬间,后端会有大量请求,在重建缓存时,会造成后端负载过大,导致应用崩溃。

  • 💡 使用互斥锁

    • 只允许一个线程重建缓存,其他线程等待重建缓存的线程执行完,才能从缓存获取数据
  • 💡 Key 永不过期

    • 利用后台线程去单独构建缓存

🎏 缓存一致性

更新

❌ 先更新数据库,再更新缓存

❌ 先更新缓存,再更新数据库

删除

❓ 先删除缓存,再更新数据库

可以考虑延迟双删。在更新完数据库后,延迟一段时间再删除一次缓存。

⭕ 先更新数据库,再删除缓存

在实际中,出现的概率非常低。缓存的写入要远远快于数据库的写入。

异步

通过 更新 + 删除,是两个不同的操作,不具备原子性,可能会导致不一致的问题。

  • 中间件

通过中间件(如 Canal -> https://github.com/alibaba/canal )订阅数据库的 binlog,当更新完数据库时,通过中间件去删除缓存。

📕 参考

Licensed under CC BY-NC-SA 4.0