生产问题-动态刷新nacos后会导致线程阻塞的情况及解决方案

情景回顾

最近生产环境出现微服务线程卡死的情况,导致业务无法正常执行,通过JStack排查是由于动态刷新nacos后会导致线程阻塞,现在对于这种情况作简单演示。

nacos说明

Nacos是一个较常使用的服务配置和发现的框架,如果使用不当确实可能会出现死锁,导致线程阻塞。不过,由于版本迭代,具体的场景会有差异。一般来说,如果发生死锁,多是由于资源竞争和不按顺序获取多个资源导致。

以下是一个理论上可能出现死锁的场景(虚拟示例),在动态刷新配置(如使用Spring Cloud Alibaba Nacos Config)时可能出现:

@RefreshScope
@Service
public class SomeService {

    @Value("${some.config}")
    private String someConfig;

    public void doSomething() {
        synchronized(someConfig) {
            // ... 执行一些操作
        }
    }
}

在如上代码中如果动态刷新了some.config配置,而多个线程进入了doSomething()并且检查到someConfig的更改,可能造成它们之间的相互阻塞。这尤其在代码同步块较大或其他 synchronized 块嵌套使用时更常见。

这里应用程序通过@RefreshScope注解用来实现配置自动更新。@RefreshScope设置在一个Bean上,当检测到配置更改时,Spring会尝试重新初始化这个Bean。假设在刷新这个Bean的过程中,另外一个线程正在调用doSomething()方法(因为它是同步的),这可能会导致死锁。

为了避免这种情况,在设计时应该确保:

  1. 外部配置和内部状态之间需要有清晰的分离。
  2. 在设计Bean的同步策略时要小心,避免在受Spring管理和需要动态刷新的Bean上使用synchronized。考虑使用其他同步机制。
  3. 审慎使用@RefreshScope以最小化使用其范围,并关注可能的Bean循环依赖。
  4. 如果遇到复杂的Bean依赖关系和多并发操作,建议增加适当的并发控制测试,以检测可能的死锁情况
  5. 最好不要在@Value注入的字段上使用synchronized关键字;对于需要排他控制的逻辑,采用其他并发工具类,如ReentrantLock或者利用java.util.concurrent下的其他并发类。
  6. Review代码,避免使用大的同步块,并适当拆分逻辑减小锁的粒度,尽量降低不同操作间的锁竞争
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值