溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何解決高并發(fā)下重啟服務接口調(diào)用老是超時的問題

發(fā)布時間:2021-10-23 15:57:56 來源:億速云 閱讀:220 作者:iii 欄目:開發(fā)技術

這篇文章主要講解了“如何解決高并發(fā)下重啟服務接口調(diào)用老是超時的問題”,文中的講解內(nèi)容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“如何解決高并發(fā)下重啟服務接口調(diào)用老是超時的問題”吧!

預熱

首先我們來看下什么是服務預熱?

先舉一個生活的中的例子,買過新車的同學應該知道新車都有一個磨合期的,大概開個一兩千公里之后,才能達到最佳的狀態(tài)。

其實服務預熱也是這個意思,服務剛啟動的時候?qū)⒋嬖谝欢巍改ズ掀凇?,這段期間服務運行狀態(tài)沒有達到最佳,如果一下子將服務流量提升到平常的狀態(tài),可能會存在大量的請求超時或者瞬間將系統(tǒng)壓垮。

如何解決高并發(fā)下重啟服務接口調(diào)用老是超時的問題

所以服務剛啟動的時候我們要慢慢增加的流量,直到一段時間后增加到閾值的上限,給系統(tǒng)一個「預熱過程」,讓其運行狀態(tài)到達最佳。

如何解決高并發(fā)下重啟服務接口調(diào)用老是超時的問題

那為什么服務剛啟動的時候系統(tǒng)狀態(tài)沒有到達最佳狀態(tài)?

大概原因其實如下:

Java 應用存在一個類加載的過程,而這個過程是按需加載的。即服務剛啟動時候,JVM 只加載了啟動過程必需的類。

我們自己所需要的類,直到服務被調(diào)用之后才會被真正的加載。

另外對于一些「熱點代碼」,JVM 將會使用 JIT 編譯器編譯成本地代碼,提高運行速度。

上面兩個過程是出于 JVM 系統(tǒng)層面的影響。

除此之外,我們服務系統(tǒng)中可能會需要一些緩存資源。剛啟動的時候,由于資源不存在,服務需要去加載這些資源。

Dubbo 預熱實現(xiàn)方式

好了,了解完預熱是咋回事后,我們回到正題,來看下 Dubbo 是如何實現(xiàn)預熱的。

首先我們來看下 Dubbo 服務模型:

如何解決高并發(fā)下重啟服務接口調(diào)用老是超時的問題

服務提供者啟動之后將會把節(jié)點相關信息注冊到注冊中心,服務消費者通過注冊中心就可以及時獲取所有的服務節(jié)點。

當服務消費者調(diào)用服務時,內(nèi)部將會通過負載均衡組件選擇一個節(jié)點,進行服務調(diào)用。

如上圖所示,假設 B 節(jié)點服務剛啟動,其需要一個預熱過程,這就需要服務消費者逐漸將流量分發(fā)給 B 節(jié)點。

下面我們就從 Dubbo 源碼出發(fā),觀察服務預熱具體實現(xiàn)方式,具體源碼位于 AbstractLoadBalance#getWeight

如何解決高并發(fā)下重啟服務接口調(diào)用老是超時的問題

ps: 當前源碼 Dubbo 版本為2.7.4,低于這個版本代碼實現(xiàn)存在少量差異,詳情見下文。

這段代碼主要分為三步:

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術社區(qū)

  2. 獲取服務提供者啟動時間 timestamp

  3. 使用當前時間減去服務提供者啟動時間,計算服務提供者已運行時間 uptime

  4. 根據(jù)已運行時間動態(tài)計算服務預熱過程的權(quán)重

第三步動態(tài)權(quán)重計算方法如下:

如何解決高并發(fā)下重啟服務接口調(diào)用老是超時的問題

這里計算方式其實很簡單,簡單來說服務運行時間越久,權(quán)重越高,直到正常權(quán)重。

假如服務提供者已運行 1 分鐘,那么 weight 最終結(jié)果為 10 。

假如服務提供者已運行 5 分鐘,那么 weight 最終結(jié)果為 50 。

假如服務提供者已運行 11 分鐘,超過默認預熱時間的閾值 10分 鐘,那么將不會再計算,直接返回 weight 默認權(quán)重。

這里我們需要注意的是,Dubbo 默認提供五種負載均衡的策略:

  • Random LoadBalance :「加權(quán)隨機」策略

  • RoundRobin LoadBalance:「加權(quán)輪詢」策略

  • LeastActive LoadBalance:「最少活躍調(diào)用數(shù)」策略

  • ConsistentHash LoadBalance:「一致性 Hash」 策略

  • ShortestResponse LoadBalance:「最短響應時間」策略

「ShortestResponse LoadBalance」 策略小伙伴們可能會比較陌生,官方文檔中并沒有提到這個策略。

其實這個是 Dubbo 2.7.7 版本新增的負載均衡策略,官方文檔估計還沒更新。

如何解決高并發(fā)下重啟服務接口調(diào)用老是超時的問題

ps:感興趣的小伙伴,可以去修改下官方的文檔,增加這個新的負載均衡的策略,為開源獻出我們的一份力量。

回到正文,從AbstractLoadBalance#getWeight調(diào)用關系可以看到,「ConsistentHash LoadBalance」  實現(xiàn)類是不支持服務預熱,這點需要注意一下。

如何解決高并發(fā)下重啟服務接口調(diào)用老是超時的問題

Dubbo 預熱歷史 bug-反復橫跳雖然 Dubbo 預熱的相關代碼,總體看起來不是很難,但是歷史版本還是存在幾個 Bug,導致預熱失效。

Dubbo 2.5.5 之前的版本

在 Dubbo 2.5.5 之前的版本,AbstractLoadBalance#getWeight實現(xiàn)方式如下:

如何解決高并發(fā)下重啟服務接口調(diào)用老是超時的問題

這個版本跟現(xiàn)在代碼一樣,都是從節(jié)點的 timestamp獲取服務啟動時間。不過這個版本存在一些問題,Dubbo  沒有把服務提供者啟動時間傳給消費者,導致這里獲取 timestamp是消費者啟動時間,這樣就導致預熱失效。

等到 Dubbo 2.5.6 ,修復這個問題,源碼如下:

如何解決高并發(fā)下重啟服務接口調(diào)用老是超時的問題

這個版本將服務提供者啟動時間單獨保存在 remote.timestamp 屬性中,源碼位于 ClusterUtils#mergeUrl

如何解決高并發(fā)下重啟服務接口調(diào)用老是超時的問題

通過這種方式修復預熱失效的問題。

Dubbo 2.7.2 預熱又失效了

當 Dubbo 版本升級到 2.7.2 ,這個預熱失效 Bug 又回來了。帶來這個問題主要原因是ClusterUtils#mergeUrl  源碼中清除了remote.timestamp,轉(zhuǎn)而統(tǒng)一使用 timestamp保存服務啟動時間。

如何解決高并發(fā)下重啟服務接口調(diào)用老是超時的問題

但是呢,由于修改沒有徹底, AbstractLoadBalance#getWeight還是依然使用 remote.timestamp  獲取服務啟動時間,這就導致預熱失效。

預熱代碼的隱藏 bug

這個 Bug 在Dubbo 2.7.4 版本被徹底修復,另外還順帶優(yōu)化了代碼中存在缺陷。

先看下原先的代碼中國缺陷,原先預熱代碼實現(xiàn)采用如下方式計算服務啟動運行的時間。

int uptime = (int) (System.currentTimeMillis() - timestamp);

但是這里存在一個問題,如果服務提供者與消費者兩端時鐘是不一致,服務提供者啟動時間很有可能會大于消費者本地時間。

這種情況,uptime 計算結(jié)果為一個負值,這就會導致權(quán)重將使用配置的默認值,預熱也失效了。

所以針對這種情況 「@aftersss」 提供了修復的方案,加入相關的判斷,當 uptime為負值的時候,直接返回權(quán)重 1。

不過在 「Code review」 過程中,「@beiwei30」 覺得不用加入額外 if 判斷,可以直接使用 Math.max兼容。

如何解決高并發(fā)下重啟服務接口調(diào)用老是超時的問題

不過這樣修改,還是存在一個問題:Integer 精度丟失問題。

如何解決高并發(fā)下重啟服務接口調(diào)用老是超時的問題

如果此時 System.currentTimeMillis() = 1566209746000(2019-08-19 18:15:46),而  timestamp = 1561914711000(2019-07-01 01:11:51),當兩者差值為:「4295035000」。

這是一個遠大于 Integer.MAX_VALUE的值,所以在 long 轉(zhuǎn)為 int 時候精度丟失,導致最后實際得到 int 值為  「67704」。

而這個值小于服務預熱的默認時間(10 * 60 * 1000),所以進入動態(tài)計算權(quán)重環(huán)節(jié),最終將得到一個比較小的權(quán)重,這就導致「假預熱」。

所以最后還是采用 「@aftersss」 修復的方案,采用 long 類型存儲時間戳計算結(jié)果,最終優(yōu)化代碼如下:

如何解決高并發(fā)下重啟服務接口調(diào)用老是超時的問題

感謝各位的閱讀,以上就是“如何解決高并發(fā)下重啟服務接口調(diào)用老是超時的問題”的內(nèi)容了,經(jīng)過本文的學習后,相信大家對如何解決高并發(fā)下重啟服務接口調(diào)用老是超時的問題這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI