dubbo源碼分析--預熱warmup過程

阿飛Javaer,轉載請註明原創出處,謝謝!

前言

今天羣裏小夥伴黃曉峯VIVO諮詢一個問題:”dubbo接口怎麼做預熱呢,每次上線,都會有一小部分超時?”,熟悉JVM都知道,JVM重啓後有一段預熱過程,要運行一段時間,它的性能才能達到最佳狀態;阿里JVM團隊就針對這個缺陷進行了優化,其特性名曰:jwarmup,可以點擊Alibaba JVM創新提效 獲國際社區認可登臺JVM圈頂會,對jwarmup稍微瞭解;

另外,在阿里大神你假笨那裏瞭解到jwarmup的大概原理:針對上次JIT對應用的優化,主動去觸發JIT編譯優化,而不是等jvm運行一段時間自己去感知!

阿里大廠可以這麼做,我們小廠腫麼辦?事實上dubbo作者樑飛大神考慮到了這種情況,在dubbo中也引入了”warmup”特性(和阿里的jwarmup還是完全不一樣的),核心源碼在“com.alibaba.dubbo.rpc.cluster.loadbalance.AbstractLoadBalance.java”中:

protected int getWeight(Invoker<?> invoker, Invocation invocation) {
    // 先得到Provider的權重
    int weight = invoker.getUrl().getMethodParameter(invocation.getMethodName(), Constants.WEIGHT_KEY, Constants.DEFAULT_WEIGHT);
    if (weight > 0) {
        // 得到provider的啓動時間戳
        long timestamp = invoker.getUrl().getParameter(Constants.REMOTE_TIMESTAMP_KEY, 0L);
        if (timestamp > 0L) {
            // provider已經運行時間
            int uptime = (int) (System.currentTimeMillis() - timestamp);
            // 得到warmup的值,默認爲10分鐘
            int warmup = invoker.getUrl().getParameter(Constants.WARMUP_KEY, Constants.DEFAULT_WARMUP);
            // provider運行時間少於預熱時間,那麼需要重新計算權重weight(即需要降權)
            if (uptime > 0 && uptime < warmup) {
                weight = calculateWarmupWeight(uptime, warmup, weight);
            }
        }
    }
    return weight;
}

static int calculateWarmupWeight(int uptime, int warmup, int weight) {
    // 隨着provider的啓動時間越來越長,慢慢提升權重直到weight
    int ww = (int) ( (float) uptime / ( (float) warmup / (float) weight ) );
    return ww < 1 ? 1 : (ww > weight ? weight : ww);
}

warnup權重計算過程:

根據calculateWarmupWeight()方法實現可知,隨着provider的啓動時間越來越長,慢慢提升權重直到weight,且權重最小值爲1,所以:
如果provider運行了1分鐘,那麼weight爲10,即只有最終需要承擔的10%流量;
如果provider運行了2分鐘,那麼weight爲20,即只有最終需要承擔的20%流量;
如果provider運行了5分鐘,那麼weight爲50,即只有最終需要承擔的50%流量;
... ...

這裏需要注意的是,dubbo默認有3種負載均衡實現方式:隨機,輪詢,一致性哈希;其中一致性哈希是不受權重影響的,也就是說,如果選擇一致性哈希負載均衡,就不支持dubbo的預熱特性了;可以參考14.dubbo源碼-負載均衡,有對其進行分析;

問題

既然,dubbo有預熱功能,爲什麼每次重啓,還會有那麼多的超時呢?後來諮詢小夥伴黃曉峯VIVO,他們的dubbo是基於dubbox的自建分支,dubbox2.8.4和dubbo原生分支的代碼是有一點出入的:
dubbox&dubbo AbstractLoadBalance.java差異性

筆者查找Github上dubbo更新,從AbstractLoadBalance.java的提交記錄發現有過一次fix,記錄如下:
Fix warmup timestamp bug

修改記錄爲如下所示:
the commit

fix來源:https://github.com/apache/incubator-dubbo/commit/ed66afd9a38d80f839f0381fbd1dc1d3c068bc1c#diff-c5cb2df641f0a7d0553343c757425d2b

真相

真相原來如此,由於dubbox基於dubbo比較老的分支,而這個bug fix是committed on 10 Oct 2017;所以dubbox分支的bug依然存在。

既然提到dubbo預熱問題,另外一個優化點也可以參考一下,dubbo官方稱之爲延遲暴露

# 這個申明的含義是等spring容器啓動後過5s再暴露dubbo服務:
<dubbo:provider delay="5000"/>
或者延遲暴露某個接口:
<dubbo:service delay="5000" interface="com.alibaba.dubbo.demo.DemoService" ref="demoService" version="1.0.0"/>

驗證日誌如下–可以看到”Dubbo service server started”即dubbo服務啓動後,過了5s才暴露服務:

[28/04/18 05:40:59:059 CST] main  INFO support.DefaultListableBeanFactory: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@6b927fb: defining beans [dubbo-test,com.alibaba.dubbo.config.RegistryConfig,com.alibaba.dubbo.config.ProviderConfig,demoService,testService,com.alibaba.dubbo.demo.DemoService,com.alibaba.dubbo.demo.TestService]; root of factory hierarchy
[28/04/18 05:40:59:059 CST] main  INFO container.Main:  [DUBBO] Dubbo SpringContainer started!, dubbo version: 2.0.0, current host: 127.0.0.1
[2018-04-28 17:40:59] Dubbo service server started!
[28/04/18 05:41:04:004 CST] DelayExportServiceThread  INFO config.AbstractConfig:  [DUBBO] Export dubbo service com.alibaba.dubbo.demo.DemoService to local registry, dubbo version: 2.0.0, current host: 127.0.0.1
[28/04/18 05:41:04:004 CST] DelayExportServiceThread  INFO config.AbstractConfig:  [DUBBO] Export dubbo service com.alibaba.dubbo.demo.TestService to local registry, dubbo version: 2.0.0, current host: 127.0.0.1

總結

無論是dubbo的warmup特性還是延遲暴露服務,對生產環境都有很大的幫助,所以,趕緊做如下的優化吧:
1. 如果是dubbox分支,或者舊的dubbo分支,請修復warmup特性時間戳的問題;
2. 配置<dubbo:provider delay="5000"/>延遲暴露所有dubbo服務;

說明:按照dubbo的參數等價轉換特性,可以用-Ddubbo.provider.deplay代替,但是筆者跟蹤源碼發現這裏有個bug並已經提交了issue,請戳System property dubbo.service.delay invalid,所以老老實實用這種xml配置吧

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章