redis 如何 mysql_Redis 如何保持和 MySQL 数据一致

一、需求起因

在高并发的业务场景下,数据库大多数情况都是用户并发访问最薄弱的环节。所以,就需要使用redis做一个缓冲操作,让请求先访问到redis,而不是直接访问MySQL等数据库。

cdae928751c7b4f3ec4f262917fda236.png

这个业务场景,主要是解决读数据从Redis缓存,一般都是按照下图的流程来进行业务操作。

c170dc137e1581c671be30b54a7e473e.png

读取缓存步骤一般没有什么问题,但是一旦涉及到数据更新:数据库和缓存更新,就容易出现缓存(Redis)和数据库(MySQL)间的数据一致性问题。

不管是先写MySQL数据库,再删除Redis缓存;还是先删除缓存,再写库,都有可能出现数据不一致的情况。举一个例子:

1.如果删除了缓存Redis,还没有来得及写库MySQL,另一个线程就来读取,发现缓存为空,则去数据库中读取数据写入缓存,此时缓存中为脏数据。

2.如果先写了库,在删除缓存前,写库的线程宕机了,没有删除掉缓存,则也会出现数据不一致情况。

因为写和读是并发的,没法保证顺序,就会出现缓存和数据库的数据不一致的问题。

如来解决?这里给出两个解决方案,先易后难,结合业务和技术代价选择使用。

二、缓存和数据库一致性解决方案

85c78e944c889bc97d5784259c50ee0b.png

1.第一种方案:采用延时双删策略

在写库前后都进行redis.del(key)操作,并且设定合理的超时时间。

伪代码如下:

public void write(String key,Object data){

redis.delKey(key);

db.updateData(data);

Thread.sleep(500);

redis.delKey(key);

}

具体的步骤就是:

先删除缓存;

再写数据库;

休眠500毫秒;

再次删除缓存。

那么,这个500毫秒怎么确定的,具体该休眠多久呢?

需要评估自己的项目的读数据业务逻辑的耗时。这么做的目的,就是确保读请求结束,写请求可以删除读请求造成的缓存脏数据。

当然这种策略还要考虑redis和数据库主从同步的耗时。最后的的写数据的休眠时间:则在读数据业务逻辑的耗时基础上,加几百ms即可。比如:休眠1秒。

设置缓存过期时间

从理论上来说,给缓存设置过期时间,是保证最终一致性的解决方案。所有的写操作以数据库为准,只要到达缓存过期时间,则后面的读请求自然会从数据库中读取新值然后回填缓存。

该方案的弊端

结合双删策略+缓存超时设置,这样最差的情况就是在超时时间内数据存在不一致,而且又增加了写请求的耗时。

2、第二种方案:异步更新缓存(基于订阅binlog的同步机制)

技术整体思路:

MySQL binlog增量订阅消费+消息队列+增量数据更新到redis

读Redis:热数据基本都在Redis

写MySQL:增删改都是操作MySQL

更新Redis数据:MySQ的数据操作binlog,来更新到Redis

Redis更新

1)数据操作主要分为两大块:

一个是全量(将全部数据一次写入到redis)

一个是增量(实时更新)

这里说的是增量,指的是mysql的update、insert、delate变更数据。

2)读取binlog后分析 ,利用消息队列,推送更新各台的redis缓存数据。

这样一旦MySQL中产生了新的写入、更新、删除等操作,就可以把binlog相关的消息推送至Redis,Redis再根据binlog中的记录,对Redis进行更新。

其实这种机制,很类似MySQL的主从备份机制,因为MySQL的主备也是通过binlog来实现的数据一致性。

这里可以结合使用canal(阿里的一款开源框架),通过该框架可以对MySQL的binlog进行订阅,而canal正是模仿了mysql的slave数据库的备份请求,使得Redis的数据更新达到了相同的效果。

当然,这里的消息推送工具你也可以采用别的第三方:kafka、rabbitMQ等来实现推送更新Redis。

