缓存一致性解决方案 @ systemime | 2021-11-19T12:49:20+08:00 | 3 分钟阅读 | 更新于 2021-11-19T12:49:20+08:00

MySQL主从集群与Redis缓存更新先后顺序,以及如何保证并发情况下Redis缓存被正确更新

最终一致性

记录一下主要解决方案

问题关键点在于数据库与缓存先更新谁?

对于数据读取以及缓存应用方案,通常是: 请求 -> 查缓存(命中返回) -> 查库(命中返回) -> 返回同时写缓存

所以实际有以下四种可能:

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

如果对缓存下手

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

数据库更新失败是要回滚的,意味着缓存也需要回滚,缓存维护工作是个问题,and,如果缓存中缓存的是程序运行结果,回滚将增加负担

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

这是主要是 脏数据 的问题, 可能存在以下时序:

数据库中此时有数据D1,缓存有R1

进程A -> 删除缓存R1 ->                                                 D1更新为D2 -> 等待后续进程访问重新读取D2,并设置缓存R1 = D2
                     进程B —> 读取R1失败 -> 读取DB得到D1 -> 设置缓存R1 = D1

此时,进程A更新的数据不会被写入缓存,缓存中仍然是脏数据

如果先对数据库下手

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

这是主要也是 脏数据 的问题, 可能存在以下时序:

进程A -> 更新DB,更新数据D1                                              -> 使用D1更新缓存R1
                         进程B -> 更新DB,更新数据D2 —> 使用D2更新缓存R1

此时,缓存中的结果还可信吗?缓存到了一个脏数据,缓存与库中记录不一致

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

这里有一个小概率情况,当select比update慢时,可能存在以下时序

缓存R1失效 -> 进程A查询DB,得到D1 ->               更新缓存R1 = D1
             进程B更新DB,D修改为D2 —> 删除缓存R1

还是 脏数据 问题

这里要注意如果针对高并发情况,热点数据失效防止同时过多请求打到DB,可以访问DB前加分布式锁只允许一个进程访问数据库 在其他进程拿到锁以后,先尝试获取缓存

总结

分析几种缓存与数据库更新删除先后顺序可能出现的情况,可以得到结论是我们应该先对数据库进行更新,其实在主从数据库中,进程一般写master节点、读slave节点,两个节点之间同步也存在延迟,Redis缓存更新的情况更加繁杂

目前主要有两种解决方案

  • 延迟双删
  • 订阅主从库之间同步的binglog日志

延迟双删

先更新数据库,再删除缓存的拓展方案,先将缓存删除,再更新数据库,等待n时间后,再删除缓存

但是等待时间一般根据系统实际情况按经验而定,仍然有可能出现问题

根据binlog日志进行缓存更新

写master成功情况下,master会将数据通过binlog同步到从库,此时可以使用中间件(如阿里的canal)去订阅binlog日志(通过单线程订阅保证订阅事件顺序),通过日志中最新的内容更新Redis

注:Redis如果更新失败,可以将消息放到消息队列重复执行

强一致性

加锁做互斥并且写数据库和写缓存搞成一个事务,over

日后探讨

© 2018 - 2022 systemime 的博客

Powered by Hugo with theme Dream.

---

avatar
关于我

systemime 的博客

记录一些生活与技术的事或思考

毕业于 🏫 山东科技大学泰山科技学院

目前职位为Python后端开发工程师

热爱代码,热爱开源

主要的技术栈是:

  • python
  • celery
  • django
  • shell
  • sql
  • go
  • nginx

爱好

  • 羽毛球
  • 编码
我的一些开源项目

计划或项目:

  • skill_test ➡️ 一个包含项目常用的django模板:常用脚本、单测方法、数据库连接池、异步请求池,restful风格的回调接口管理器 60%
  • Vbox ➡️ 一个基于k8s和docker的容器云平台,早期项目代码较简单 90%
  • YuQue-Assistant ➡️ 用于批量拉取语雀工作区文章,使用进程池+协程
  • 一个代理池 60%
  • simple_db_pool ➡️ 一个简单数据库连接池 100%
  • 一个电报消息转发脚本 90%
  • 使用flutter做一个app 计划中
  • 其他若干脚本(bilibili、微博图片视频下载、文件对比、图片颜色提取…)
其他

如果你喜欢我的博客、开源项目或者它们可以给你带来帮助,可以赏一杯咖啡 ☕ 给我。~

If you like my open source projects or they can help you. You can buy me a coffee ☕.~

PayPal

https://paypal.me/systemime

支付宝赞赏码

alipay

微信赞赏码

wechat

最好附加一下信息或者留言,方便我可以将捐助记录 📝 下来,十分感谢 🙏。

It is better to attach some information or leave a message so that I can record the donation 📝, thank you very much 🙏.