详解Redis数据库和缓存不一致的情况及解决方案

数据库与缓存不一致是分布式系统中常见问题,本质是数据在缓存层和存储层出现版本差异

一、并发写操作导致不一致(最常见)

  • 场景描述

    • 线程A更新数据库 → 线程B更新数据库 → 线程B更新缓存 → 线程A更新缓存

    • 结果:缓存中存储的是线程A的旧数据

  • 发生条件

  • 解决方案

    • 分布式锁:对同Key的写操作加锁

    • 串行化队列:将写请求放入MQ顺序执行

二、先更新数据库后删除缓存失败(Cache-Aside模式)

  • 场景描述

    • 更新数据库成功

    • 删除缓存失败(网络抖动/Redis超时)

    • 结果:缓存中残留旧数据

  • 关键代码风险点

    public void updateData(Data data) {db.update(data);          // 步骤1:数据库更新成功cache.delete(data.getId()); // 步骤2:缓存删除失败!
    }
  • 解决方案

    • 重试机制

      void deleteWithRetry(String key, int maxRetry) {int retry = 0;while (!cache.delete(key) && retry++ < maxRetry) {Thread.sleep(50);}
      }
    • 异步补偿:通过Binlog监听(如Canal)触发二次删除

三、主从延迟导致脏读(读写分离架构)

  • 场景描述

    • 主库更新成功 → 删除缓存

    • 读请求从未同步的从库读取旧值 → 回填缓存

    • 结果:缓存被旧数据污染

  • 解决方案

    • 延迟双删

      db.update(data);          // 更新主库
      cache.delete(key);        // 首次删除
      Thread.sleep(500);       // 等待主从同步
      cache.delete(key);        // 二次删除
    • 强制读主库:对一致性要求高的查询直连主库

四、缓存过期时高并发读(Cache Miss风暴)

  • 场景描述

    • 缓存过期瞬间涌入大量读请求

    • 请求1查DB → 请求2查DB → ... → 请求N查DB

    • 多个线程同时回填缓存(可能乱序)

    • 结果:缓存可能被中间状态数据覆盖

  • 极端案例

    • 请求1读取到旧值V1,回填耗时久

    • 请求2读取新值V2并先完成回填

    • 请求1最终将V1写入缓存(覆盖V2)

  • 解决方案

    • 互斥锁重建:仅允许一个线程重建缓存

    • 逻辑过期:物理缓存永不过期,通过逻辑时间控制

五、批量操作与部分失效

  • 场景描述

    • 场景1:批量更新数据库成功,但部分缓存删除失败

    • 场景2:分页查询缓存无法感知单条数据变更

    • 结果:缓存中存在部分脏数据

  • ​​​​​​​典型案例

    • 商品列表页缓存无法感知单个商品价格变更

    • 订单列表缓存未失效时,订单状态已更新

  • 解决方案

    • 缓存维度拆分:按查询条件设计缓存Key

    • 增量广播:通过消息队列通知相关缓存失效

    • 短过期时间:对聚合查询设置更短TTL

六、跨服务数据变更

  • 场景描述

    • 服务A更新数据库 → 服务B的缓存未失效

    • 原因:服务间缺乏缓存协同机制

    • 结果跨服务缓存残留旧数据

  • ​​​​​​​微服务常见问题

  • 解决方案

    • 领域事件通知:通过消息队列(Kafka/RabbitMQ)广播变更

    • 统一缓存层:所有服务通过SDK操作缓存,SDK统一处理失效

七、终极解决之道:取舍策略

        根据业务需求选择合适的一致性级别:

策略一致性强度性能影响适用场景
先删缓存再更新DB写少读多
先更新DB再删缓存通用方案(需重试)
双写+事务金融交易
延迟监听(Binlog)最终一致高并发写场景
忽略不一致+短TTL允许短暂脏读的业务

         重要原则:不要尝试绝对强一致,除非接受性能断崖式下降。通常建议采用 "更新DB + 延迟双删 + 重试队列" 的组合策略。

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

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

相关文章

湖北理元理律师事务所:企业债务危机的“急诊科”式应对方案

