数据库与缓存怎样做同步最好_一笑而过者也的博客-程序员宅基地

技术标签: 数据库与缓存一致方案  数据库  

前言:

           在读取与写入缓存方面大家都是这么做的:判断是否有缓存数据,无数据的话从数据库加载,若查出数据不为null,则写入缓存,再把数据返回调用方。

            但是这里有一个问题需要分析,缓存与数据库的同步,在更新完数据库后,是更新缓存还是删除缓存,还是先删缓存,再更新数据库。从理论上来说,设置过期时间是最终保持一致的解决方案。但是这不是最好的办法,在缓存有效期内或者高并发情况下,会很可能出现读取到的数据与缓存不一致的情况。

三种策略:

           1.先更新数据库,再更新缓存

           2.先删除缓存,再更新数据库

           3.先更新数据库,再删除缓存

           不会出现先更新缓存再更新数据库,如果更新数据库失败了,那就完了

1.先更新数据库,再更新缓存

        这套方案不太好

         a.线程安全角度

                 (1) 线程A更新了数据库

                 (2) 线程B更新了数据库

                 (3) 线程B更新了缓存

                 (4) 线程A更新了缓存

            这样缓存中就出现了错误的数据库

           b.业务场景

                 如果数据库写的场景比较多,读的场景比较少,就会出现数据库频繁更新,缓存频繁更新可能缓存根本就没有读,这样浪费性能

                   如果写入数据库的值,并不是直接写入缓存的,而是要经过一系列复杂的计算再写入缓存,那么每次写入数据库后,再次计算写入缓存,也是浪费性能的。删除缓存显得更为合适。

 2.先删缓存,再更新数据库

            高并发操作下,依旧会出现问题

            (1) A线程进行写操作,先删除缓存

            (2) B线程发现没有缓存,去数据库读取旧值

            (3) B线程将旧值写入缓存

            (4) A线程更新数据库

            这样,数据库中的数据,又是脏数据了,还有在数据库主从分离情况下,中从没来的及同步,结果把未同步的数据写入到了缓存。这怎么解决

          采用延时双删策略

             redis.delKey(key);

             db.update(Data);

             new Thread(()->{Thread.sleep(1000);redis.delKey(key);}).start();

          在不影响程序响应的情况下,开一个线程去删除缓存,    至于是多少时间后删除,可以自己评估,不一定是1s。

          但是这种情况下,如果第二次删除缓存失败了怎么办?

3.先更新数据库,再删缓存

      这样也有问题

            (1) 缓存刚好失效

            (2) A查数据库得到一个旧值

            (3) B将新值写入数据库

            (4) B删除缓存

             (5) A将旧值写入缓存

           因为数据库的读比写快,所以这种概率比较低正常顺序应该是1 2 5 3 4,但是也是有可能发生的,也可能是查询出来值后,经过一系列计算,又写入缓存的。解决办法还是延时缓存双删,但是和2一样,删除失败了怎么办?

解决方案1

         

               1.更新数据库

               2.删除缓存失败

               3.将要删除的key发送到消息队列

               4.消费消息删除key,重试直到成功

 

解决方案2

           

(1)更新数据库数据
(2)数据库会将操作信息写入binlog日志当中
(3)订阅程序提取出所需要的数据以及key
(4)另起一段非业务代码,获得该信息
(5)尝试删除缓存操作,发现删除失败
(6)将这些信息发送至消息队列
(7)重新从消息队列中获得该数据,重试操作。

 

备注说明:上述的订阅binlog程序在mysql中有现成的中间件叫canal,可以完成订阅binlog日志的功能。至于oracle中,博主目前不知道有没有现成中间件可以使用。另外,重试机制,博主是采用的是消息队列的方式。如果对一致性要求不是很高,直接在程序中另起一个线程,每隔一段时间去重试即可,这些大家可以灵活自由发挥,只是提供一个思路。

 

 

参考文献:

分布式之数据库和缓存双写一致性方案解析

 

          

实时内容请关注微信公众号,公众号与博客同时更新:程序员星星

 

 

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u012326462/article/details/81415522

智能推荐

搜索引擎接口测试-大数据统计测试_搜索接口怎么测_疯批美人东方陨的博客-程序员宅基地

搜索引擎接口测试。业务接口返回6000-9000个字段搜索接口查了7个搜索链路业务接口传参加上调试信息后的接口返回43846个字段测试需求:选取某一天人物的query,标识出同时出type=12及type=3的query,计算同时出现的概率,另外把同时出的query给出来,分析使用query选取:人物top1000 跟随机1000QA测试设计:去FBI捞取top1000个人物query+任意1000个人物query。读取引擎接口,判断response返回JSONObject.

Python web学习笔记——(一)flask实现websocket+Echarts图表数据实时更新_python websocket 数据持久化_wei22134的博客-程序员宅基地

