【经典问题】mysql和redis数据一致性问题
前言
MySQL和Redis数据一致性算是个很经典的问题,在之前也看到过很多相关的文章,最近心血来潮,想把一致性问题的解决方案和存在问题都总结一下。
不推荐方案
1 先更新MySQL,再更新Redis。

如上图有两个请求要同时进行更新操作,在并发情况下,B请求虽然更新时间晚于A请求,但是可能因为网络延迟问题,导致本来A请求要先更新Redis的操作晚于B请求更新Redis的操作,最终导致了MySQL出现数据不一致。
2 先更新Redis,在更新MySQL。

这种情况其实等同于第一种情况。
3 先删除Redis缓存,再更新MySQL。

A请求对数据的更新操作晚于请求B的读取操作,导致B请求将数据库的旧值又写回缓存,删除缓存在这种情况下没有意义。
推荐方案
1 先删除Redis缓存,再更新MySQL,再删一次Redis缓存(延迟双删)

在第三种情况中,出现了删除缓存后被其他请求更新为旧值的情况,那么在这种情况下,再删除一遍缓存不就可以解决问题了。这里第二次删除缓存的时间必须在B请求回写旧值之后,所以要社招好第二次删除缓存的等待时间,根据业务实际耗时来定,假设B请求回写缓存要300ms,那么A请求可以设置等待500ms再进行缓存删除。
但是上面这种情况也会出现问题,比如延迟双删的时候删除缓存失败怎么办。
这个时候可以借助MQ重试机制。如下图:

将删除的请求放到MQ队列里面,然后系统再从MQ里面取出删除请求的操作,由于MQ支持失败重试,删除失败后会继续投递消息。
2 先更新MySQL,再删除Redis缓存。

在上面这种情况下,请求B出现了读取了一次旧值,如果对于业务是一致性要求没那么强的话(比如秒杀,减库存),这种方案也是可以的,误差范围是可以接收的,只存在这么一次数值是旧的情况。
当然还有特殊情况如下:

当B请求先查询Redis,这个时候redis刚好缓存失效,B请求就会去MySQL查询旧值,后续B请求回写旧值的请求又晚于A请求删除缓存的请求,导致缓存里面放的是旧值。
但是这种情况出现需要 同时满足以下两个条件:
(1)缓存刚好失效
(2)读请求回写缓存的时间晚于写请求回写缓存的时间
上述两个条件同时成立的概率是极小的,综上来说,这种方案还是不错的,复杂度也不高,但同时也是可能存在删除缓存失败的特殊情况导致误差。
3 先更新MySQL,通过 Binlog,异步更新 Redis

