news 2026/9/8 16:53:49

Redisson RLocalCachedMap 遇上事务就翻车?事务提交后缓存不一致的 3 种实战修复路径

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Redisson RLocalCachedMap 遇上事务就翻车?事务提交后缓存不一致的 3 种实战修复路径

Redisson RLocalCachedMap 遇上事务就翻车?事务提交后缓存不一致的 3 种实战修复路径

【免费下载链接】redissonRedisson: Valkey & Redis Java Client and Real-Time Data Platform. Sync/Async/RxJava/Reactive API. Over 50 Valkey and Redis based Java objects and services: Set, Multimap, SortedSet, Map, List, Queue, Deque, Semaphore, Lock, AtomicLong, Map Reduce, Bloom filter, Spring, Tomcat, Scheduler, JCache API, Hibernate, RPC, local cache..项目地址: https://gitcode.com/GitHub_Trending/re/redisson

Redisson 事务提交成功了,主库数据是对的,但 RLocalCachedMap 在部分实例上仍返回旧值。

先对号入座——你的症状是哪一种?

  • 同一实例刚 commit 完,马上读同一个 key 还是旧值,过一会儿又好了
  • A 实例提交成功,B 实例持续读旧值,重试也不恢复,只有重启才正常
  • 问题偶发,且基本都出现在断连、Redis 主从切换前后
  • 高并发扣减后,读接口拿到的还是扣减前的库存,直接超卖

四条症状根因相同,但修复成本差很多,所以先分清"旧值能容忍多久"。命中前两条且写量小的,看场景 A;"持续不恢复"或"断连后必现"的,直接跳到场景 B;扣减链路出问题的,直接看场景 C。

事务后本地缓存为什么变旧?一张图讲清楚

先纠正一个常见误区:Redisson 的事务不是 Redis 原生 MULTI/EXEC,而是客户端事务——写操作先对 key 加分布式锁,操作缓存在客户端内存里,commit() 时才整体下发给 Redis,隔离级别是 READ_COMMITTED,见 docs/transactions.md。RLocalCachedMap 则把一份数据存在每个实例的 JVM 里,远端变更不会主动推新值,而是通过 topic 广播失效消息(INVALIDATE)或完整新值(UPDATE),各实例收到后自行更新本地缓存,见 docs/client-side-caching.md。

源码里还有一个动作:事务内第一次写 local cached map 时,Redisson 会先发 LocalCachedMapDisable 消息"屏蔽"该 key 的失效订阅;commit() 时执行完写入,再广播对应的 enable/失效通知。所以"事务内别的实例看不到"是事务语义的代价,不算 bug;真正的损失窗口只有两个——失效消息经 pub/sub 有毫秒级延迟,以及实例恰好断连时消息丢失,而默认重连策略是 NONE,丢了就丢着。

实例 A(事务) Redis 实例 B(本地缓存) put p_1001=99(仅缓存+加锁,未下发) B 本地缓存=旧值 ← 未提交,不可见,正常 commit() ────────> 执行写入、释放锁 经 topic 广播失效/新值 ────────────────────────> B 收到后刷新本地缓存 (B 恰好断连/消息延迟时:B 一直是旧值)

RLocalCachedMap 事务提交后的失效广播时序:延迟窗口与消息丢失点

三种场景,三种打法

小写入量、键少:提交后强制刷新

写 QPS 在一百以内、缓存键只有几百个,比如内部工具、低频库存,别折腾策略,用默认 INVALIDATE 加提交后强制刷新就够,因为 key 少,整份失效的代价可以忽略。

