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

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

大家好,我是小林。

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

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


前情回顾


上回程序员阿旺为了提升数据访问的性能,引入 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
相关文章
|
传感器 算法 机器人
倒立摆
倒立摆
53 0
|
7月前
|
存储 算法 前端开发
2865. 美丽塔 I
2865. 美丽塔 I
38 0
|
机器学习/深度学习 传感器 安全
【倒立摆】基于PID实现双回路倒立摆控制附Matlab代码
【倒立摆】基于PID实现双回路倒立摆控制附Matlab代码
|
机器学习/深度学习 传感器 算法
【倒立摆】基于PID模糊控制算法模拟倒立摆系统附Matlab代码
【倒立摆】基于PID模糊控制算法模拟倒立摆系统附Matlab代码
|
机器学习/深度学习 算法 决策智能
基于强化学习的倒立摆控制策略Matlab实现(附代码)
基于强化学习的倒立摆控制策略Matlab实现(附代码)
237 0
|
数据可视化 JavaScript 前端开发
数据是美丽的
除了这个节点,最近我又沉迷另一个 dataisbeautiful 的节点,上面有大量数据可视化的作品。不过,由于网站是全英文,加上访问有些不稳定,估计大家看起来不大方便。所以我今天挑选最近看到的几个不错的可视化案例分享一下,都附了具体的链接供进一步了解。
|
算法
m基于滑膜变结构的倒立摆控制系统matlab仿真
m基于滑膜变结构的倒立摆控制系统matlab仿真
298 0
|
传感器
现代控制理论课程实验三:一阶倒立摆的LQR控制器设计
现代控制理论课程实验三:一阶倒立摆的LQR控制器设计
现代控制理论课程实验三:一阶倒立摆的LQR控制器设计