本地缓存怎么在分布式环境下保持一致性

本地缓存(如 Caffeine、Guava Cache)是节点本地的内存缓存,分布式场景下各节点缓存独立,易出现 "数据不一致"(如节点 A 更新了数据库,节点 B 的缓存还是旧数据),解决方案如下:

1、核心挑战

  • 数据孤岛:每个节点的缓存仅存储本地访问的数据,无法感知其他节点的更新;

  • 并发更新:多节点同时更新同一数据,可能导致 "部分节点缓存未更新";

  • 延迟问题:即使触发缓存更新,网络延迟也可能导致短期不一致。

2、解决方案

方案 1:事件通知(消息队列)
  • 核心原理:通过消息队列(如 Kafka、RabbitMQ)广播 "数据更新事件",所有节点监听事件,收到后删除 / 更新本地缓存。

  • 实现步骤

    • 节点 A 更新数据库后,向消息队列发送事件:{type: "delete", key: "user:1001"}

    • 所有节点(包括 A 自己)订阅该消息队列,收到事件后执行cache.delete("user:1001")

    • 后续节点查询 "user:1001" 时,缓存未命中,查数据库获取最新数据并写入缓存。

  • 优缺点

    • 优点:一致性较好(延迟低),实现灵活;

    • 缺点:依赖消息队列(需保证消息不丢失、不重复);

  • 适用场景:中高一致性要求、节点数适中的场景(如电商商品缓存)。

方案 2:发布 / 订阅模式(如 Redis Pub/Sub)
  • 核心原理:基于 Redis 的发布 / 订阅功能,更新节点发布 "缓存更新消息",其他节点订阅消息并更新缓存。

  • 实现步骤

    • 所有节点订阅 Redis 的 "cache_update" 频道;

    • 节点 A 更新数据库后,向 "cache_update" 频道发布消息:"delete:user:1001"

    • 其他节点收到消息后,解析出 key,执行cache.delete("user:1001")

  • 优缺点

    • 优点:轻量级(无需额外部署消息队列),实时性高;

    • 缺点:Redis Pub/Sub 不保证消息持久化(节点离线则丢失消息);

  • 适用场景:对一致性要求一般、可接受短期不一致的场景(如非核心业务缓存)。

方案 3:版本号控制
  • 核心原理:为每个缓存 key 关联一个 "版本号",查询时先对比版本号,不一致则更新缓存。

  • 实现步骤

    • 数据库表新增 "version" 字段(如 user 表的 version,每次更新 + 1);

    • 缓存存储 "数据 + 版本号":cache.set("user:1001", {data: ..., version: 3})

    • 节点 B 查询时,先查缓存的版本号(3),再查数据库的版本号(4);

    • 若缓存版本号 < 数据库版本号,删除缓存,重新查询数据库写入缓存。

  • 优缺点

    • 优点:不依赖外部组件,一致性可控;

    • 缺点:每次查询多一次数据库版本号检查(性能略有损耗);

  • 适用场景:对一致性要求较高、不希望依赖中间件的场景(如核心配置缓存)。

方案 4:定时全量同步
  • 核心原理:后台线程定期从数据库全量加载数据,覆盖本地缓存,保证最终一致性。

  • 实现步骤

    • 节点启动时,全量加载 "热门商品列表" 到本地缓存;

    • 后台线程每 5 分钟执行一次全量同步:List<Product> products = db.query("select * from product where is_hot=1")

    • 用新数据覆盖本地缓存:cache.putAll(products.stream().collect(toMap(p->p.getId(), p->p)))

  • 优缺点

    • 优点:实现简单,适合全量数据场景;

    • 缺点:一致性弱(同步周期内数据不一致),全量同步性能损耗大;

  • 适用场景:数据变化频率低、对一致性要求低的场景(如静态配置、热门商品列表)。

3、综合最佳实践

  • 核心数据:事件通知(Kafka)+ 版本号控制(双重保障);

  • 非核心数据:发布 / 订阅(Redis Pub/Sub);

  • 静态数据:定时全量同步 + 过期时间兜底;

  • 兜底策略:所有本地缓存设置合理的过期时间(如 5-10 分钟),即使一致性方案失效,过期后也会自动更新。

相关推荐
深蓝电商API21 分钟前
缓存策略在海淘代购系统中的应用
缓存·系统架构·跨境电商·代购系统·反向海淘·代购平台
睡醒的土豆41 分钟前
解决 Kafka 管理工具中文乱码问题
分布式·kafka
庞轩px1 小时前
缓存Key设计的“七要七不要”
java·jvm·redis·缓存
難釋懷2 小时前
Redis分片集群手动故障转移
数据库·redis·缓存
SuniaWang4 小时前
《Spring AI + 大模型全栈实战》学习手册系列· 专题二:《Milvus 向量数据库:从零开始搭建 RAG 系统的核心组件》
java·人工智能·分布式·后端·spring·架构·typescript
Hui Baby4 小时前
TIDB分布式数据库提交设想
数据库·分布式·tidb
⑩-4 小时前
RabbitMQ 架构和工作原理?RabbitMQ 延迟队列如何实现?
java·分布式·架构·rabbitmq
国冶机电安装4 小时前
分布式控制系统(DCS)安装:从方案设计到投运验收的完整指南
分布式
用什么都重名5 小时前
Redis 入门与实践:从基础到 Stream 消息队列
数据库·redis·缓存
飞Link5 小时前
告别 ROS 的臃肿:用 ZeroMQ 构建极速具身智能分布式大脑(附 Python 实战)
开发语言·分布式·python