RLocalCachedMap<String, Integer> stockCache = redisson.getLocalCachedMap( "product_stock", LocalCachedMapOptions.defaults()); RTransaction tx = redisson.createTransaction(TransactionOptions.defaults()); try { // 事务代理必须传非事务实例获取,代理的写只进事务队列,不碰本地缓存 tx.getLocalCachedMap(stockCache).put("p_1001", 99); tx.commit(); stockCache.clearLocalCache(); // commit 后再广播一次失效,兜住可能漏掉的提交通知 } catch (TransactionException e) { tx.rollback(); }

⚠️ 坑点:RTransaction 没有按名称取 local cached map 的方法,只接受传实例;拿错了代理,写根本进不了事务。

失效边界:commit 频率超过每秒几百次就别用了,每次 clearLocalCache 都是全 key 广播,读放大很快盖过省下的网络开销。

读多写少、多实例共享:选对同步策略

读写比大于十比一、多实例共享同一份数据,比如商品详情、配置中心,核心是让提交后的新值主动送到每个实例,同时保证断连后能补上漏掉的消息。

// UPDATE 把完整 key+value 广播给所有实例,读端无需回 Redis 查 LocalCachedMapOptions<String, Integer> options = LocalCachedMapOptions.<String, Integer>defaults() .syncStrategy(SyncStrategy.UPDATE) .reconnectionStrategy(ReconnectionStrategy.LOAD) .evictionPolicy(EvictionPolicy.LRU) .cacheSize(1000); RLocalCachedMap<String, Integer> stockCache = redisson.getLocalCachedMap("product_stock", options); RTransaction tx = redisson.createTransaction(TransactionOptions.defaults()); tx.getLocalCachedMap(stockCache).put("p_1001", 99); tx.commit(); // 提交时 Redisson 自动经 topic 广播新值,无需手动刷新

LOAD 会把失效记录进一份保留 10 分钟的日志,断连后 10 分钟内重连会自动补刷对应 key——这正是把"持续不恢复"症状修掉的配置,默认的 NONE 则什么都不做。

⚠️ 坑点:UPDATE 广播的是完整 key 加 value,value 超过 1KB 时带宽随实例数成倍放大,这种场景退回 INVALIDATE,让读端自己回源。

失效边界:写频率上来后广播消息开始堆积,或业务要求"提交后立刻读到的必须是新值",说明本地缓存已经不适合这条链路,转场景 C。

高并发写、强一致:放弃本地缓存

秒杀、库存扣减、金融类,读接口返回一个旧值就是资损事故,这类链路里 RLocalCachedMap 本身就是错误工具,因为本地缓存的失效是最终一致的,而扣减要求强一致。

RLock lock = redisson.getLock("stock_lock:p_1001"); if (!lock.tryLock(1, 3, TimeUnit.SECONDS)) { throw new IllegalStateException("扣减繁忙,稍后重试"); } try { // 扣减链路用普通 map,彻底绕开本地缓存 RMap<String, Integer> stockMap = redisson.getMap("product_stock"); int current = stockMap.get("p_1001"); if (current <= 0) throw new IllegalStateException("库存不足"); // CAS:即使锁被误用,也不会基于旧值覆盖写 stockMap.fastPut("p_1001", current - 1, current); } finally { lock.unlock(); }

锁保证临界区内没有别的写者,fastPut 保证就算锁逻辑写错,旧值也不会被覆盖,两层兜底。读库存的接口同样直接读普通 map,不走任何带本地缓存的实例。

失效边界:锁竞争到几千 QPS 以上、等待队列开始堆积,就该改成队列化预扣减或原子 decrement,别再上锁。

配置速查 & 避坑清单

配置项推荐值一句话作用去哪看
syncStrategy读多写少用 INVALIDATE,小 value 用 UPDATE决定提交后广播的是失效标记还是完整新值client-side-caching.md
reconnectionStrategyLOAD断连重连后补刷漏掉的失效消息,修"不恢复"client-side-caching.md
cacheSize1000–100000 表示无上限,-1 表示永不缓存collections.md
transaction timeout5s超时未 commit 自动回滚,防锁悬挂transactions.md
responseTimeout3scommit 等 Redis 响应的超时transactions.md
  • ⚠️ 事务 map 只接受传非事务实例,不存在按名称创建
  • ⚠️ syncStrategy 设 NONE 后缓存永不失效,只剩 TTL 兜底
  • ⚠️ 同一个 key 别混用带本地缓存和不带的实例
  • ⚠️ 集群模式用 {} hash tag 让事务相关 key 落同一 slot

延伸阅读

  • docs/transactions.md — 事务支持的对象清单、READ_COMMITTED 隔离级别与全部超时参数
  • docs/client-side-caching.md — SyncStrategy 三种取值、重连策略与本地缓存的完整配置项
  • RedissonTransaction.java — commit 时对本地缓存广播 LocalCachedMapDisable/Enable 的完整处理逻辑

【免费下载链接】redissonRedisson: Valkey & Redis Java Client and Real-Time Data Platform. Sync/Async/RxJava/Reactive API. Over 50 Valkey and Redis based Java objects and services: Set, Multimap, SortedSet, Map, List, Queue, Deque, Semaphore, Lock, AtomicLong, Map Reduce, Bloom filter, Spring, Tomcat, Scheduler, JCache API, Hibernate, RPC, local cache..项目地址: https://gitcode.com/GitHub_Trending/re/redisson

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

pot-desktop 生词本使用指南:划词翻译单词如何一键收藏

pot-desktop 生词本使用指南&#xff1a;划词翻译单词如何一键收藏 【免费下载链接】pot-desktop &#x1f308;一个跨平台的划词翻译和OCR软件 | A cross-platform software for text translation and recognition. 项目地址: https://gitcode.com/GitHub_Trending/po/pot-d…

作者头像 李华
网站建设 2026/9/8 16:51:39

Spring Boot集成向量数据库与RAG:从语义搜索到智能问答

做“Spring with AI ()”这个系列&#xff0c;初衷很简单&#xff1a;很多团队技术栈已经稳定在Spring Boot上&#xff0c;现在又想把AI能力接进来&#xff0c;但不想为了一个“智能搜索”就引入一整套新语言新框架。这篇文章对应系列里的“搜索扩展”主题&#xff0c;核心是把…

作者头像 李华
网站建设 2026/9/8 16:50:06

TMS320F28335 DSP最小系统核心板设计:从原理图到PCB布局实战解析

简介&#xff1a;面向DSP开发者和电子工程师&#xff0c;这份完整资料包围绕TMS320F28335浮点DSP最小系统核心板&#xff0c;提供ALTIUM格式硬件原理图、PCB图&#xff08;未布线&#xff09;及配套测试软件源码&#xff0c;可辅助理解电源、复位、晶振时钟、存储器接口等最小系…

作者头像 李华
网站建设 2026/9/8 16:49:08

消除AI味:一套可复用的文本人性化改写方法

想让AI写的东西读着像个真人&#xff0c;这件事看起来不难&#xff0c;真做起来全是细节。我在日常内容生产里试过各种方法&#xff0c;从纯粹改词到重新搭结构&#xff0c;折腾了大半年&#xff0c;才慢慢总结出一套能稳定复用的套路。这套东西业内叫 humanizer&#xff0c;或…

作者头像 李华
网站建设 2026/9/8 16:48:37

SillyTavern 完整指南:如何十分钟搭好你的 AI 角色扮演前台

SillyTavern 完整指南&#xff1a;如何十分钟搭好你的 AI 角色扮演前台 【免费下载链接】SillyTavern LLM Frontend for Power Users. 项目地址: https://gitcode.com/GitHub_Trending/si/SillyTavern SillyTavern 是一个开源的 LLM 前端&#xff0c;负责把你本地的或云…

作者头像 李华