当企业陷入债务危机时&#xff0c;传统“头痛医头”的应对往往加速死亡。本方案基于企业债务重组实务&#xff0c;提炼出 “止血-清创-修复”三阶急救体系&#xff0c;助力企业守住生存底线。 第一阶段&#xff1a;精准止血&#xff08;0-30天关键期&#xff09; 目标&#x…

华为云Flexus+DeepSeek征文|基于Dify构建智能票据信息识别助手

华为云FlexusDeepSeek征文&#xff5c;基于Dify构建智能票据信息识别助手 一、构建智能票据信息识别助手前言二、构建智能票据信息识别助手环境2.1 基于FlexusX实例的Dify平台2.2 基于MaaS的模型API商用服务 三、构建智能票据信息识别助手实战3.1 配置Dify环境3.2 配置Dify工具…

Python实例题:基于联邦学习的隐私保护 AI 系统(分布式学习、隐私计算)

目录 Python实例题 题目 问题描述 解题思路 关键代码框架 难点分析 扩展方向 Python实例题 题目 基于联邦学习的隐私保护 AI 系统&#xff08;分布式学习、隐私计算&#xff09; 问题描述 开发一个基于联邦学习的隐私保护 AI 系统&#xff0c;包含以下功能&#xff…

点点(小红书AI搜索):生活场景的智能搜索助手

1. 产品概述 点点是小红书于2024年12月正式推出的AI搜索助手&#xff0c;由上海生动诗章科技有限公司开发&#xff0c;定位为生活场景搜索工具&#xff0c;聚焦交通、美食、旅游、购物等日常需求&#xff0c;旨在通过即时信息和真实用户分享帮助用户“精准避坑”。 核心特点 …

软件工程概述:核心概念、模型与方法全解析

一、软件工程定义与诞生背景 定义 将系统化、规范化、可度量的方法应用于软件开发、运行和维护的过程&#xff08;IEEE标准&#xff09;。 核心目标&#xff1a;在可控成本下&#xff0c;生产高质量、可维护、满足需求的软件产品。 - 软件开发&#xff1a;需求 → 设计 → 编码…

LVS+Keepalived+nginx

LVSKeepalivednginx 1 安装依赖 sudo yum install ipvsadm keepalived -y 查询是否安装成功 rpm -q -a keepalived 2 配置虚拟IP并安装ipvsadm /etc/sysconfig/network-scripts cp ifcfg-ens33 ifcfg-ens33:1 修改里面配置文件 TYPE"Ethernet" PROXY_METHOD"n…

数据分析实操篇:京东淘宝商品实时数据获取与分析

在电商行业蓬勃发展的当下&#xff0c;数据已然成为驱动决策的核心要素。无论是商家精准把控市场需求、制定营销策略&#xff0c;还是消费者做出明智的购物抉择&#xff0c;都离不开对电商平台商品数据的深入剖析。京东和淘宝作为国内电商领域的两大巨头&#xff0c;汇聚了海量…

微信小程序扫码添加音频播放报错{errCode:10001, errMsg:“errCode:602,err:error,not found param“}

主要流程代码如下&#xff1a; let innerAudioContext wx.createInnerAudioContext() // 提示音 innerAudioContext.autoplay true innerAudioContext.src ../images/scan.mp3 innerAudioContext.onError(function(res){ console.log(onError 开始监听:,res) }) innerAudi…

SVN合并指南,从dev合并部分revision到release指南

dev合并到release 1.进入release的工作区&#xff0c;右击选择Merge 点击Next 2.确认merge来源分支和当前分支 点击Show Log&#xff0c;挑选需要合并的单号 3. 选择需要合并的commit 注意点击Hide no-mergeable revisions&#xff0c;来隐藏掉已经合并的commit 4.选择需…

《计算机网络:自顶向下方法(第8版)》Chapter 8 课后题

复习题 8.1节 R1. 机密性是攻击者截获原始明文消息的密文加密后无法确定原始明文的属性。消息完整性是接收方可以检测发送的消息&#xff08;无论是否加密&#xff09;在传输过程中是否又被更改的属性。 因此&#xff0c;这两者是不同的概念&#xff0c;可以独立存在。一个在传…

抖音小程序开发:ttml和传统html的区别

