不能只用本地map缓存,因其存在单机内存受限、集群数据不同步、缺乏自动过期淘汰机制三大硬伤;必须与redis等分布式缓存配合,通过“本地→redis→db”读路径穿透和“先库后删+广播清理”写一致性策略实现两级协同。

直接用本地 Map 做缓存不可靠,但把它和 Redis 等分布式缓存配合起来,就能在性能、一致性、资源消耗之间取得实际平衡。关键不是“有没有缓存”,而是“怎么让两级缓存真正协同工作”。
为什么不能只用本地 Map?
本地 Map(比如 ConcurrentHashMap)速度快、无网络开销,但它有三个硬伤:
- 单机内存有限,缓存大量数据(如万级商品)极易 OOM;
- 集群多节点下,各实例 Map 数据完全隔离,更新无法同步,极易脏读;
- 没有自动过期、淘汰、统计等机制,全靠手动维护,出错率高。
所以本地 Map 只能作为“临时加速层”,必须依赖分布式缓存兜底和对齐。
二级联动的核心流程(读路径)
每次查询走“本地 → 分布式 → DB”三级穿透,命中即返回:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 先查本地 Map:用商品 ID 作 key,若存在且未过期,直接返回;
- 本地未命中,查 Redis:key 格式如
product:1001,若命中,写回本地 Map(带 TTL,如 20 秒),再返回; - Redis 也未命中,查数据库,结果同时写入 Redis(设 10 分钟过期)和本地 Map(设 20 秒过期),避免下次重复穿透。
写操作如何保证两级一致?
更新时坚持“先库后删”,不更新缓存,只清理:
- 业务修改商品价格:先执行 SQL 更新数据库;
- 立即删除 Redis 中的
product:1001; - 同步广播一条清理指令(例如通过 Redis Pub/Sub 或轻量 MQ),通知所有应用节点清除本地 Map 中的
1001; - 若广播失败或节点离线,依靠本地 Map 的 TTL(20 秒)自动失效,作为兜底。
不直接更新本地 Map,是因为并发写可能覆盖彼此——A 写新价进 Map,B 还在用旧值覆盖,最终 Map 里存的是错的。
落地要点与避坑提醒
真正上线时,这几个细节决定成败:
-
本地 Map 必须带过期:别用裸
ConcurrentHashMap,改用 Caffeine(推荐)或 Guava Cache,强制设置expireAfterWrite(20, SECONDS); -
Redis key 设计要统一:本地 Map 的 key 和 Redis 的 key 命名规则必须一致(如都用
"product:" + id),否则联动失效; - 降级开关要预留:当 Redis 不可用时,允许本地 Map 在 TTL 内继续服务(哪怕数据略旧),比直接打穿 DB 强得多;
- 监控两级命中率:本地命中率 > 85% + Redis 命中率 > 95%,说明设计合理;若本地命中率低,说明热点不集中或 TTL 太短。










