日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

面试官:高并发下重启服务,接口调用老是超时,你有什么解决办法?

發布時間:2025/3/16 编程问答 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 面试官:高并发下重启服务,接口调用老是超时,你有什么解决办法? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

今天文章內容來自一位朋友出去面試碰到的問題:

「了解 Dubbo 服務預熱過程嗎?詳細聊聊它的原理。」

這個問題朋友沒有很好答出來,因為之前也沒了解過。說實話一開始我只是大概知道這塊預熱的代碼位于何處,但是原理什么的還是沒有仔細去了解。

所以這次仔細去看了下代碼,查了一些 Github 這塊代碼提交記錄,終于搞明白這塊的原理,跟大家一起分享下。

預熱

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

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

其實服務預熱也是這個意思,服務剛啟動的時候將存在一段「磨合期」,這段期間服務運行狀態沒有達到最佳,如果一下子將服務流量提升到平常的狀態,可能會存在大量的請求超時或者瞬間將系統壓垮。

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

那為什么服務剛啟動的時候系統狀態沒有到達最佳狀態?

大概原因其實如下:

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

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

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

上面兩個過程是出于 JVM 系統層面的影響。

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

Dubbo 預熱實現方式

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

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

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

當服務消費者調用服務時,內部將會通過負載均衡組件選擇一個節點,進行服務調用。

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

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

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

這段代碼主要分為三步:

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

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

  • 根據已運行時間動態計算服務預熱過程的權重

  • 第三步動態權重計算方法如下:

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

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

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

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

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

    • Random LoadBalance :「加權隨機」策略

    • RoundRobin LoadBalance:「加權輪詢」策略

    • LeastActive LoadBalance:「最少活躍調用數」策略

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

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

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

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

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

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

    Dubbo 預熱歷史 bug-反復橫跳

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

    Dubbo 2.5.5 之前的版本

    在 Dubbo 2.5.5 之前的版本,AbstractLoadBalance#getWeight實現方式如下:

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

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

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

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

    Dubbo 2.7.2 預熱又失效了

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

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

    預熱代碼的隱藏 bug

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

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

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

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

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

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

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

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

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

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

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

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

    總結

    今天的文章主要介紹了服務預熱的作用,以及 Dubbo 服務預熱的實現方式。

    這個實現方式整體來說不是很難,簡單來說就是隨著運行時間逐漸提高權重,從而增加服務節點的流量。

    如果你當前使用框架并沒有這個功能,而你正需要服務預熱,可以參考 Dubbo 的實現方式。

    另外由于 Dubbo 歷史版本存在一些 Bug,如果各小伙伴需要使用服務預熱功能,需要注意避免使用以下版本:

    • 「Dubbo 2.5.5 之前的版本」

    • 「Dubbo 2.7.2/ 2.7.3」

    相關資料

  • https://github.com/apache/dubbo/issues/6242

  • https://github.com/apache/dubbo/issues/306

  • https://github.com/apache/dubbo/pull/4870

  • 有道無術,術可成;有術無道,止于術

    歡迎大家關注Java之道公眾號

    好文章,我在看??

    總結

    以上是生活随笔為你收集整理的面试官:高并发下重启服务,接口调用老是超时,你有什么解决办法?的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。