被 leeder 摆了一道,哭笑不得!

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 Tair(兼容Redis),内存型 2GB
简介: 大家好,我是小林。上一周我写一了篇,数据库和缓存双写一致性的文章「老板真爱画大饼!」,故事的主人公是程序员阿旺。当时只写了上半篇,看到很多小伙伴催更下篇,说来就来!

大家好,我是小林。

上一周我写一了篇,数据库和缓存双写一致性的文章「老板真爱画大饼!」,故事的主人公是程序员阿旺。

当时只写了上半篇,看到很多小伙伴催更下篇,说来就来!


前情回顾


上回程序员阿旺为了提升数据访问的性能,引入 Redis 作为 MySQL 缓存层,但是这件事情并不是那么简单,因为还要考虑 Redis 和 MySQL 双写一致性的问题。


阿旺经过一番周折,最终选用了「先更新数据库,再删缓存」的策略,原因是这个策略即使在并发读写时,也能最大程度保证数据一致性。


聪明的阿旺还搞了个兜底的方案,就是给缓存加上了过期时间。


本以为就这样不会在出现数据一致性的问题,结果将功能上线后,老板还是收到用户的投诉「说自己明明更新了数据,但是数据要过一段时间才生效」,客户接受不了。


老板转告给了阿旺,阿旺得知又有 Bug 就更慌了,立马就登录服务器去排查问题,查看日志后得知了原因。


「先更新数据库, 再删除缓存」其实是两个操作,这次客户投诉的问题就在于,在删除缓存(第二个操作)的时候失败了,导致缓存中的数据是旧值,而数据库是最新值


好在之前给缓存加上了过期时间,所以才会出现客户说的过一段时间才更新生效的现象,假设如果没有这个过期时间的兜底,那后续的请求读到的就会一直是缓存中的旧数据,这样问题就更大了。


所以新的问题来了,如何保证「先更新数据库 ,再删除缓存」这两个操作能执行成功?


阿旺分析出问题后,慌慌张张的向老板汇报了问题。老板知道事情后,又给了阿旺几天来解决这个问题,画饼的事情这次没有再提了。


  • 阿旺会用什么方式来解决这个问题呢?
  • 老板画的饼事情,能否兑现给阿旺呢?


如何保证两个操作都能执行成功?


这次用户的投诉是因为在删除缓存(第二个操作)的时候失败了,导致缓存还是旧值,而数据库是最新值,造成数据库和缓存数据不一致的问题,会对敏感业务造成影响。


举个例子,来说明下。应用要把数据 X 的值从 1 更新为 2,先成功更新了数据库,然后在 Redis 缓存中删除 X 的缓存,但是这个操作却失败了,这个时候数据库中 X 的新值为 2,Redis 中的 X 的缓存值为 1,出现了数据库和缓存数据不一致的问题。

4.png

那么,后续有访问数据 X 的请求,会先在 Redis 中查询,因为缓存并没有 诶删除,所以会缓存命中,但是读到的却是旧值 1。


其实不管是先操作数据库,还是先操作缓存,只要第二个操作失败都会出现数据一致的问题。


问题原因知道了,该怎么解决呢?有两种方法:

  • 重试机制。
  • 订阅 MySQL binlog,再操作缓存。


先来说第一种。


重试机制


我们可以引入消息队列,将第二个操作(删除缓存)要操作的数据加入到消息队列,由消费者来操作数据。

  • 如果应用删除缓存失败,可以从消息队列中重新读取数据,然后再次删除缓存,这个就是重试机制。当然,如果重试超过的一定次数,还是没有成功,我们就需要向业务层发送报错信息了。
  • 如果删除缓存成功,就要把数据从消息队列中移除,避免重复操作,否则就继续重试。

举个例子,来说明重试机制的过程。

3.png


订阅 MySQL binlog,再操作缓存


先更新数据库,再删缓存」的策略的第一步是更新数据库,那么更新数据库成功,就会产生一条变更日志,记录在 binlog 里。


