You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scala/Spark中Redisson调用Redis出现死锁问题求助

Redisson 3.9.1调用Redis死锁原因分析

问题场景

刚接触Scala与Spark技术栈,在Scala代码中通过Redisson 3.9.1调用Redis获取少量键数据时出现死锁,对应的线程栈信息如下:

"Attach Listener" #124 daemon prio=9 os_prio=0 tid=0x00007fbde8002800 nid=0x494e1 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Keep-Alive-Timer" #123 daemon prio=8 os_prio=0 tid=0x00007fbd68021000 nid=0x493d1 waiting on condition [0x00007fbb2fffe000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
        at java.lang.Thread.sleep(Native Method)
        at sun.net.www.http.KeepAliveCache.run(KeepAliveCache.java:172)
        at java.lang.Thread.run(Thread.java:748)

"ForkJoinPool-1-worker-5" #117 daemon prio=5 os_prio=0 tid=0x00007fbc9c87b000 nid=0x475ba waiting on condition [0x00007fbb1dbfc000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00007fc68d00ed50> (a java.util.concurrent.CountDownLatch$Sync)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:997)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1304)
        at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:231)
        at org.redisson.command.CommandAsyncService.get(CommandAsyncService.java:182)
        at org.redisson.RedissonKeys$2.iterator(RedissonKeys.java:127)
        at org.redisson.RedissonKeys$2.iterator(RedissonKeys.java:123)
        at org.redisson.BaseIterator.hasNext(BaseIterator.java:54)
        at scala.collection.convert.Wrappers$JIteratorWrapper.hasNext(Wrappers.scala:42)
        at scala.collection.Iterator$class.foreach(Iterator.scala:893)
        at scala.collection.AbstractIterator.foreach(Iterator.scala:1336)
        at scala.collection.IterableLike$class.foreach(IterableLike.scala:72)
        at scala.collection.AbstractIterable.foreach(Iterable.scala:54)
        at scala.collection.TraversableLike$class.filterImpl(TraversableLike.scala:247)
        at scala.collection.TraversableLike$class.filterNot(TraversableLike.scala:267)
        at scala.collection.AbstractTraversable.filterNot(Traversable.scala:104)
        at com.mycomosi.eaa.common.infrastructure.topology.store.TopologyStoreEntityService$$anonfun$getTopologyInstanceIdsExcludingVersion$1$$anonfun$apply$7.apply(TopologyStoreEntityService.scala:73)
        at com.mycomosi.eaa.common.infrastructure.topology.store.TopologyStoreEntityService$$anonfun$getTopologyInstanceIdsExcludingVersion$1$$anonfun$apply$7.apply(TopologyStoreEntityService.scala:70)
        at scala.collection.immutable.Set$Set1.foreach(Set.scala:94)
        at com.mycomosi.eaa.common.infrastructure.topology.store.TopologyStoreEntityService$$anonfun$getTopologyInstanceIdsExcludingVersion$1.apply(TopologyStoreEntityService.scala:70)
        at com.mycomosi.eaa.common.infrastructure.topology.store.TopologyStoreEntityService$$anonfun$getTopologyInstanceIdsExcludingVersion$1.apply(TopologyStoreEntityService.scala:69)
        at scala.collection.Iterator$class.foreach(Iterator.scala:893)
        at scala.collection.AbstractIterator.foreach(Iterator.scala:1336)

原因分析

从线程栈核心调用链可定位问题根因:

  1. 线程阻塞本质:ForkJoinPool-1-worker-5线程卡在CountDownLatch.await(),等待CommandAsyncService.get()中的计数门闩释放,但对应的Redis异步命令回调从未触发,导致线程永久等待。
  2. 版本缺陷:Redisson 3.9.1属于老旧版本,存在已知的异步回调异常问题——当Redis连接超时、网络波动或命令执行异常时,异步任务的回调逻辑无法正确触发,CountDownLatch无法计数到0,线程陷入死锁。
  3. 线程模型冲突:Spark任务运行在ForkJoinPool线程池中,Redisson异步操作依赖自身线程池。在ForkJoin线程中同步调用get()阻塞等待异步结果,可能因线程资源耗尽、上下文类加载冲突,导致Redisson回调线程无法正常执行。
  4. 迭代器异步加载bug:RedissonKeys的迭代器采用异步加载key的方式,老版本该逻辑在并发场景下存在线程阻塞问题,结合Scala的JIteratorWrapper包装后,遍历操作触发的同步等待进一步放大了问题。

解决方案建议

  • 升级Redisson版本:直接升级到3.17.x及以上稳定版本,该版本修复了大量线程阻塞和异步回调相关的bug。
  • 避免同步阻塞调用:在Spark线程中不要直接调用Redisson异步方法的get(),改用异步回调(如whenComplete)或将Redisson操作提交到独立线程池中执行。
  • 优化Redis连接配置:检查Redisson连接池的最大连接数、超时时间设置,确保连接资源充足,同时确认Redis服务正常、网络无波动。
  • 替换迭代器查询方式:改用Redisson的同步批量查询API(如getKeysByPattern)先获取所有目标key,再进行遍历,避免迭代器异步加载带来的阻塞风险。

内容的提问来源于stack exchange,提问作者Chandan Gawri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 04:05:28