📌 踩坑记录:Spring Cloud Sleuth 引入导致服务启动死锁问题
🧭 背景
在某项目中,因需接入链路追踪功能,引入了如下依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
项目中存在 Redis 相关组件(如 Lettuce、Redisson),且有类在初始化阶段调用 Redis 操作。
🧨 问题现象
服务启动过程中阻塞卡死,应用长时间停留在启动阶段,无明显报错。
通过 JStack 分析线程堆栈,发现如下特征:
- 出现大量线程阻塞在
brave.Tracer
、Sampler
、BraveTracing
等相关调用; - Redis 操作线程
lettuce-nioEventLoop-*
卡在 bean 初始化相关方法; - 典型堆栈如下(关键片段):
at brave.sampler.Sampler$$EnhancerBySpringCGLIB...
at brave.Tracer.nextSpan(Tracer.java:502)
at io.lettuce.core.tracing.BraveTracing$BraveTracer.nextSpan...
🔍 说明 Sleuth 在 Redis 客户端初始化过程中尝试注入链路追踪逻辑,引发 Bean 加载死锁。
🔍 原因分析
1. Sleuth 默认启用 Redis 链路追踪
引入 spring-cloud-starter-sleuth
后,Spring 会自动激活:
org.springframework.cloud.sleuth.instrument.redis.TraceLettuceAutoConfiguration
该类会为 Lettuce Redis 客户端注入 BraveTracing
,以实现命令级链路追踪。
2. Redis 客户端线程在初始化阶段触发了 tracing 逻辑
在部分 Redis 使用场景中(例如初始化阶段访问 Redis,或类中定义 Redis 操作作为 static 变量等),Redis 客户端(Netty I/O 线程)触发了 tracing 调用。
此时 Sleuth 内部需要从 Spring 容器中获取:
Tracer
Sampler
BeanFactory
等
而这些 bean 此时可能尚未完成初始化,导致线程相互等待、卡死,最终表现为启动死锁。
✅ 解决方案
在 application.yml
中加入以下配置,彻底关闭 Sleuth 对 Redis 的 tracing 自动注入:
spring:
sleuth:
redis:
enabled: false
✳️ 效果
该配置会阻止 TraceLettuceAutoConfiguration
被加载,避免将 Sleuth 的 tracing 注入 Lettuce,进而彻底解除死锁隐患。
🧪 验证方式
- 启动应用时,观察 Redis 是否仍有 BraveTracing 相关日志;
- 使用 JStack 验证不再出现
brave.Tracer
、Sampler
、lettuce
tracing 调用堆栈; - 启动速度显著恢复正常。
🎯 总结建议
项目建议项 | 说明 |
---|---|
✅ 默认关闭 Redis tracing | 如无实际链路追踪需求,可关闭,避免隐性死锁 |
✅ Redis 初始化应避免过早访问 | 不应在静态代码块或构造方法中访问 Redis |
✅ 检查 Sleuth 自动配置副作用 | 尤其关注 Kafka、RocketMQ、Feign、Async、Redis 等组件 |
📁 附件参考配置(最终保留)
spring:
sleuth:
redis:
enabled: false
如需进一步排查其他 tracing 问题(Kafka、Redisson 等),建议开启 debug log 或 JStack 分析 bean 加载情况。