news 2026/7/27 9:47:19

高并发缓存一致性实战:Cache Aside、Write Through、Read Through 选型与落地

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
高并发缓存一致性实战:Cache Aside、Write Through、Read Through 选型与落地

高并发缓存一致性实战:Cache Aside、Write Through、Read Through 选型与落地

一、为什么高并发下缓存一致性这么难

  • 核心矛盾在于:数据库与缓存的两次写不是原子操作,而请求执行顺序在并发场景下不可控,导致短暂甚至较长时间的数据不一致。典型时序问题包括:先删缓存后写库,期间读请求把旧值回填;先写库后删缓存,期间读请求命中旧缓存;多写并发时缓存被旧值覆盖等。即便采用“先更新数据库,再删除缓存”,在极小窗口内仍可能读到旧值,只能追求最终一致性。在读写分离架构下,主从同步时延还会放大不一致窗口。为降低风险,工程上通常配合TTL 过期兜底延迟双删异步失效等手段共同使用。

二、三大缓存访问模式对比与选型

模式读流程写流程一致性特征适用场景主要代价
Cache Aside(旁路缓存)命中则返回;未命中读库并回填缓存建议“先更新数据库,再删除缓存通常最终一致;并发读写存在短暂旧值窗口读多写少、计算/聚合类缓存需处理删除失败、并发回填、主从时延
Read Through(读穿透)命中则返回;未命中由缓存层自动读库并回填应用视缓存为唯一数据源,由缓存层同步写库读路径简化;一致性取决于写路径实现希望读逻辑透明、统一缓存策略首次访问延迟;可能缓存“一次性”数据
Write Through(写穿透)命中则返回;未命中同 Cache Aside应用写缓存,缓存同步写库后返回写路径强一致;读路径同 Cache Aside写后读频繁、对一致性要求高写延迟增加;缓存写放大、可能“污染”
说明:Read/Write Through 常由缓存组件/代理封装实现,对应用透明;Write Behind(写回,异步批量写库)虽能提升吞吐,但一致性风险更高,不在本文三种模式之列。

三、高并发下的工程化落地清单

  • 写策略与顺序
    • 优先采用:先更新数据库,再删除缓存;为兜底设置合理 TTL。在极端并发或“删后回填”风险高的场景,增加延迟双删(如写库后延迟数百毫秒再删一次),降低脏数据驻留时间。
  • 删除失败与补偿
    • 写库成功后若删除缓存失败,采用异步重试(本地队列或消息队列)确保最终删除;或引入事件驱动(如订阅MySQL binlog,通过Canal/Kafka广播失效),将缓存失效与业务解耦。
  • 读写分离与强一致读
    • 缓存未命中且业务要求强一致时,读请求可强制走主库回填,避免从库同步时延导致回填旧值;代价是主库压力上升,需结合熔断/降级策略。
  • 热点与并发控制
    • 对热点 Key 的缓存重建加分布式锁/互斥锁,避免“缓存击穿”;并发重建时只允许一个线程回种,其他线程等待重试,显著降低数据库瞬时压力。
  • 多级缓存一致性
    • 本地缓存(如Caffeine)+ 分布式缓存(如Redis)组合时,失效需广播到所有实例(如Redis Pub/Sub),并给本地缓存设置较短 TTL错峰过期,避免“多级不一致”和“失效风暴”。

四、模式落地代码示例

  • Cache Aside(Spring Boot + Redis,含 TTL 与互斥锁)
