定位解決dubbo-admin本地啟動很慢問題


場景

嘗試本地IDEA啟動dubbo-admin,連接到測試環境的zookeeper,查看各微服務情況。
等了幾分鍾發現仍未啟動成功,日志里不斷打印[DUBBO] Subscribe...信息。
而成功啟動應打印
Tomcat started on port(s): 7001 (http) with context path ''
Started DubboAdminApplication in xxx seconds...

分析

日志里一直在打印訂閱(subscribe)相關信息,而測試環境dubbo-admin的啟動卻很快,不到1分鍾啟動完成。
dubbo-admin里有個RegistryServerSync類,實現了InitializingBean,DisposableBean,NotifyListener3個接口,
其中在InitializingBeanafterPropertiesSet方法:

public void afterPropertiesSet() throws Exception {
    logger.info("Init Dubbo Admin Sync Cache...");
    registryService.subscribe(SUBSCRIBE, this);
}

其中registryService是注入到Spring容器的:

@Autowired
private RegistryService registryService;

在dubbo-admin應用的application.properties文件里配置了注冊中心類型和地址:

dubbo.registry.address=zookeeper://192.168.20.4:2181

通過Dubbo的SPI,接口RegistryService的實現類是ZookeeperRegistry,注意到它實現其父抽象類FailbackRegistry
doSubscribe方法中,是通過for循環遍歷服務逐個處理的,測試環境的zookeeper在阿里雲內網服務器上,本地公司內網與阿里雲內網
有大概20-30ms左右的延遲(通過ping命令和咨詢負責網絡運維的同事得知),而測試環境注冊的服務有幾百個,這是啟動慢的原因所在。

解決

思路: 自定義一個類跟ZookeeperRegistry類似,單線程遍歷處理改為多線程並發處理。

步驟:

  1. 新建MyZookeeperRegistry類繼承FailbackRegistry類,將原ZookeeperRegistry類的代碼拷過來進行修改
    關鍵代碼如下:
private ExecutorService es = Executors.newFixedThreadPool(50);
...
List<String> services = zkClient.addChildListener(root, zkListener);
if (services != null && !services.isEmpty()) {
    long totalStart = System.currentTimeMillis();
    for (String service : services) {
        service = URL.decode(service);
        anyServices.add(service);

        String finalService = service;
        es.submit(new Runnable() {
            @Override
            public void run() {
                long start = System.currentTimeMillis();
                subscribe(url.setPath(finalService).addParameters(Constants.INTERFACE_KEY, finalService,
                        Constants.CHECK_KEY, String.valueOf(false)), listener);
                logger.info("subscribe cost=" + (System.currentTimeMillis() - start) + "ms" + ",url=" + url);
            }
        });
    }

    es.shutdown();
    if (!es.awaitTermination(1, TimeUnit.MINUTES)) {
        es.shutdownNow();
    }
    logger.info("subscribe all done,cost=" + (System.currentTimeMillis() - totalStart) + "ms");
}

注:

  • 這里使用固定線程池用50個線程來並發處理訂閱
  • 通過線程池提供的shutdown,awaitTermination,shutdownNow3個方法來實現主線程等待子線程執行,設置等待超時時間,並且打印總耗時
  1. 修改application.properties配置文件,使用自定義的MyZookeeperRegistry
    dubbo.registry.address=zookeeper://xxx:2181
    修改為:
    dubbo.registry.address=myzookeeper://xxx:2181

  2. 重啟應用大概20多秒啟動成功

問題解決:)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM