业务: 项目启动时,需要从redis中获取一个业务数据
出现问题: 从redis获取数据时出现卡死现象,项目无法正常启动.
环境配置:
Springboot-data-redis 2.3.5版本
整个项目中依赖较多较为复杂(成熟项目)
排查过程
debug源码
从redisTemplate.get()方法一直debug下去,发现获取数据卡在getConnection的地方,也就是客户端向redis服务端获取连接的时候
过一段时间后出现异常(复现该问题时出现异常输出,第一环境一直在假死状态,并未输出异常)
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'scopedTarget.defaultTraceSampler' defined in class path resource [org/springframework/cloud/sleuth/sampler/SamplerAutoConfiguration$RefreshScopedSamplerConfiguration.class]: Unsatisfied dependency expressed through method 'defaultTraceSampler' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationNotAllowedException: Error creating bean with name 'spring.sleuth.sampler-org.springframework.cloud.sleuth.sampler.SamplerProperties': Singleton bean creation not allowed while singletons of this factory are in destruction (Do not request a bean from a BeanFactory in a destroy method implementation!)
同时查看线程状态发现线程状态一直在wait状态
猜测卡死现象是因为出现了锁的情况,同时结合百度搜索此类问题,看了一些博客后如: https://blog.csdn.net/x275920/article/details/124078274
但并非我遇到的情况,我们并未使用lettuce连接池,同时服务端也不是集群,只是一个单点
但别人的排查思路也挺有帮助的
解决
最终我尝试将一个一个的涉及到的jar包一个一个去除,再去除到sleuth的时候,奇迹出现了,项目启动没有任何问题,redis也是正常情况.
至此,先定位到问题所在: redis和sleuth出现冲突
再次百度...
https://blog.csdn.net/weixin_44743245/article/details/120813121
这个里面写的就比较全了
总结以下: 其实就是死锁,main线程,lettute线程,上面报错的这个bean scopedTarget.defaultTraceSampler 这三个形成了一个死锁
main拿着singletonObjects的锁,等着lettute来唤醒,luttute获取连接的时候由于sleuth要采样,需要创建scopedTarget.defaultTraceSampler,这个bean创建又依赖于singletonObjects,就这样锁上了.
知道问题之后,解决办法就好搞多了
如上文文章中所说:
- 使用spring.sleuth.redis.enabled=false来禁用sleuth的redis采样功能(我采用的,因为链路追踪暂时没用)
- 排除TraceRedisAutoConfiguration.class(这个方案类似1),因为配置了enabled=false就自动不注入该bean了
- 自定义采样器,来避免死锁,如果以后必要要采样redis,那可能就需要考虑这种方案了 暂记.
总结
排查这个问题的过程中也尝试了改造为lettute连接池的方式,虽然并没有解决问题,也是对redis有了更深入的了解.
搜解决方案也是需要先定位到问题的,不然只搜redis卡死虽然会出来一堆文章,但是其实并不是你遇到的问题,必须要大概能定位到问题的所在,才能更好的结合搜索引擎.比如本次排查过程中,一开始并没有注意到sleuth的问题,一顿搜索其实没啥用,在确定了是因为sleuth的问题后,再针对性的搜索问题就能很快得到答案.
同时也大概了解了一下sleuth的功能.
总结完毕!