Java Spring Saga模式BFF网关线程耗尽:CPU内存正常但无法处理请求
Saga事务的同步阻塞编排
Saga模式下如果采用串行同步等待所有子事务完成,每个请求会占用线程直到整个Saga流程结束。哪怕核心服务的Socket超时正常,若子服务业务处理耗时久、Saga分支多,线程会被长时间占用,最终耗尽。
排查方向:梳理Saga编排逻辑,确认是否存在不必要的同步等待;统计每个子事务的实际处理耗时,定位慢操作环节。HTTP客户端连接池配置缺陷
虽然设置了Socket超时,但如果HTTP客户端(如RestTemplate、WebClient)的连接池最大连接数小于并发请求数,或连接回收策略不合理(比如连接未正确释放、空闲连接超时过长),会导致请求线程阻塞在获取连接的环节,无法释放。
排查方向:检查连接池参数(maxTotal、defaultMaxPerRoute等);监控连接池的活跃连接数、等待队列长度指标。应用线程池配置不匹配负载
Spring应用默认线程池(如Tomcat Connector线程池、@Async自定义线程池)若核心线程数、最大线程数设置过小,或队列容量过大导致请求堆积,当并发请求超过处理能力时,会出现线程耗尽。
排查方向:查看Tomcat的server.tomcat.threads.max等参数;检查Saga流程专用线程池的核心线程数、队列配置,确认是否存在队列饱和、线程不足的情况。未察觉的阻塞IO或锁等待
代码中存在同步文件IO、未设置查询超时的JDBC操作、未正确释放的分布式锁等阻塞逻辑,会让线程长时间处于WAITING/TIMED_WAITING状态,无法处理新请求。
排查方向:生成线程dump分析线程状态,定位阻塞代码块;检查JDBC连接的查询超时配置,确认分布式锁的释放逻辑。Saga补偿逻辑的阻塞与重试问题
补偿逻辑若采用同步执行且耗时较长,或重试机制不合理(无限重试、重试间隔过短),会占用大量线程处理补偿任务,挤占正常请求的线程资源。
排查方向:查看补偿逻辑的执行方式,是否可改为异步处理;检查补偿重试的次数、间隔配置,避免过度重试。请求上下文资源泄漏
ThreadLocal资源未在请求结束时清理,或数据库连接、HTTP连接等资源未正确释放,会导致线程被绑定无法复用,最终耗尽可用线程。
排查方向:检查ThreadLocal的使用场景,确认是否有清理逻辑;通过线程dump查看线程绑定的资源情况。同步等待外部事件的逻辑
Saga流程中若存在同步等待MQ消息、第三方回调的逻辑(比如用CountDownLatch阻塞线程),大量这类请求会导致线程长时间挂起,快速耗尽线程池。
排查方向:梳理Saga流程,确认是否存在同步等待外部事件的逻辑,评估是否可改为异步回调方式。
内容的提问来源于stack exchange,提问作者Praful Jha