1 传统 Web 中 HTML 的角色 HyperText Markup Language&#xff1a;用来描述页面结构——标题、段落、图片、表单…… 只负责“放什么元素、排在什么层级”&#xff0c;真正的行为靠 JS&#xff0c;视觉靠 CSS。 <!-- 传统网页&#xff1a;结构 class 交给 CSS --> &…

Unity2D 街机风太空射击游戏 学习记录 #12QFramework引入

概述 这是一款基于Unity引擎开发的2D街机风太空射击游戏&#xff0c;笔者并不是游戏开发人&#xff0c;作者是siki学院的凉鞋老师。 笔者只是学习项目&#xff0c;记录学习&#xff0c;同时也想帮助他人更好的学习这个项目 作者会记录学习这一期用到的知识&#xff0c;和一些…

Proteus如何创建第一个工程

视频教程&#xff1a; [最详细]Proteus新建第一个工程与快捷键设置 操作步骤 1打开Proteus后&#xff0c;左上角点击文件然后点击新建工程。 2新建工程后&#xff0c;弹出以下界面&#xff0c;选择修改自己的工程名字&#xff0c;&#xff08;工程名的后缀“.pdspsj”不要修改…

现代浏览器剪贴板操作指南 + 示例页面 navigator.clipboard 详解与实战

在 Web 开发中&#xff0c;复制文本到剪贴板是一个常见需求。多年来&#xff0c;过去我们依赖 Flash 或 document.execCommand(copy) 来实现。它曾是我们的得力助手&#xff0c;但这些方法存在兼容性差、安全性低的问题。现已经被正式标记为废弃&#xff08;Deprecated&#xf…

OpenCV-Python学习笔记

2 OpenCV中的Gui特性 2-1 图像入门 目标 学习如何读取图像、显示图像和保存图像 学习api函数&#xff1a;cv.imread()、cv.imshow()、cv.imwrite() 学习使用Matplotlib显示图像 使用OpenCV 读取图像 在OpenCV中&#xff0c;使用函数cv.imread()读取图像。 img cv.imread(le…

2025年- H87-Lc195--287.寻找重复数(技巧,二分查找OR动态规划)--Java版

1.题目描述 2.思路 3.代码实现 public class H287 {public int findDuplicate(int[] nums) {// 重复数字可能的最小值int min1;// 重复数字可能的最大值&#xff0c;数组长度为 n&#xff0c;数字范围是 [1, n-1]int maxnums.length-1;while(min<max) {// 防止溢出&#xf…

PVE使用ubuntu-cloud-24.img创建虚拟机并制作模板

前言 在使用pve时,虽然它已经可以克隆虚拟机,已经极大提升了创建虚拟机速度,但创建完成后,不可避免还是要配置下网络,因为服务器要使用静态IP,克隆出的机器需要重新设置新的IP地址,有没有连这一步都省了方法呢?有,就是Cloud-Init 创建虚拟机模板 1. 下载ubuntu-clo…

LLM增强检索---GraphRAG + LangGraph项目实战

专栏&#xff1a;大模型垂直应用技术​ ​​​​ 个人主页:云端筑梦狮 大模型应用落地亟需解决的核心问题有一个是&#xff1a;如何与私域数据交互。私域数据主要的问题是&#xff1a;需要有效地将企业数据整合进大语言模型中。由于大模型的上下文处理能力有限&#xff0c;一…

修改SSH端口实战

本次实战主要涉及SSH端口的修改和配置。首先&#xff0c;对master、slave1和slave2三台云主机的SSH配置文件进行修改&#xff0c;指定新的SSH端口&#xff0c;并重启SSH服务。接着&#xff0c;通过FinalShell工具修改连接端口&#xff0c;实现SSH连接到三台云主机。然后&#x…

PyTorch中的permute, transpose, view, reshape和flatten函数详解(已解决)

1.permute permute函数用于重新排列张量的维度。它接受一个元组作为参数&#xff0c;表示新的维度顺序。例如&#xff0c;如果我们有一个形状为(2, 3)的二维张量&#xff0c;我们可以使用permute函数将其维度重新排列为(3, 2)&#xff0c;如下所示&#xff1a; >>> …