@ServicepublicclassProductService{@AutowiredprivateProductRepositoryrepo;@AutowiredprivateStringRedisTemplateredis;privatestaticfinalDurationTTL=Duration.ofMinutes(10);privatestaticfinalDurationLOCK_TTL=Duration.ofSeconds(3);publicProductDTOget(Longid){Stringkey="product:"+id;// 1) 命中直接返回ProductDTOv=(ProductDTO)redis.opsForValue().get(key);if(v!=null)returnv;// 2) 未命中:互斥重建StringlockKey="lock:"+key;Booleanlocked=redis.opsForValue().setIfAbsent(lockKey,"1",LOCK_TTL);if(Boolean.TRUE.equals(locked)){try{v=repo.findById(id);if(v!=null)redis.opsForValue().set(key,v,TTL);returnv;}finally{redis.delete(lockKey);}}else{// 未抢到锁,短暂等待后重试一次Thread.sleep(50);returnget(id);}}publicvoidupdate(ProductDTOdto){// 1) 先更新数据库repo.save(dto);// 2) 再删除缓存(失败可入MQ/定时补偿重试)redis.delete("product:"+dto.getId());}}
  • Read Through(Spring Cache 抽象,缓存层自动读库回填)
@Configuration@EnableCachingpublicclassCacheCfg{@BeanpublicRedisCacheManagercacheManager(RedisConnectionFactorycf){RedisCacheConfigurationcfg=RedisCacheConfiguration.defaultCacheConfig().serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(newStringRedisSerializer())).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(newGenericJackson2JsonRedisSerializer())).entryTtl(Duration.ofMinutes(10)).disableCachingNullValues();returnRedisCacheManager.builder(cf).cacheDefaults(cfg).build();}}@ServicepublicclassProductReadThroughService{@Cacheable(value="products",key="#id",sync=true)publicProductDTOget(Longid){// 缓存未命中时,由 Spring Cache 调用此方法读库并回填returnrepo.findById(id);}}

🔥 关注公众号【云技纵横】,开始更新redis缓存进阶,包含手写缓存注解,缓存雪崩等内容哟!

提示:Write Through 通常依赖支持写穿透的缓存组件/代理(如部分企业级缓存网关),应用将写请求发给缓存,由缓存层负责同步写库,代码形态与 Read Through 类似,但写路径会“穿透”到数据库。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/16 8:47:10

cuda安装完成后验证步骤:nvidia-smi与PyTorch-CUDA-v2.8联动检查

CUDA环境验证实战:从驱动到PyTorch的端到端检查 在深度学习项目启动前,最令人沮丧的场景莫过于——代码写完、数据准备好,结果运行时却发现GPU没启用。更糟的是,错误信息模糊:“CUDA not available”,却不…

作者头像 李华
网站建设 2026/7/15 13:18:05

Android16 添加应用共享库

有时候需要添加一个公共so库,给多个应用使用,可以做如下修改:在system/core/rootdir/etc/public.libraries.android.txt里面修改:# See https://android.googlesource.com/platform/ndk//main/docs/PlatformApis.md libandroid.so…

作者头像 李华
网站建设 2026/7/22 6:20:16

【课程设计/毕业设计】基于springboot的公司财务管理系统设计实现 财务收支管理 收入/支出记录增删改查基于SpringBoot财务管理系统的设计与实现【附源码、数据库、万字文档】

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

作者头像 李华
网站建设 2026/7/19 15:22:18

【实战】 SAAS租户元数据模型设计

SAAS租户元数据模型设计 请关注公众号【碳硅化合物AI】 设计说明 本文档定义SAAS多租户平台的元数据模型,包括应用、模块、菜单、按钮、API、实体、表单、字段、视图等元数据对象,以及它们与租户的关联关系。 元数据表结构 1. 应用表 (application)…

作者头像 李华
网站建设 2026/7/25 4:26:33

Java毕设选题推荐:基于SpringBoot+web的中医诊所预约挂号系统设计与实现基于web的中医诊所预约挂号系统设计与实现【附源码、mysql、文档、调试+代码讲解+全bao等】

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

作者头像 李华
网站建设 2026/7/16 16:04:27

Git忽略文件.gitignore模板:PyTorch项目必备

Git忽略文件 .gitignore 模板:PyTorch 项目必备 在深度学习项目的日常开发中,你是否曾遇到过这样的场景?刚完成一轮模型训练,准备提交代码时,发现 Git 列出了成百上千个待跟踪文件——从 checkpoints/ 下的 .pth 权重…

作者头像 李华