当前位置: 首页 > news >正文

【个人笔记】数据一致性的解决方案

保证数据一致性:指保证redis里的数据和mysql的数据是一致的,不能说mysql更新了,但redis里面的还是旧的数据,反之亦然

先说结论:增删改的时候,把Redis中的缓存删了

为什么不先更新数据库,再更新缓存?
如果更新后不一定被读取,那么会进行很多次无意义的更新,万一你写入数据库的值,并不是直接写入缓存的,而是要经过一系列复杂的计算再写入缓存。那么,每次写入数据库后,都再次计算写入缓存的值,无疑是浪费性能的。显然,删除缓存更为适合。

那先写入库还是先删缓存呢?

  • 如果先删除缓存再写入库:还没来得及写入,就有线程来读取,这时候发现缓存为空,然后就去读了数据库旧数据并写入缓存,在数据库更新后发现数据不一致(此时缓存中为脏数据)
  • 如果先写入库再删除缓存:先写了库,但线程挂了缓存没删,这时候直接读旧缓存,也会数据不一致。

最终选择:先写入库再删缓存,并采取措施保证删除操作

最简单最基础的措施:延迟双删
基本思路:在写库前后都进行redis.del(key)操作,并且设定合理的超时时间。
具体步骤:
1、删缓存;
2、写入数据库;
3、休眠500毫秒(看情况定)
4、再次删除缓存

但问题是:删除失败怎么办
可以改成异步重试删除,有很多种方法可以进行重试

  • 单独起一个线程,但可能会创建太多线程导致OOM,不建议用;
  • 交给线程池处理,但如果服务器重启,部分数据可能会丢失,不建议用;
  • 交给定时任务进行重试,比如elastic-job,定时1秒删除一次,尝试5次(自己决定),缺点是实时性不高;
  • 交给mq等消息中间件,让删除缓存的消费者进行重试
  • 订阅mysql的binlog,在订阅者中,如果发现了更新数据请求,则删除相应的缓存。(最常用)

具体来说:当一条数据发生修改时,MySQL 就会产生一条变更日志(Binlog),我们可以用消息队列订阅这个日志(而不是代码!用的是阿里的canel插件),拿到日志中具体操作的数据,再根据这条数据,用消息队列去删除对应的缓存,由专门的消费者来不断重试,直到删除成功。
过程:
1)更新数据库(增删改)
2)通过canal监听binlog,把监听到的binlog 数据发送到 MQ 队列中
3)通过消息队列的"删除缓存消费者"将缓存数据删除(缓存删除失败则通过MQ不断重试,直至删除成功)(用死信队列)

相关文章:

  • MySQL-数据库约束
  • 翻译:Recent Event Camera Innovations: A Survey
  • Anki 学习日记 - 卡片模版 - 单选ABCD(纯操作)
  • 《Linux运维总结:使用 MongoDB工具备份和恢复mongodb 7.0.14分片集群(方案一)》
  • yolov8环境安装
  • GPT+AI技术实战:构建多端智能虚拟数字人的创新与突破
  • WebRTC中的维纳滤波器实现详解:基于决策导向的SNR估计
  • 0基础学习CSS(六)字体
  • C++中的lower_bound函数详解
  • 孙论文——定标
  • 牛顿迭代法求解x 的平方根
  • lombok详细教程(详解)
  • windows系统中后台运行java程序
  • UnityShader 一种RGB分离效果
  • 【matlab画多纵坐标图像】
  • JS 中的深拷贝与浅拷贝
  • 【个人向】《HTTP图解》阅后小结
  • extjs4学习之配置
  • flutter的key在widget list的作用以及必要性
  • iOS帅气加载动画、通知视图、红包助手、引导页、导航栏、朋友圈、小游戏等效果源码...
  • Iterator 和 for...of 循环
  • JS学习笔记——闭包
  • Nodejs和JavaWeb协助开发
  • node学习系列之简单文件上传
  • Quartz实现数据同步 | 从0开始构建SpringCloud微服务(3)
  • weex踩坑之旅第一弹 ~ 搭建具有入口文件的weex脚手架
  • 包装类对象
  • 机器学习中为什么要做归一化normalization
  • 嵌入式文件系统
  • 融云开发漫谈:你是否了解Go语言并发编程的第一要义?
  • 深入体验bash on windows,在windows上搭建原生的linux开发环境,酷!
  • 吴恩达Deep Learning课程练习题参考答案——R语言版
  • 新书推荐|Windows黑客编程技术详解
  • 源码安装memcached和php memcache扩展
  • Java总结 - String - 这篇请使劲喷我
  • ​经​纬​恒​润​二​面​​三​七​互​娱​一​面​​元​象​二​面​
  • #{}和${}的区别?
  • #大学#套接字
  • #数学建模# 线性规划问题的Matlab求解
  • $ git push -u origin master 推送到远程库出错
  • (ctrl.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“
  • (九)c52学习之旅-定时器
  • (强烈推荐)移动端音视频从零到上手(下)
  • (算法)前K大的和
  • (转) ns2/nam与nam实现相关的文件
  • (转)setTimeout 和 setInterval 的区别
  • .DFS.
  • .gitignore不生效的解决方案
  • .Net Memory Profiler的使用举例
  • .NET开源全面方便的第三方登录组件集合 - MrHuo.OAuth
  • ??Nginx实现会话保持_Nginx会话保持与Redis的结合_Nginx实现四层负载均衡
  • @GlobalLock注解作用与原理解析
  • [ Linux Audio 篇 ] 音频开发入门基础知识
  • [ 物联网 ]拟合模型解决传感器数据获取中数据与实际值的误差的补偿方法
  • []error LNK2001: unresolved external symbol _m