20. dubbo源碼-預(yù)熱warmup過程

阿飛Javaer,轉(zhuǎn)載請(qǐng)注明原創(chuàng)出處,謝謝!

前言

今天群里小伙伴黃曉峰VIVO咨詢一個(gè)問題:"dubbo接口怎么做預(yù)熱呢,每次上線,都會(huì)有一小部分超時(shí)?",熟悉JVM都知道,JVM重啟后有一段預(yù)熱過程,要運(yùn)行一段時(shí)間,它的性能才能達(dá)到最佳狀態(tài);阿里JVM團(tuán)隊(duì)就針對(duì)這個(gè)缺陷進(jìn)行了優(yōu)化,其特性名曰:jwarmup,可以點(diǎn)擊Alibaba JVM創(chuàng)新提效 獲國(guó)際社區(qū)認(rèn)可登臺(tái)JVM圈頂會(huì),對(duì)jwarmup稍微了解;

另外,在阿里大神你假笨那里了解到j(luò)warmup的大概原理:針對(duì)上次JIT對(duì)應(yīng)用的優(yōu)化,主動(dòng)去觸發(fā)JIT編譯優(yōu)化,而不是等jvm運(yùn)行一段時(shí)間自己去感知!

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

protected int getWeight(Invoker<?> invoker, Invocation invocation) {
    // 先得到Provider的權(quán)重
    int weight = invoker.getUrl().getMethodParameter(invocation.getMethodName(), Constants.WEIGHT_KEY, Constants.DEFAULT_WEIGHT);
    if (weight > 0) {
        // 得到provider的啟動(dòng)時(shí)間戳
        long timestamp = invoker.getUrl().getParameter(Constants.REMOTE_TIMESTAMP_KEY, 0L);
        if (timestamp > 0L) {
            // provider已經(jīng)運(yùn)行時(shí)間
            int uptime = (int) (System.currentTimeMillis() - timestamp);
            // 得到warmup的值,默認(rèn)為10分鐘
            int warmup = invoker.getUrl().getParameter(Constants.WARMUP_KEY, Constants.DEFAULT_WARMUP);
            // provider運(yùn)行時(shí)間少于預(yù)熱時(shí)間,那么需要重新計(jì)算權(quán)重weight(即需要降權(quán))
            if (uptime > 0 && uptime < warmup) {
                weight = calculateWarmupWeight(uptime, warmup, weight);
            }
        }
    }
    return weight;
}

static int calculateWarmupWeight(int uptime, int warmup, int weight) {
    // 隨著provider的啟動(dòng)時(shí)間越來越長(zhǎng),慢慢提升權(quán)重直到weight
    int ww = (int) ( (float) uptime / ( (float) warmup / (float) weight ) );
    return ww < 1 ? 1 : (ww > weight ? weight : ww);
}

warnup權(quán)重計(jì)算過程:

根據(jù)calculateWarmupWeight()方法實(shí)現(xiàn)可知,隨著provider的啟動(dòng)時(shí)間越來越長(zhǎng),慢慢提升權(quán)重直到weight,且權(quán)重最小值為1,所以:
如果provider運(yùn)行了1分鐘,那么weight為10,即只有最終需要承擔(dān)的10%流量;
如果provider運(yùn)行了2分鐘,那么weight為20,即只有最終需要承擔(dān)的20%流量;
如果provider運(yùn)行了5分鐘,那么weight為50,即只有最終需要承擔(dān)的50%流量;
... ...

這里需要注意的是,dubbo默認(rèn)有3種負(fù)載均衡實(shí)現(xiàn)方式:隨機(jī),輪詢,一致性哈希;其中一致性哈希是不受權(quán)重影響的,也就是說,如果選擇一致性哈希負(fù)載均衡,就不支持dubbo的預(yù)熱特性了;可以參考14.dubbo源碼-負(fù)載均衡,有對(duì)其進(jìn)行分析;

問題

既然,dubbo有預(yù)熱功能,為什么每次重啟,還會(huì)有那么多的超時(shí)呢?后來咨詢小伙伴黃曉峰VIVO,他們的dubbo是基于dubbox的自建分支,dubbox2.8.4和dubbo原生分支的代碼是有一點(diǎn)出入的:

dubbox&dubbo AbstractLoadBalance.java差異性

筆者查找Github上dubbo更新,從AbstractLoadBalance.java的提交記錄發(fā)現(xiàn)有過一次fix,記錄如下:

Fix warmup timestamp bug

修改記錄為如下所示:


the commit

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

真相

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

既然提到dubbo預(yù)熱問題,另外一個(gè)優(yōu)化點(diǎn)也可以參考一下,dubbo官方稱之為延遲暴露

# 這個(gè)申明的含義是等spring容器啟動(dòng)后過5s再暴露dubbo服務(wù):
<dubbo:provider delay="5000"/>
或者延遲暴露某個(gè)接口:
<dubbo:service delay="5000" interface="com.alibaba.dubbo.demo.DemoService" ref="demoService" version="1.0.0"/>

驗(yàn)證日志如下--可以看到"Dubbo service server started"即dubbo服務(wù)啟動(dòng)后,過了5s才暴露服務(wù):

[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

總結(jié)

無論是dubbo的warmup特性還是延遲暴露服務(wù),對(duì)生產(chǎn)環(huán)境都有很大的幫助,所以,趕緊做如下的優(yōu)化吧:

  1. 如果是dubbox分支,或者舊的dubbo分支,請(qǐng)修復(fù)warmup特性時(shí)間戳的問題;
  2. 配置<dubbo:provider delay="5000"/>延遲暴露所有dubbo服務(wù);

說明:按照dubbo的參數(shù)等價(jià)轉(zhuǎn)換特性,<dubbo:provider delay="5000"/>可以用-Ddubbo.provider.deplay=5000代替,但是筆者跟蹤源碼發(fā)現(xiàn)這里有個(gè)bug并已經(jīng)提交了issue,請(qǐng)戳System property dubbo.service.delay invalid,所以目標(biāo)老老實(shí)實(shí)用<dubbo:provider delay="5000"/>這種xml配置吧

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容