首页/新闻资讯/正文详情

分布式系统中MySQL与Redis双写一致性解决方案

发布时间:2026/11/5 6:11:21 来源:云帆数科 栏目:资讯中心
分布式系统中MySQL与Redis双写一致性解决方案
1. 双写一致性问题背景与挑战在分布式系统架构中MySQL作为持久化存储层Redis作为缓存层的组合已经成为行业标配。这种架构下最棘手的场景之一就是当数据需要同时写入这两个存储系统时如何保证它们的数据一致性。我经历过多次生产环境事故都是由于双写不一致导致的业务逻辑错误。举个真实案例某电商平台的库存管理系统商品详情页显示库存100件用户下单时系统提示库存不足。排查发现Redis缓存显示库存100但MySQL实际库存已降至5件。这种幽灵库存问题就是典型的双写不一致后果。2. 常见解决方案对比分析2.1 先更新数据库再删除缓存Cache Aside Pattern这是最常用的模式我们的订单系统就采用这种方案public void updateProduct(Product product) { // 1. 更新数据库 productDao.update(product); // 2. 删除缓存 redisTemplate.delete(product: product.getId()); }潜在问题步骤2失败会导致缓存脏数据并发场景下可能出现短暂不一致优化方案Transactional public void updateProductWithRetry(Product product) { try { productDao.update(product); redisTemplate.delete(product: product.getId()); } catch (Exception e) { // 加入重试机制 retryTemplate.execute(ctx - { redisTemplate.delete(product: product.getId()); return null; }); } }2.2 双写模式Write Through我们的支付系统采用这种强一致性方案public void processPayment(Payment payment) { // 1. 开启事务 TransactionStatus status transactionManager.getTransaction(new DefaultTransactionDefinition()); try { // 2. 写MySQL paymentDao.create(payment); // 3. 写Redis redisTemplate.opsForValue().set( payment: payment.getId(), payment, Duration.ofMinutes(30) ); // 4. 提交事务 transactionManager.commit(status); } catch (Exception e) { transactionManager.rollback(status); throw new RuntimeException(支付处理失败, e); } }性能影响事务持续时间增加约40%QPS下降约25%3. 延时双删策略实践对于秒杀系统这类高并发场景我们采用改进版的延时双删public void seckillProduct(Long productId) { // 第一次删除 redisTemplate.delete(product: productId); // 更新数据库 seckillDao.reduceStock(productId); // 异步延时删除 CompletableFuture.runAsync(() - { try { Thread.sleep(1000); // 延时1秒 redisTemplate.delete(product: productId); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }); }关键参数选择延时时间通常1-2秒需要根据业务QPS调整线程池配置Bean public Executor asyncTaskExecutor() { ThreadPoolTaskExecutor executor new ThreadPoolTaskExecutor(); executor.setCorePoolSize(20); executor.setMaxPoolSize(100); executor.setQueueCapacity(500); executor.setThreadNamePrefix(Async-Del-); executor.initialize(); return executor; }4. 一致性监控与补偿机制4.1 监控方案设计我们在关键业务表添加数据版本号ALTER TABLE products ADD COLUMN data_version BIGINT DEFAULT 1;然后通过定时任务对比数据Scheduled(fixedRate 300000) public void checkConsistency() { ListProduct dbProducts productDao.findAll(); dbProducts.forEach(product - { String cacheKey product: product.getId(); Product cacheProduct (Product)redisTemplate.opsForValue().get(cacheKey); if (cacheProduct ! null !cacheProduct.getDataVersion().equals(product.getDataVersion())) { // 记录不一致事件 inconsistencyService.recordInconsistency(product.getId()); // 修复缓存 redisTemplate.opsForValue().set( cacheKey, product, Duration.ofHours(1) ); } }); }4.2 补偿策略我们开发了补偿服务来处理不一致Service public class DataConsistencyService { Autowired private RedisTemplateString, Object redisTemplate; Autowired private ProductDao productDao; Retryable(maxAttempts 3, backoff Backoff(delay 1000)) public void repairProductCache(Long productId) { Product product productDao.findById(productId); if (product ! null) { redisTemplate.opsForValue().set( product: productId, product, Duration.ofHours(1) ); } } }5. 实战经验与避坑指南超时设置陷阱Redis操作必须设置合理的超时redisTemplate.setDefaultTimeout(3000); // 3秒序列化问题确保MySQL和Redis使用相同的序列化方式redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer(Product.class));热点key处理对高频访问key采用分片策略String cacheKey product: productId : (productId % 10);事务陷阱Redis事务与MySQL事务的差异// 错误用法 redisTemplate.multi(); redisTemplate.delete(key1); productDao.update(product); // 这里抛异常会导致redis事务执行但MySQL回滚 redisTemplate.exec();缓存穿透防护对空结果也进行缓存Product product productDao.findById(id); if (product null) { redisTemplate.opsForValue().set( product: id, new NullValue(), Duration.ofMinutes(5) ); }6. 高级场景解决方案6.1 分布式锁实现使用Redisson实现强一致性public void updateWithLock(Product product) { RLock lock redissonClient.getLock(lock:product: product.getId()); try { lock.lock(3, TimeUnit.SECONDS); // 查询最新数据 Product latest productDao.findById(product.getId()); // 业务处理 latest.setStock(latest.getStock() - 1); // 更新数据库 productDao.update(latest); // 更新缓存 redisTemplate.opsForValue().set( product: latest.getId(), latest, Duration.ofHours(1) ); } finally { lock.unlock(); } }6.2 基于binlog的最终一致性使用Canal监听MySQL binlogCanalEventListener public class ProductUpdateListener { Autowired private RedisTemplateString, Object redisTemplate; UpdateListenPoint public void onUpdate(Product product) { redisTemplate.opsForValue().set( product: product.getId(), product, Duration.ofHours(1) ); } }6.3 多级缓存策略public Product getProduct(Long id) { // 1. 检查本地缓存 Product product localCache.get(id); if (product ! null) { return product; } // 2. 检查Redis product (Product)redisTemplate.opsForValue().get(product: id); if (product ! null) { localCache.put(id, product); return product; } // 3. 查询数据库 product productDao.findById(id); if (product ! null) { redisTemplate.opsForValue().set( product: id, product, Duration.ofMinutes(30) ); localCache.put(id, product); } return product; }7. 性能优化指标我们在生产环境测得不同方案的性能对比方案平均耗时(ms)吞吐量(QPS)一致性级别先更新DB后删缓存451200最终一致性同步双写120450强一致性延时双删60900准实时一致性基于binlog--最终一致性(1-2s)8. 选型建议根据业务场景选择合适方案电商核心交易同步双写分布式锁商品详情页延时双删本地缓存用户画像数据基于binlog的最终一致性秒杀库存Redis原子操作异步扣减// 秒杀库存方案示例 public boolean seckill(Long productId) { String key seckill:stock: productId; Long value redisTemplate.opsForValue().increment(key, -1); if (value 0) { // 异步记录库存变更 mqTemplate.send(seckill-stock-update, new StockUpdate(productId, -1)); return true; } else { // 库存不足恢复 redisTemplate.opsForValue().increment(key, 1); return false; } }

相关推荐

Unity UI擦除效果:RenderTexture与Shader实现刮刮卡
Unity UI擦除效果:RenderTexture与Shader实现刮刮卡

项目标题是「Unity UI擦除效果」,这本质上是在做「刮刮卡 / 手指擦除遮罩」这类交互。我会按从业者口吻写一篇完整博文,涵盖实现路线选型、坐标换算、双缓冲、线段距离场、Shader 编写、进度统计和踩坑表,主体保证在 5000 字以上。直接从正文… · 2026/11/5 6:11:21

Windows下Redis部署与优化全攻略
Windows下Redis部署与优化全攻略

1. Redis在Windows环境下的完整部署指南Redis作为一款高性能的键值数据库,在Windows平台上的部署过程与Linux环境存在显著差异。本文将详细介绍从零开始完成Redis在Windows系统中的安装、配置到可视化管理工具使用的全流程,包含多个实际部署中容易忽略的… · 2026/11/5 6:11:21

Python 300+配方知识地图:从语法到工程实战
Python 300+配方知识地图:从语法到工程实战

简介:《Python Cookbook: Everyone can cook delicious recipes 300》是Hernando Abella撰写、Aluna Publishing House于2024年出版的Python进阶参考读物,面向已掌握基础语法、希望系统提升编程能力的中级开发者与自学者,以300余个“食谱”式… · 2026/11/5 6:10:21

UCOS-II多任务与系统时钟实战:嵌入式课程设计避坑指南
UCOS-II多任务与系统时钟实战:嵌入式课程设计避坑指南

简介:这份资源是面向嵌入式专业学生与初学者的UCOS-II课程设计完整工程,围绕多任务调度与系统时钟展开,可用于课程实验、自学练手或作为RTOS入门的参考项目。压缩包共63个文件、约283KB,以35个h头文件、3个c源文件为核心代码&… · 2026/11/5 8:12:00

阿童木机器人港股冲刺:服务机器人行业商业逻辑解析
阿童木机器人港股冲刺:服务机器人行业商业逻辑解析

1. 阿童木机器人港股冲刺背后的商业逻辑 阿童木机器人近期披露的招股书显示,这家服务机器人企业在9个月内实现了1.57亿元营收,但净利润仅有94万元。这个看似矛盾的数据背后,藏着服务机器人行业怎样的生存法则?作为联想基金和车好多… · 2026/11/5 8:12:00

冥府技术体系架构:业力计算与轮回调度系统解析
冥府技术体系架构:业力计算与轮回调度系统解析

1. 冥府技术体系架构解析 在冥府技术团队中,我们建立了一套融合硅谷工程文化与东方玄学智慧的技术架构。这套系统需要处理每秒数百万级的因果事件,同时保证六道轮回的绝对公平性。作为从阳间晋升而来的技术管理者,我深刻理解两个世界的技术差… · 2026/11/5 8:12:00

OpenClaw技能库:提升开发效率的即插即用解决方案
OpenClaw技能库:提升开发效率的即插即用解决方案

1. 项目概述OpenClaw "Skills军火库"是一个专注于收集和整理各类OpenClaw技能的精选资源库。这个项目类似于一个数字化的工具箱,里面装满了各种可以直接拿来使用的"技能武器"。作为一名长期关注自动化工具和效率提升的技术从业者,我… · 2026/11/5 8:12:00

小公司如何高效利用大模型API降低成本
小公司如何高效利用大模型API降低成本

1. 为什么小公司应该避开大模型训练微调 去年接触过一家20人规模的AI创业团队,他们花了三个月时间和80%的研发预算在LLaMA模型微调上,结果做出的客服机器人还不如直接调用GPT-3.5的API效果好。这个案例很典型——当前阶段,模型训练和微调就像… · 2026/11/5 8:12:00

智能推荐算法在全屋定制系统中的应用与实践
智能推荐算法在全屋定制系统中的应用与实践

1. 项目背景与核心价值全屋定制行业近年来呈现爆发式增长,消费者对个性化家居解决方案的需求与日俱增。传统定制流程存在方案匹配度低、设计周期长、沟通成本高等痛点。这个毕业设计项目正是瞄准这一市场缺口,通过智能推荐算法重构线上定制流程。我在实际… · 2026/11/5 8:11:00

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38

多智能体协作系统架构设计与实践优化
多智能体协作系统架构设计与实践优化

1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时,Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中… · 2026/11/5 0:00:39

大模型系统性入门实战指南:从原理到部署微调的全链路路线
大模型系统性入门实战指南:从原理到部署微调的全链路路线

提到大模型的系统性入门,我先说个结论:这事真不难,难的是资料太散、路线太多,今天这个框架明天那个工具,新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#… · 2026/11/5 0:00:39

鸿蒙文件系统沙箱机制解析与开发实践
鸿蒙文件系统沙箱机制解析与开发实践

1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师,我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码,在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的… · 2026/11/5 0:00:39

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码