资讯动态

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

发布时间:2026/9/8 16:53:52 来源:尧图企业网站定制
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/redissonRedisson 事务提交成功了主库数据是对的但 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_100199仅缓存加锁未下发 B 本地缓存旧值 ← 未提交不可见正常 commit() ──────── 执行写入、释放锁 经 topic 广播失效/新值 ──────────────────────── B 收到后刷新本地缓存 B 恰好断连/消息延迟时B 一直是旧值RLocalCachedMap 事务提交后的失效广播时序延迟窗口与消息丢失点三种场景三种打法小写入量、键少提交后强制刷新写 QPS 在一百以内、缓存键只有几百个比如内部工具、低频库存别折腾策略用默认 INVALIDATE 加提交后强制刷新就够因为 key 少整份失效的代价可以忽略。RLocalCachedMapString, 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 把完整 keyvalue 广播给所有实例读端无需回 Redis 查 LocalCachedMapOptionsString, Integer options LocalCachedMapOptions.String, Integerdefaults() .syncStrategy(SyncStrategy.UPDATE) .reconnectionStrategy(ReconnectionStrategy.LOAD) .evictionPolicy(EvictionPolicy.LRU) .cacheSize(1000); RLocalCachedMapString, 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 加 valuevalue 超过 1KB 时带宽随实例数成倍放大这种场景退回 INVALIDATE让读端自己回源。失效边界写频率上来后广播消息开始堆积或业务要求提交后立刻读到的必须是新值说明本地缓存已经不适合这条链路转场景 C。高并发写、强一致放弃本地缓存秒杀、库存扣减、金融类读接口返回一个旧值就是资损事故这类链路里 RLocalCachedMap 本身就是错误工具因为本地缓存的失效是最终一致的而扣减要求强一致。RLock lock redisson.getLock(stock_lock:p_1001); if (!lock.tryLock(1, 3, TimeUnit.SECONDS)) { throw new IllegalStateException(扣减繁忙稍后重试); } try { // 扣减链路用普通 map彻底绕开本地缓存 RMapString, 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.mdreconnectionStrategyLOAD断连重连后补刷漏掉的失效消息修不恢复client-side-caching.mdcacheSize1000–100000 表示无上限-1 表示永不缓存collections.mdtransaction timeout5s超时未 commit 自动回滚防锁悬挂transactions.mdresponseTimeout3scommit 等 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),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价