发布时间:2026/9/1 7:31:08
从双写到一致:Redis缓存与数据库一致性方案全解析 一、引言为什么会有双写一致性问题在互联网高并发系统中Redis 作为缓存层几乎已经成为标配。引入缓存的初衷很简单——减轻数据库压力提升读取性能。但缓存一旦引入一个绕不开的问题就浮出水面数据库中的数据更新了Redis 中的缓存怎么办这就是所谓的“双写一致性问题”——当业务数据同时存在于数据库和 Redis 缓存中时如何保证两者数据的一致性。先看一个典型的场景用户修改了自己的昵称你更新了 MySQL但 Redis 中还存着旧的昵称。下一次用户查询时读到的是旧数据——这就是不一致。如果运气不好这种不一致可能持续很长时间直到缓存过期或被主动淘汰。二、主流解决方案详解方案一Cache-Aside Pattern旁路缓存模式这是最经典的缓存策略核心思路是应用程序在更新数据时先更新数据库再删除缓存。工作流程读请求先查缓存命中则直接返回未命中则查数据库回填缓存写请求先更新数据库再删除缓存为什么是“删缓存”而不是“更新缓存”更新缓存存在明显的并发问题线程A更新数据库为100线程B更新数据库为200如果两者以不同顺序更新缓存最终缓存值可能是错的。而删除缓存则简单得多——下次读请求自然会从数据库加载最新值。存在的问题先更新数据库再删除缓存如果删除失败怎么办缓存中会长期保留旧数据。另外在极端并发下可能出现这种情况线程A更新数据库后、删除缓存前线程B读到旧缓存并回填导致旧值覆盖新值。改进思路引入重试机制——删除缓存失败时将需要删除的 key 发送到消息队列由消费者不断重试直到成功。方案二延迟双删延迟双删是对 Cache-Aside 的改良流程如下先删除缓存更新数据库延迟 N 秒后再次删除缓存这个“延迟再删一次”的目的是什么主要是为了清除在更新数据库期间其他读请求可能写入的旧缓存数据。适用场景对一致性要求不高的非高并发业务。需要注意延迟时间怎么定一般设置为“读请求耗时 几百毫秒”的缓冲时间。但这个方案无法保证100%可靠延迟处理也可能不满足实时性需求。方案三订阅 Binlog 异步同步Canal Redis这是目前生产环境中广泛使用的方案核心思想是应用程序只负责操作数据库缓存由独立的同步服务自动维护。整体架构应用写入 MySQL → MySQL 生成 binlog → Canal 伪装成 MySQL Slave 拉取 binlog → 解析后推送给 Redis 客户端 → 更新或删除 Redis 缓存。Canal 的工作原理Canal 是阿里巴巴开源的 MySQL binlog 增量订阅组件它模拟 MySQL Slave 的交互协议向 Master 发送 dump 协议接收 binlog再将原始 byte 流解析为结构化的 INSERT/UPDATE/DELETE 事件。关键设计要点MySQL 必须开启 binlog 并设置为 ROW 模式Redis Key 设计要规范建议格式为{业务}:{实体}:{ID}设置合理的 TTL防止冷数据长期驻留同一 Key 的变更要按顺序处理如 Kafka 分区按主键哈希优势业务解耦、高吞吐低延迟、最终一致性有保障。局限性增加了组件复杂度需部署 Canal、可能还需引入 MQ且依赖 MySQL binlog。方案四分布式锁在并发更新场景下可以使用分布式锁如 Redisson在更新数据前锁定资源确保同一时刻只有一个操作能进行。优点强一致性有保障。缺点性能开销大不适合高并发场景。三、方案对比与选型建议方案一致性级别实现复杂度适用场景Cache-Aside 重试最终一致性低通用场景大多数业务延迟双删最终一致性低非高并发、一致性要求不高Canal Binlog最终一致性中需要解耦、变更频繁的场景分布式锁强一致性中并发冲突多、对一致性要求极高选型建议大多数业务场景Cache-Aside 删除重试机制就足够了简单可靠数据变更频繁、希望解耦Canal Redis 是更好的选择对一致性要求极高但并发不高可以考虑分布式锁终极兜底无论采用哪种方案都应该给缓存设置合理的过期时间这是最后一道防线四、总结缓存一致性没有银弹。强一致性、高性能、高可用三者往往不可兼得。在实际工程中我们需要根据业务场景做取舍对于用户维度的数据订单、用户信息并发冲突概率低Cache-Aside 足矣对于商品、菜单等基础数据Canal 订阅 binlog 过期时间能覆盖绝大部分需求秒杀、库存等对一致性要求极高的场景则需要更严谨的方案组合最后记住一点缓存是性能优化的手段不是数据的主存储。接受“最终一致性”的理念在绝大多数场景下用合理的方案兜底机制就能把不一致的风险控制在可接受范围内。

相关新闻

2026/9/1 7:31:08

STM32驱动DHT11温湿度传感器:从单总线时序到代码实战

简介:一份基于STM32F10X系列的DHT11温湿度传感器驱动程序资料,主要面向嵌入式初学者以及需要在STM32平台上快速实现单总线通信的开发者。资源围绕DHT11单总线通信协议展开,详细说明如何通过GPIO与定时器完成启动信号发送、27us/50us高低电平时…

2026/9/1 7:26:07

STM32F407接MPU6050实战:I2C配置与DMP欧拉角输出

简介:这款基于 STM32F407 与 MPU6050 的六轴姿态解算工程包,面向嵌入式入门的开发者,围绕“陀螺仪加速度计数据采集、I2C 通信、互补滤波融合、欧拉角串口输出”这一完整链路展开,可直接借鉴到平衡车、机器人姿态参考等场景。压缩…

2026/9/1 7:46:08

亲手实现Transformer核心:注意力机制从原理到PyTorch代码

为什么我把"看懂的"Transformer又亲手写了一遍Transformer 这个词,在深度学习圈子里几乎被说烂了。从 NLP 到 CV,从推荐系统到多模态,随处可见它的影子。但很多时候,我们看完了各种图解、听完了各种原理讲解&#xff0c…

2026/9/1 7:46:08

使用窗口函数

在复杂数据分析、报表统计、排名计算等场景中经常使用。窗口函数是 SQL 中非常强大的功能,可以在不改变行数的情况下对每一行进行计算,同时保留原始数据。 下面我从核心概念、语法结构、常用函数分类、实战案例、性能优化几个维度来系统说明。&#x1f3…

2026/9/1 7:46:08

《雾雾恋综》本地大模型驱动的剧本文案生产线搭建指南

《雾雾恋综》这个项目,第一眼看上去更像一部网文或者短剧选题:双女主、恋综、悬念感。但真正让我感兴趣的是,它能不能不再靠人工逐段憋稿,而是变成一条可由本地大模型驱动的剧本文案生产线。这篇文章就围绕这个题材,拆…

2026/9/1 7:46:08

基于AT89C51与Proteus仿真的多功能电子琴设计与实现

简介:本资源是一套基于AT89C51单片机的C语言多功能电子琴系统完整开发包,面向嵌入式初学者、单片机课程设计学生及Proteus仿真爱好者,解决从硬件建模、音阶生成到人机交互实现的一体化实践难题。压缩包共23个文件,含4个C源码&…

2026/9/1 7:46:08

COC跑团熟肉制作全指南:从音轨提取到硬字幕压制

说到 COC 跑团视频里的“熟肉”,很多观众的第一印象是字幕菌真伟大,第二印象可能就是:这个视频怎么还不更新?实际做过熟肉的人才会明白,最折磨人的往往不是翻译本身,而是从生肉到熟肉这条工具链上随时可能冒…

2026/9/1 7:41:08

QCustomPlot极坐标图叠加普通曲线:坐标转换与混合绘制实践

简介:Mathimge_Plot是一款专为DELPHI开发者设计的曲线图控件,支持绘制直线、曲线、函数图像、散点图与3D图形,适合科学计算、数据分析和工程应用场景,可灵活调整颜色、线型、标记样式等细节。压缩包共125个文件,仅394K…

2026/8/31 1:05:20

vSound小提琴数字处理器实操指南:从接线到演出的完整配置

电小提琴或者原声小提琴插电演出,第一个绕不开的坎就是声音难听。原声琴的共鸣和空气感一旦进了拾音器,出来的往往是一坨干瘪、发尖、带着奇怪塑料味的信号。我当初第一次把琴接上乐队调音台,直接被主唱吐槽"你这声音像在锯钢丝"。…

2026/8/31 2:14:20

传感器接口IC如何攻克生物化学传感的微弱信号难题?

1. 从电极到比特流:为什么生物化学传感必须依赖专用接口IC 做生物化学传感的人都有过类似的经历:明明传感器本身性能很好,信号输出却一塌糊涂——噪声大、漂移明显、重复性差,怎么调都达不到预期。很多时候问题并不在传感器&#…

2026/9/1 7:04:43

STM32F411CEU6多通道ADC采集:扫描模式+DMA实现详解

1. 多通道 ADC 的用武之地把“Multichannel ADC”和“STM32F411CEU6”这两个关键字放在一起,其实就是嵌入式开发里最常遇到的一类需求:用一块不算贵的 MCU,同时采集多路模拟信号。STM32F411CEU6 是 48 引脚的 Cortex-M4F 主控,主频…

2026/9/1 0:00:42

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/1 0:00:42

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/1 0:00:42

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

2026/9/1 0:00:42

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行&#xff0c;Type-C接口算是典型的“看着简单&#xff0c;做起来全坑”的东西。光引脚就24个&#xff0c;高低速信号、电源、控制线全部塞在一个小小的连接器里&#xff0c;如果PCB布局不做规划&#xff0c;打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/1 0:00:42

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/1 0:00:42

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…