dubbo泛化引发的生产故障之dubbo隐藏的坑#

上个月公司zk集群发生了一次故障,然后要求所有项目组自检有无使用Dubbo编程式/泛化调用,强制使用@Reference生成Consumer。具体原因是线上某服务访问量在短时间大量访问zk并创建了240万+的节点,导致zk所有节点陆续崩溃导致,多个应用因无法连接到zk报错。原因是听说泛化调用时候,provider没启动,导致每次请求都在zk创建消费节点。

由于是和自己关联性不大的项目组,了解的并不是很清楚,但是想搞明白这个事情,因此就进行了如下实验:

试验1:泛化不使用缓存

dubbo泛化写法

public Result<Map> getProductGenericCache(ProductDTO dto) {
    ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>();
    ApplicationConfig application = new ApplicationConfig();
    application.setName("pangu-client-consumer-generic");
    // 连接注册中心配置
    RegistryConfig registry = new RegistryConfig();
    registry.setAddress("zookeeper://127.0.0.1:2181");
    // 服务消费者缺省值配置
    ConsumerConfig consumer = new ConsumerConfig();
    consumer.setTimeout(5000);
    consumer.setRetries(0);

    reference.setApplication(application);
    reference.setRegistry(registry);
    reference.setConsumer(consumer);
    reference.setInterface(org.pangu.api.ProductService.class); // 弱类型接口名
    //        reference.setVersion("");
    //        reference.setGroup("");
    reference.setGeneric(true); // 声明为泛化接口
    GenericService svc = reference.get();
    Object target = svc.$invoke("findProduct", new String[]{ProductDTO.class.getName()}, new Object[]{dto});//实际网关中,方法名、参数类型、参数是作为参数传入
    return Result.success((Map)target);
}

这个写法,就没有缓存reference,因此每次请求这个方法,就会在zk创建个消费节点(无论provider是否启动),请求量大的时候,就会导致zk所有节点陆续崩溃。使用泛化不缓存,这个估计稍微看了官方文档都不会出现这个错误。引发这次故障的这个应用功能,又不是初次上线,运行了一段时间了,生产有zk节点数监控,不然初次就发现这个问题了。因此基本可以排除对方是没有使用缓存的问题。

试验2:泛化使用缓存

@Override
public Result<Map> getProductGenericCache(ProductDTO dto) {
    ReferenceConfigCache referenceCache = ReferenceConfigCache.getCache();

    ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>();//缓存,否则每次请求都会创建一个ReferenceConfig,并在zk注册节点,最终可能导致zk节点过多影响性能
    ApplicationConfig application = new ApplicationConfig();
    application.setName("pangu-client-consumer-generic");
    // 连接注册中心配置
    RegistryConfig registry = new RegistryConfig();
    registry.setAddress("zookeeper://127.0.0.1:2181");

    // 服务消费者缺省值配置
    ConsumerConfig consumer = new ConsumerConfig();
    consumer.setTimeout(5000);
    consumer.setRetries(0);

    reference.setApplication(application);
    reference.setRegistry(registry);
    reference.setConsumer(consumer);
    reference.setInterface(org.pangu.api.ProductService.class); // 弱类型接口名
    //        reference.setVersion("");
    //        reference.setGroup("");
    reference.setGeneric(true); // 声明为泛化接口
    GenericService svc = referenceCache.get(reference);//cache.get方法中会缓存 Reference对象,并且调用ReferenceConfig.get方法启动ReferenceConfig
    Object target = svc.$invoke("findProduct", new String[]{ProductDTO.class.getName()}, new Object[]{dto});//实际网关中,方法名、参数类型、参数是作为参数传入
    return Result.success((Map)target);
}

在provider端无论是否启动,都只会在zk创建一个消费节点

试验3:设置服务检查为true,reference.setCheck(true);

排除了前面两个试验,又查看了下dubbo源码,泛化使用ReferenceConfig,那么无论如何都会执行ReferenceConfig.get(),代码如下

public synchronized T get() {
    if (destroyed) {
        throw new IllegalStateException("Already destroyed!");
    }
    if (ref == null) {
        init();
    }
    return ref;
}

ref为null,则执行初始化init,那么ref是怎么来的呢?是在init操作内由createProxy生成,createProxy代码如下

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值