A请求更新完MySQL,借助Canal进行监听并把相关的修改记录推送到MQ,MQ经过消费系统拉取消息对Redis进行更新,如果在Redis更新之前,有新的读请求,依然会导致数据不一致性的问题,但是这种方案能够实现最终一致性。
在这里Canal作为一个组件,监听binlog和发送消息到MQ都由Canal完成。
方案总结
前三种方案都是不推荐使用的。对于推荐使用的方案,从实时性和技术复杂度来说,先写数据库再删除缓存是比较好的选择。如果要确保最终一致性的话,可以用binlog异步更新缓存的方案。
【经典问题】mysql和redis数据一致性问题的更多相关文章
- 【面试普通人VS高手系列】Redis和Mysql如何保证数据一致性
今天分享一道一线互联网公司高频面试题. "Redis和Mysql如何保证数据一致性". 这个问题难倒了不少工作5年以上的程序员,难的不是问题本身,而是解决这个问题的思维模式. 下面 ...
- 电商中的库存管理实现-mysql与redis
库存是电商系统的核心环节,如何做到不少卖,不超卖是库存关心的核心业务问题.业务量大时带来的问题是如何更快速的处理库存计算. 此处以最简模式来讨论库存设计. 以下内容只做分析,不能直接套用,欢迎 ...
- Mysql和Redis数据如何保持一致
先阐明一下Mysql和Redis的关系:Mysql是数据库,用来持久化数据,一定程度上保证数据的可靠性:Redis是用来当缓存,用来提升数据访问的性能. 关于如何保证Mysql和Redis中的数据一致 ...
- linux安装和配置 mysql、redis 过程中遇到的问题记录
linux下部署mysql和redis网上的教程很多,这里记录一下我部署.配置的过程中遇到的一些问题和解决办法. mysql ①安装完成后启动的时候报错 Starting MySQL.The serv ...
- Mysql与Redis的同步实践
一.测试环境在Ubuntu kylin 14.04 64bit 已经安装Mysql.Redis.php.lib_mysqludf_json.so.Gearman. 点击这里查看测试数据库及表参考 本文 ...
- 通过Gearman实现MySQL到Redis的数据同步
对于变化频率非常快的数据来说,如果还选择传统的静态缓存方式(Memocached.File System等)展示数据,可能在缓存的存取上会有很大的开销,并不能很好的满足需要,而Redis这样基于内存的 ...
- 一步完成 MySQL 向 Redis 迁移
从mysql搬一个大表到redis中,你会发现在提取.转换或是载入一行数据时,速度慢的让你难以忍受.这里我就要告诉一个让你解脱的小技巧.使用“管道输出”的方式把mysql命令行产生的内容直接传递给re ...
- MySQL to Redis
[TOC] 简介 使用mysql2redis可以非常便捷的将mysql中的数据导出到redis中去, 通常是需要一个select语句即可实现. 软件安装 // 安装apr + apr-util $ w ...
- Gearman + Nodejs + MySQL UDF异步实现 MySQL 到 Redis 的数据同步
[TOC] 1, 环境 CentOS, MySQL, Redis, Nodejs 2, Redis简介 Redis是一个开源的K-V内存数据库,它的key可以是string/set/hash/list ...
- mysql常见优化,更多mysql,Redis,memcached等文章
mysql常见优化 http://www.cnblogs.com/ggjucheng/archive/2012/11/07/2758058.html 更多mysql,Redis,memcached等文 ...
随机推荐
- ps--提升字体排版的美感四个有效方法
一,文字的摆放位置 (字体的选择不要超过三种,分散注意力)
- macbook-键盘连击问题002
https://support.apple.com/zh-cn/HT205662 如何清洁 MacBook 或 MacBook Pro 的键盘 如果您的 MacBook(2015 年及更新机型)或 M ...
- vue 甘特图(三):甘特图右侧内容拖动展示
vue3 甘特图(三):甘特图右侧内容拖动展示内容 解决因多个项目周期跨度不同,在一页屏幕里展示不完全,需要通过拖动甘特图下方的滚动条,去查看对应时间段内的内容 拖拽滚动视图,展示对应时间甘特图 构思 ...
- 重温dp——最长上升公共子序列
一道经典的dp了 题目描述 给出 1,2,-,n 的两个排列 P1 和 P2 ,求它们的最长公共子序列. 输入格式 第一行是一个数 n. 接下来两行,每行为 n 个数,为自然数 1,2,-,n 的一 ...
- 小景的Dba之路--Oracle用exp导出dmp文件很慢
小景最近在系统压测相关的工作,其中涉及了Oracle数据库相关的知识,之前考的OCP证书也在此地起了作用.今天的问题是:Oracle用exp导出dmp文件很慢,究竟是什么原因,具体的解决方案都有哪些呢 ...
- 一款简单漂亮的WPF UI - AduSkin
前言 经常会有同学会问,有没有好看简单的WPF UI库推荐的.今天就给大家推荐一款简单漂亮的WPF UI,融合多个开源框架组件:AduSkin. WPF是什么? WPF 是一个强大的桌面应用程序框架, ...
- 内存与CPU:计算机默契交互的关键解析
内存 内存和CPU之间的交互是计算机体系结构中至关重要的一部分.它们之间的互动类似于一对不可分割的爱侣,彼此相互依赖且密不可分.没有内存,CPU无法执行程序指令,这样计算机就会变得毫无意义.同样地,如 ...
- dijkstra算法(朴素 + 堆优化)
dijkstra算法的大题思路是通过n - 1次迭代,每次迭代把一个点距汇点的最短路确定,当n - 1次循环过后所有点的最短路都已经确定 注意:dijkstra算法只适用于没有负权边的单源最短路 以下 ...
- 前端脚手架CLI生成模版命令工具(包括,npm包的发布,脚手架的搭建,注意事项,优化等)
写在前面 这是停更以后,续更的一篇文章. 为什么好长时间都没有更新,因为去其他平台更新了,包括掘金,思否,简书等. 在那些地方感觉没有归属感,有的平台原创审核很麻烦,简书号称可以获得打赏,可是码了几十 ...
- Web Woeker和Shared Worker的使用以及案例
目录 1.前言 2.介绍 Web Worker 3.使用须知及兼容性 3.1.使用须知 3.2.兼容性 4.使用 Web Worker 4.1.创建 Web Worker 4.2.与主线程通信 4.3 ...