使用MongoDB Reactive Streams Java API执行查询时偶现阻塞挂起问题
问题根因与排查方案
该偶现阻塞是MongoDB Reactive Streams Java驱动使用中的典型问题,按以下优先级排查即可解决:
1. Subscriber请求调用时序错误
Reactive Streams 规范强制要求:Subscriber 必须在 onSubscribe 回调中主动调用 Subscription#request(n) 方法向 Publisher 申请数据,才会触发后续的 onNext/onError/onComplete 回调。
90%以上的同类阻塞问题都是因为 request 调用存在竞态:如果你的 SettingSubscriber 实现中将 request 调用放在了 await() 执行之后,会直接触发死锁——await 在等待回调触发释放阻塞,而 Publisher 只有收到 request 请求才会推送事件触发回调。
正确的 onSubscribe 实现示例:
@Override public void onSubscribe(Subscription subscription) { this.subscription = subscription; // 必须第一时间调用request,不要放在任何阻塞逻辑之后 subscription.request(Long.MAX_VALUE); }
2. MongoDB连接池耗尽
如果存在未正确处理的订阅(比如订阅后未处理终止回调、游标未主动释放),会导致连接池中的连接被长期占用,新查询无法获取连接时就不会返回任何事件,一直处于等待状态。
排查步骤:
- 阻塞发生时采集MongoDB客户端连接池指标,确认是否达到最大连接数上限
- 检查全量查询逻辑,确保无论请求成功失败都最终触发游标释放,不要遗漏对
onError回调的处理
3. 阻塞工具实现缺陷
检查 await() 方法的实现逻辑:
- 如果基于
CountDownLatch实现,确认初始化计数和期望的回调触发次数匹配:如果只等待onComplete触发就设为1,不要和查询结果条数绑定,否则空查询结果会直接触发死锁 - 禁止使用无超时的无限等待,必须设置合理的超时时间,同时捕获
InterruptedException后要正确重置线程中断状态,不要吞掉中断异常
4. 驱动版本已知Bug
4.2.x及以下版本的MongoDB Reactive Streams驱动存在偶现的内部竞态Bug,会出现Publisher已生成结果但未推送给Subscriber的问题,建议直接升级到4.7.0及以上的稳定版。
内容的提问来源于stack exchange,提问作者gscaparrotti
相关产品推荐
相关产品推荐