于是我们就可以通过订阅 binlog 日志,拿到具体要操作的数据,然后再执行缓存删除,阿里巴巴开源的 Canal 中间件就是基于这个实现的。


Canal 模拟 MySQL 主从复制的交互协议,把自己伪装成一个 MySQL 的从节点,向 MySQL 主节点发送 dump 请求,MySQL 收到请求后,就会开始推送 Binlog 给 Canal,Canal 解析 Binlog 字节流之后,转换为便于读取的结构化数据,供下游程序订阅使用。


下图是 Canal 的工作原理:

2.png

所以,如果要想保证「先更新数据库,再删缓存」策略第二个操作能执行成功,我们可以使用「消息队列来重试缓存的删除」,或者「订阅 MySQL binlog 再操作缓存」,这两种方法有一个共同的特点,都是采用异步操作缓存。


老板发饼啦


阿旺由于对消息队列比较熟悉,所以他决定采用「消息队列来重试缓存的删除」的方案,来解决这次的用户问题。


经过几天几夜的操作,服务器搞定啦,立马向老板汇报工作。


老板让阿旺再观察些时间,如果没问题,到中秋节就商量“饼”的事情。


时间过的很快,中秋佳节到了,这期间一直都没有用户反馈数据不一致的问题。


老板见这次阿旺表现很好,没有再出现任何差错,服务器的访问性能也上来了,于是给阿旺发了这个超级大的月饼,你看这个饼又大又圆,就像你的代码又长又多.

0.png

阿旺看到这个月饼,哭笑不得,没想到这就是老板画的饼,是真的很大饼。。。。以上故事纯属虚拟,如有巧合,以你为准。



相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
传感器 算法 机器人
倒立摆
倒立摆
50 0
|
机器学习/深度学习 传感器 安全
【倒立摆】基于PID实现双回路倒立摆控制附Matlab代码
【倒立摆】基于PID实现双回路倒立摆控制附Matlab代码
|
机器学习/深度学习 传感器 算法
【倒立摆】基于PID模糊控制算法模拟倒立摆系统附Matlab代码
【倒立摆】基于PID模糊控制算法模拟倒立摆系统附Matlab代码
|
机器学习/深度学习 算法 决策智能
基于强化学习的倒立摆控制策略Matlab实现(附代码)
基于强化学习的倒立摆控制策略Matlab实现(附代码)
231 0
|
传感器
现代控制理论课程实验三:一阶倒立摆的LQR控制器设计
现代控制理论课程实验三:一阶倒立摆的LQR控制器设计
现代控制理论课程实验三:一阶倒立摆的LQR控制器设计
|
PHP 数据安全/隐私保护
|
移动开发 前端开发 JavaScript
最新30幅动人心脾的优秀摄影作品欣赏
  有人说过的一句精辟的语言:摄影家的能力是把日常生活中稍纵即逝的平凡事物转化为不朽的视觉图像。的确,摄影师们帮助记录下那些生活中特别的瞬间,让其他人能够一起感受这些动人的时刻。今天这篇文章继续向大家分享30幅动人心脾的摄影作品,一起欣赏。
886 0
|
前端开发
40幅五彩缤纷的秋天风景摄影作品欣赏(下篇)
  秋天的美是成熟的--它不像春那么羞涩,夏那么坦露,冬那么内向;秋,收获的季节,金黄的季节,同春一样可爱,同夏一样热情,同冬一样迷人。今天这篇文章和大家分享40幅五彩缤纷的秋天风景摄影作品,一起欣赏:)   Autumn Lake w/ Fog Blooming Autumn Berri...
909 0
|
前端开发
40幅五彩缤纷的秋天风景摄影作品欣赏(上篇)
  秋天的美是成熟的--它不像春那么羞涩,夏那么坦露,冬那么内向;秋,收获的季节,金黄的季节,同春一样可爱,同夏一样热情,同冬一样迷人。今天这篇文章和大家分享40幅五彩缤纷的秋天风景摄影作品,一起欣赏:) Yellow Trees in Autumn   The Leaves are Tu...
1196 0