過載保護+異構服務器的負載均衡,怎麼設計?

負載均衡是指,將請求/數據分攤到多個操做單元上執行,關鍵在於均衡。程序員

然而,後端的服務器有可能硬件條件不一樣:後端

  • 若是對標低配的服務器「均勻」分攤負載,高配的服務器利用率會不足
  • 若是對標高配的服務器「均勻」分攤負載,低配的服務器會扛不住

可否根據異構服務器的處理能力來動態、自適應進行負載均衡,以及過載保護呢?服務器

負載均衡一般是怎麼作的?

過載保護+異構服務器的負載均衡,怎麼設計?
service層的負載均衡,通常是經過service鏈接池來實現的,調用方鏈接池會創建與下游服務多個鏈接,每次請求「隨機」獲取鏈接,來保證訪問的均衡性。架構

負載均衡、故障轉移、超時處理等細節也都是經過調用方鏈接池來實現的。負載均衡

調用方鏈接池可否,根據service的處理能力,動態+自適應的進行負載調度呢?

方案一:能夠經過「靜態權重」標識service的處理能力。

過載保護+異構服務器的負載均衡,怎麼設計?
最容易想到的方法,能夠爲每一個下游service設置一個「權重」,表明service的處理能力,來調整訪問到每一個service的機率,如上圖所示:ide

(1) 假設ip1,ip2,ip3的處理能力相同,能夠設置weight1=1,weight2=1,weight3=1,這樣三個service鏈接被獲取到的機率分別就是1/3,1/3,1/3,可以保證均衡訪問;優化

(2) 假設ip1的處理能力是ip2,ip3的處理能力的2倍,能夠設置weight1=2,weight2=1,weight3=1,這樣三個service鏈接被獲取到的機率分別就是2/4,1/4,1/4,可以保證處理能力強的service分到等比的流量,不至於資源浪費;設計

Nginx就具有相似的能力。blog

方案優勢:簡單粗暴,可以快速的實現異構服務器的負載均衡。ip

方案缺點:權重是固定的,沒法自適應動態調整,而不少時候,服務器的處理能力是很難用一個固定的數值量化。

方案二:經過「動態權重」標識service的處理能力。

如何來標識一個service的處理能力呢?
服務能不能處理得過來,該由調用方說了算:

  • 調用服務,快速處理,處理能力跟得上
  • 調用服務,處理超時,處理能力頗有可能跟不上了

如何來設計動態權重?
能夠這麼玩:
(1) 用一個動態權重,來標識每一個service的處理能力,默認初始處理能力相同,即分配給每一個service的機率相等;
(2) 每當service成功處理一個請求,認爲service處理能力足夠,權重動態+1;
(3) 每當service超時處理一個請求,認爲service處理能力可能要跟不上了,權重動態-10;
畫外音:
權重降低,會比權重上升更快。
爲了方便權重的處理,能夠把權重的範圍限定爲[0, 100],把權重的初始值設爲60分。

舉例說明:
假設service-ip1,service-ip2,service-ip3的動態權重初始值:

  • weight1=60
  • weight2=60
  • weight3=60
    剛開始時,請求分配給這3臺service的機率分別是60/180,60/180,60/180,即負載是均衡的。

隨着時間的推移:

  • 處理能力強的service成功處理的請求愈來愈多
  • 處理能力弱的service偶爾有超時

隨着動態權重的增減,權重會發生變化:

  • weight1=100
  • weight2=60
  • weight3=40
    那麼此時,請求分配給這3臺service的機率分別是100/200,60/200,40/200,即處理能力強的service會被分配到更多的流量。

那什麼是過載保護?

過載保護+異構服務器的負載均衡,怎麼設計?
如上圖所示,若是沒有過載保護:

  • 隨着外部負載的不斷升高,系統實際處理負載會增長
  • 外部負載升高到一個臨界值,系統會被壓垮,實際處理能力會降爲0
    畫外音:這就是所謂的「掉底」。

過載保護,是指當外部負載超過系統處理能力時,系統會進行自我保護,依然能對外提供有損的穩定服務。
過載保護+異構服務器的負載均衡,怎麼設計?
如上圖所示,若是進行了過載保護:

  • 隨着外部負載的不斷升高,系統實際處理負載會增長
  • 外部負載即便超過一個臨界值,系統不會被壓垮,而能保持必定的處理能力
    畫外音:外部負載無限大,系統也不會「掉底」。

那如何進行過載保護?

方案一:能夠經過「靜態權重」標識service的處理能力。

這是最簡易的方式,服務端設定一個負載閾值,超過這個閾值的請求壓過來,所有拋棄。
畫外音:這個方式不是特別優雅。

方案二:藉助「動態權重」來實施過載保護。

如同異構服務器負載均衡,仍然經過:

  • 成功處理加分(+1)
  • 處理超時扣分(-10)
    這種動態權重,來標識後端的處理能力。
    畫外音:仍然是在鏈接池層面實現的。

當一個服務端多次處理超時,權重不斷下降時,鏈接池只要實施一些策略,就可以對「疑似過載」的服務器進行降壓,而不用服務器「拋棄請求」這麼粗暴的實施過載保護。

應該實施什麼樣的策略,來對「疑似過載」的服務器進行降壓保護呢?

能夠這麼玩:
(1) 若是某一個服務器,連續3個請求都超時,即連續-10分三次,就能夠認爲,服務器處理不過來了,得給這個服務器喘一小口氣,因而設定策略:接下來的若干時間內,例如1秒,負載再也不分配給這個服務器;
畫外音:休息1秒後,再分給它。

(2) 若是某一個service的動態權重,降爲了0(休息了3次還超時),就能夠認爲,服務器徹底處理不過來了,得給這個服務器喘一大口氣,因而設定策略:接下來的若干時間內,例如1分鐘,請求再也不分配給這個服務器;
畫外音:根據經驗,此時服務器通常在fullGC,差很少1分鐘能回過神來。

這樣的話,不但能借助「動態權重」來實施動態自適應的異構服務器負載均衡,還能在客戶端層面更優雅的實施過載保護,在某個下游服務器快要響應不過來的時候,給其喘息的機會。

過載保護要注意什麼問題?

要防止過載保護引發服務器的雪崩,若是「總體負載」已經超過了「服務器集羣」的處理能力,怎麼轉移請求也是處理不過來的。這時,仍是得經過拋棄請求來實施自我保護。

總結

  • 負載均衡、故障轉移、超時處理一般是鏈接池層面來實施的
  • 異構服務器負載均衡,最簡單的方式是靜態權重法,缺點是沒法自適應動態調整
  • 動態權重法,能夠動態的根據服務器的處理能力來分配負載,須要有鏈接池層面的微小改動
  • 過載保護,是在負載太高時,服務器爲了保護本身,保證必定處理能力的一種自救方式
  • 動態權重法,還能夠用作服務器的過載保護
    過載保護+異構服務器的負載均衡,怎麼設計?

架構師之路-分享可落地的技術文章
相關推薦:
《GFS架構啓示》
《Google MapReduce解決什麼問題?》
《Google MapReduce巧妙優化思路?》
《程序員養女兒的四大要點!》

聽說,配圖值得轉。

相關文章
相關標籤/搜索