flaskio+echarts实现图表实时更新项目概述遇到的问题Websocket 概述使用WebSocket协议的原因Flask实现WebSocket(全双工通信)方法一、使用flask-sockets(经过测试,无法连接)方法二、通过 `flask-sockeio` 实现WebSocket项目概述本人毕业设计是一个基于WSN的环境监控系统,实现流程如下:硬件端采集数据(包括温湿度,光照强度,当前位置经纬度等),并通过WiFi模块,上传至后端,后端采用JAVA编写,后端接收数据并对其进行存储,同时转

lca(倍增)_lca预处理_wichiene的博客-程序员宅基地

lca预处理每个点的深度,以及(1<<i)层(倍增)后的祖先节点 求lca 使x在y上方即深度小于y; 把x,y跳到同一深度 找到lca 倒序枚举i向上跳的说明:首先,一个正整数可以分解成(2^i+2^(i-1)+......+2^2+2^1+2^0) 而如果可跳两个(2^i)就相当于可以跳(2^(i+1))向上跳的时候,每一次跳尽可能多的...

微服务和VUE入门教程(23): 微服务之间的调用_vue微服务_hdubigben的博客-程序员宅基地

微服务和VUE(23): 微服务之间的调用1. 前言:开发微服务,免不了会有微服务之间的调用。在这里,我们使用的是openfeign 。因为微服务间的调用不需要通过zuul,因此就可以跳过token验证这一步,但是也没有了zuul的服务转发这个功能。为了模拟微服务间的调用,我们在my-user微服务中新建一个接口,让my-student微服务来调用这个接口。2. UserController.java 修改新建一个hello的接口,很简单,只有一个打印语句。@RequestMapping(val

adb学习笔记——>第1节:adb指定目标设备_adb 指定device_沧海黎明的博客-程序员宅基地

本博客参考:https://blog.csdn.net/qq_33003441/article/details/809737441、指定目标设备命令如果只有一个设备/模拟器连接时,则命令为:adb <command>如果有多个设备/模拟器连接时,则需要区分指定目标设备命令,命令为:adb [-d |-e |-s <serialNumber>] <...

【XYZ】常见三维坐标系约定图结_x y z三个轴的方向3d示意图_子兮、的博客-程序员宅基地

三维接触时间长了会慢慢发现,不同的引擎、建模软件、库对坐标系的约定各不相同。本篇总结了本人目前接触到的一些常见软件和库的坐标系,直接给出截图,希望能达到直观的速查表效果。

随便推点

Linux-(在写CPU的过程中遇到的)_Vuko-wxh的博客-程序员宅基地

最近在学习自己制作CPU 需要进行再Linux系统上进行GNU工具的使用,汇总了一些自己遇到的问题和用到的指令,大部分是在别处看到的,贴贴剪剪,希望对大家有帮助。安装虚拟机大家进行百度吧,我不建议大家装个双系统,我觉得没有虚拟机好用。装机的话:推荐软件安装管家公众号进行安装设置共享文件夹:1、The command could not be located because '/us...

java中数组拼接成字符串中间用逗号隔开_字符串数组拼接成逗号隔开_小四是个程序员的博客-程序员宅基地

使用到期之后![在这里插入代码片](https://img-blog.csdnimg.cn/20200317150457219.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjMyMjY0OA==,size_16,...

中国AVS超高清编码标准体系与生态建设(附部分视频)_LiveVideoStack_的博客-程序员宅基地

随着5G时代的到来,视频压缩方面面临更大的挑战,另外用户对于视频需求的提高使得在视频压缩方面需要做更多的提升。本文来自北京大学的王荣刚在LiveVideoStackCon 2019深圳站...

【STM32】R05D电控红外协议的美的空调遥控器_美的空调红外编码_人面兽心Edison的博客-程序员宅基地

目录一、设计思路一、R05D红外协议原理1.协议手册理解2.验证时序(重点)二、硬件实现1.需要的材料2.对发射模块电路进行修改3.STM32 GPIO选择三、代码实现1.载波38kHZ实现2.R05D时序实现3.调用函数并验证一、设计思路通常红外遥控采用NEC传输协议,而美的空调采用的是R05D红外协议(应该是自己设计的协议),因此用一般红外编码发射模块无法直接对空调进行控制。解决方法:获取R05D协议手册 + 用红外接收管对原有遥控器红外接收进行波形分析。一、R05D红外协议原理R05D电控功

《C Primer Plus(第五版)中文版》第6章第1至16题_vs9841的博客-程序员宅基地

1、编写一个程序,创建一个具有26个元素的数组,并在其中存放26个小写字母,并让该程序显示该数组的内容。#include int main(void){ char c[26]; int i; char j = 'a'; for(i=0;i<26;i++,j++) { c[i] = j; printf("%c ",c[i]); } return 0;}

推荐文章

热门文章

相关标签