如何保证MySQL和Redis数据一致性?
背景
在高并发的业务场景中,因为MySQL数据库是操作磁盘效率比较低,因此大多数情况下数据库都是高并发系统的瓶颈。因为Redis操作数据是在内存中进行,所以就需要使用Redis做一个缓存。让请求先访问到Redis,而不是直接访问MySQL数据库。效果图如下
查询数据
上面的业务场景,就是一个典型的MySQL存储数据和Redis缓存数据的业务场景。下面来看看一般的查询流程,如下图:
上面的查询流程如下:
用户请求系统,系统先查询Redis中是否有数据? 如果Redis中有数据,则直接将缓存中的数据响应给用户。 如果Redis中没有数据,则取查询MySQL数据库中是否有数据? 如果MySQL中有数据,则先将数据更新到Redis中,再将数据响应给用户。 如果MySQL中没有数据,则响应空数据给用户,请求结束。
上面的查询流程很简单,通过先查Redis缓存,避免大量请求访问MySQL数据库,从而大大提高系统响应效率。而且如果Redis中没有而MySQL中有,当从MySQL拿到数据以后,先将数据更新到Redis缓存中,这样下次请求同一份数据的时候就能从Redis中获取了。
更新数据
上面的查询流程是没什么问题,可是数据很有可能会更新。那么更新的时候怎么操作才能保证Redis和MySQL中的数据都更新成功并且一致呢?
下面看看一种常用的解决方案(双删缓存):
第一个问题:为什么是删除Redis缓存数据而不是更新数据?
假设我们缓存的数据是要做一个很复杂的计算,而且还不一定能用到。那如果你更新MySQL数据之后去更新Redis缓存不是就很耗时了,而且有可能做无用功。
第二个问题:为什么是先删除Redis缓存数据而不是先更新数据库呢?
我们不妨假设先更新MySQL中的数据,然后再删除缓存。如果更新完MySQL但是删除Redis失败了(别问为什么会失败?系统故障行不行,全球断电行不行?),那下次查询请求过来,因为Redis中有缓存数据,所以直接返回Redis缓存的旧数据了,是不是就出问题了?
那我们再看看,如果先删除Redis缓存,再更新MySQL。如果删除完Redis成功,但是更新MySQL失败。下次查询的时候,查询到Redis缓存发现没有,再去查MySQL,然后更新到Redis,虽然MySQL更新失败了,但是Redis中的数据和MySQL是一致的。
第三个问题:为什么更新完MySQL后还要再删一次Redis缓存呢?
假设我们第一次删完Redis结束,正在更新MySQL但是还没更新成功的时候,这时候有另外一个请求来查询数据。第二个请求查询Redis没有,然后查询MySQL这时候因为MySQL还没更新完,所以查询到的还是旧数据,同时把旧数据更新到Redis中了,等下一个请求再来查询的时候发现Redis有数据,就直接返回旧数据了。
因此更新完MySQL后需要再次删除Redis缓存。这样即使更新数据中间有其他个请求把旧数据更新到Redis中了,因为再次删了Redis缓存中的旧数据,依然能够避免其他请求获取到旧数据。
❝
我们认为数据是否更新成功是以MySQL中的数据为准,因此MySQL还没更新完成前或者更新失败,获取到旧数据不算是问题。所以我们只要保证Redis和MySQL中的数据一致就行。
❞
如何保证MySQL和Redis数据一致性?的更多相关文章
- Mysql和Redis数据如何保持一致
先阐明一下Mysql和Redis的关系:Mysql是数据库,用来持久化数据,一定程度上保证数据的可靠性:Redis是用来当缓存,用来提升数据访问的性能. 关于如何保证Mysql和Redis中的数据一致 ...
- 电商中的库存管理实现-mysql与redis
库存是电商系统的核心环节,如何做到不少卖,不超卖是库存关心的核心业务问题.业务量大时带来的问题是如何更快速的处理库存计算. 此处以最简模式来讨论库存设计. 以下内容只做分析,不能直接套用,欢迎 ...
- Gearman + Nodejs + MySQL UDF异步实现 MySQL 到 Redis 的数据同步
[TOC] 1, 环境 CentOS, MySQL, Redis, Nodejs 2, Redis简介 Redis是一个开源的K-V内存数据库,它的key可以是string/set/hash/list ...
- 06 python操作MySQL和redis(进阶)
python操作mysql.redis 阶段一.mysql事务 主要用于处理操作量大,复杂度高的数据.比如说,在人员管理系统中,你删除一个人员,你即需要删除人员的基本资料,也要删除和该人员相关的信息, ...
- PHP商品秒杀问题解决方案实例详解【mysql与redis】
本文实例讲述了PHP商品秒杀问题解决方案.分享给大家供大家参考,具体如下: 引言 假设num是存储在数据库中的字段,保存了被秒杀产品的剩余数量. if($num > 0){ //用户抢购成功,记 ...
- 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 ...
随机推荐
- go语言变量的零值和nil
Go语言中无论是全局变量还是局部变量,只要定义了一个变量都有默认的0值 int/int8/int16/int32/int64/uint/uint8/uint16/uint32/uint64/byte/ ...
- 【图论#02】岛屿系列题(数量、周长、最大面积),flood fill算法的代码实现与优化
岛屿数量 给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量. 岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成. 此外,你可以假设该网 ...
- Spring-Cloud集成redis-cluster
前言 系统之前接入的是单点redis,为了条系统高可用能力,特增加集成redis-cluster集群的步骤 依赖库引入 <dependency> <groupId>org.sp ...
- 【Azure 应用服务】App Service For Windows 中如何设置代理实现前端静态文件和后端Java Spring Boot Jar包
问题描述 部署在App Service For Windows 中的网站使用 Java Spring Boot + 静态文件 (浏览器端使用Vue.js 与服务器端Java Spring Boot交互 ...
- pycharm/Intellij idea双击打不开,没有反应,下列方法亲测有用!
第一种方法: 看看你的微软C++运行库是不是误删了.....我就这么干过...以前有个软件捆绑这个 安装了 结果我后来给删了 ,导致我pycharm 和intellij idea全都打不开 !!!各位 ...
- spring注解版 图文教程
注解方式,需要配置contextp空间,@component若无参数,那就是只能类方式加载 注解开发不用set 构造器 注入函数 注解注入属性 管理第三方bean 示例: 数据库的类写在一个文件,文件 ...
- 基于 XAF Blazor 的规则引擎编辑器
开源项目地址:https://gitee.com/lowcodexaf/rules-engine-editor 前言 本项目是基于XAFBlazor的规则引擎编辑器,规则引擎采用的是微软开源的Rule ...
- RocketMQ为什么这么快?我从源码中扒出了10个原因!
大家好,我是三友~~ RocketMQ作为阿里开源的消息中间件,深受广大开发者的喜爱 而这其中一个很重要原因就是,它处理消息和拉取消息的速度非常快 那么,问题来了,RocketMQ为什么这么快呢? 接 ...
- windows下如何结束Tomcat进程
问题描述: 使用IDEA启动java中的SSM项目之后,服务正常运行.操作过程中不小心把IDEA 开发工具给关闭啦,导致tomcat没有正常停止,使用的端口8080仍然被占用.再次 打开IDEA,启动 ...
- $event - vue中默认参数的显示 - @on-change="func($event, code)" - 基础知识
@on-change="checkAllOnChangeHandle($event,scItem.code)"