以上就是Redis和MySQL数据一致性详解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/502940.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

truncate python是删除文件内容吗_在Python中操作文件之truncate()方法的使用教程

truncate()方法截断该文件的大小。如果可选的尺寸参数存在,该文件被截断(最多)的大小。 大小默认为当前位置。当前文件位置不改变。注意,如果一个指定的大小超过了文件的当前大小,其结果是依赖于平台。 注意:此方法不会在当文件工…

sqlserver mysql时间格式化_SqlServer时间格式化

最近用的SqlServer比较多, 时间 格式化 老是忘记,现整理如下:(来源于网上,具体来源地址忘记了,归根到底MSDN吧) SELECT CONVERT(varchar(50), GETDATE(), 0): 05 16 2006 10:57AM SELECT CONVERT(varchar(50), GETDATE…

iframe 跨域_【梯云纵】搞定前端跨域

韦陀掌法,难陀时间善恶;梯云纵,难纵过乱世纷扰。现在开始写代码o(╯□╰)o什么是跨域1.跨域的定义广义的跨域是指一个域下对的文档或者脚本试图去请求另外一个域下的资源。a链接、重定向、表单提交、、、等标签background:url()、font-face()ajax 跨域请求……狭义的…

java中exception_Java中的异常 Exceptions

1. 概念exception是“exceptional event”的缩写,是指执行程序中发生的事件,破坏了程序的正常执行流程。Java 异常处理机制使程序更加健壮易于调试,它可以告诉程序员三个问题:错误的类型、位置、原因,帮助程序员解决错…

python异步asy_Python 异步编程之asyncio【转载】

一、协程的认识 协程(Coroutine),也可以被称为微线程,是一种用户态内的上下文切换技术。 简而言之,其实就是通过一个线程实现代码块相互切换执行。例如:deffunc1():print(1) ...print(2)deffunc2():print(3…

bitcount java_Java源码解释之Integer.bitCount

Java中的Integer.bitCount(i)的返回值是i的二进制表示中1的个数。源码如下:public static int bitCount(int i) {// HD, Figure 5-2i i - ((i >>> 1) & 0x55555555);i (i & 0x33333333) ((i >>> 2) & 0x33333333);i (i (i >&…

python自定义全局异常_如何在python中进行全局异常捕获

使用sys.excepthook函数进行全局异常的获取。 首先定义异常处理函数, 并使用该函数接收系统异常信息。 import wx import sys class TestFrame(wx.Frame): def __init__(self): wx.Frame.__init__(self, None, -1, test) btn wx.Button(self, -1, test) btn.Bind(w…

git merge 冲突_卧槽!小姐姐用动画图解 Git 命令,这也太秀了吧?!

公众号关注 “GitHubDaily”设为 “星标”,每天带你逛 GitHub!大家好,我是小 G。在座的各位应该都知道,Git 作为居家必备、团队协作之利器,自从 Linus Torvalds 发布这款工具后,便一直受到各路开发者的喜爱…

freebsd java 能用吗_在FreeBSD 4.9下安装JAVA环境

导读:资源下载地址:1.http://www.sun.com/softwarre/java2/download.html2.http://ftp.csie.chu.edu.tw/FreeBSD/distfiles/openmotif/3.http://ameba.sc-uni.ktu.lt/pub/FreeBSD/4.http://www.wormwang.net/mirrors/java/一、以下的包要先下载放到各自的…

python中exec是什么意思_Python中的进程分支fork和exec详解

在python中,任务并发一种方式是通过进程分支来实现的.在linux系统在,通过fork()方法来实现进程分支. 1.fork()调用后会创建一个新的子进程,这个子进程是原父进程的副本.子进程可以独立父进程外运行. 2.fork()是一个很特殊的方法,一次调用,两次返回. 3.fork()它会返回2个值,一个…

java冒泡排序原理_冒泡排序原理及其java实现

冒泡排序原理:临近的数字两两进行比较,按照从小到大或者从大到小的顺序进行交换,这样外层循环每循环一次,都会把一个数的顺序排好(从小到大的话每次都会把上回剩余的数据最大的放在剩余数的最后面,反之则是最小的放剩余…

java holder_java.sql.SQLException: connection holder is null

错误信息2017-11-15 14:53:16.931 [ ] ERROR com.hzcf.flagship.web.AssetPlanController 126 :### Error updating database. Cause: java.sql.SQLException: connection holder is null### Cause: java.sql.SQLException: connection holder is null; uncategorized SQLExcep…

java signed_如何从java中的字节读取signed int?

我有一个规范读取接下来的两个字节是signed int.要在java中读取我有以下内容当我使用以下代码在java中读取signed int时,我得到值65449计算无符号的逻辑int a (byte[1] & 0xff) <<8int b (byte[0] & 0xff) <<0int c ab我认为这是错误的,因为如果我和0xff我…

android 删除文件 代码_代码审计之某系统后台存在任意删除文件

本文作者&#xff1a;霾团队交流群&#xff1a;673441920-----------------------------------------------------------前言POC镇楼&#xff01;&#xff01;&#xff01;POST 漏洞演示过程&#xff1a;首先我们利用D盾监听下我们的项目以外的目录。这里刚刚我们创建了这个文件…

ubuntu java8 java9_在Ubuntu/Debian系统上安装Java 9的方法

本文介绍在Ubuntu/Debian系统上安装Oracle Java 9的方法&#xff1a;使用webupd8team/java PPA&#xff0c;相同的PPA提供了Java 8和Java 7等旧版Java的软件包&#xff0c;如果你的应用程序需要这个&#xff0c;可以随意安装它们。要安装新版本可参考在Ubuntu 18.04系统上安装J…

websocket 压力测试_打造最强移动测试平台

笔者今年换掉了服役N年的旧手机&#xff0c;新手机12G的RAM&#xff0c;比自用的本子内存都大&#xff0c;如果只是玩游戏感觉不能完全发挥出全部机能&#xff0c;但又因为怕影响日常使用没有进行root&#xff0c;经过一番折腾&#xff0c;发现即使不root也不影响把它变成一款测…

python银行系统模拟演练_python多线程实现代码(模拟银行服务操作流程)

1.模拟银行服务完成程序代码目前&#xff0c;在以银行营业大厅为代表的窗口行业中大量使用排队(叫号)系统&#xff0c;该系统完全模拟了人群排队全过程&#xff0c;通过取票进队、排队等待、叫号服务等功能&#xff0c;代替了人们站队的辛苦。排队叫号软件的具体操作流程为&…

字符串左侧补0_(48)C++面试之最长不含重复字符的子字符串(动态规划)

// 面试题48&#xff1a;最长不含重复字符的子字符串// 题目&#xff1a;请从字符串中找出一个最长的不包含重复字符的子字符串&#xff0c;计算该最长子// 字符串的长度。假设字符串中只包含从a到z的字符。#include <vector> #include <string> #include <iost…

jp摩根的人都在学python么_摩根大通已要求所有资管部门员工必须学习编程

当代最具竞争力的技能是什么&#xff1f;摩根大通CEO告诉你---编程。今年新加入摩根大通的全部资产管理分析师必须强制学习编程语言&#xff0c;Python。摩根大通资管经理Mary Callahan Erodes表示“现代资产管理的唯一语言是编程语言”。因为强制普及编程语言&#xff0c;现在…

java exec 关闭_如何正确关闭java ExecutorService

从ExecutorService的 Oracle API文档页面推荐的方法&#xff1a;void shutdownAndAwaitTermination(ExecutorService pool) {pool.shutdown(); // Disable new tasks from being submittedtry {// Wait a while for existing tasks to terminateif (!pool.awaitTermination(60,…