在進入主題以前,我想先和你分享一個需求,這是咱們公司的業務部門給咱們提的。
算法
他們反饋的問題是這樣的:有一次碰上流量高峯,他們忽然發現線上服務的可用率下降了,通過排查發現,是由於其中有幾臺機器比較舊了。當時最先申請的一批容器配置比較低,縮容的時候留下了幾臺,當流量達到高峯時,這幾臺容器因爲負載過高,就扛不住壓力了。業務問咱們有沒有好的服務治理策略?後端
業務部門問題示意圖這個問題其實挺好解決的,咱們當時給出的方案是:在治理平臺上調低這幾臺機器的權重,這樣的話,訪問的流量天然就減小了。但業務接着反饋了,說:當他們發現服務可用率下降的時候,業務請求已經受到影響了,這時再如此解決,須要時間啊,那這段時間裏業務可能已經有損失了。緊接着他們就提出了需求,問:RPC 框架有沒有什麼智能負載的機制?可否及時地自動控制服務節點接收到的訪問量?服務器
這個需求其實很合理,這也是一個比較廣泛的問題。確實,雖然說咱們的服務治理平臺可以動態地控制線上服務節點接收的訪問量,但當業務方發現部分機器負載太高或者響應變慢的時候再去調整節點權重,真的極可能已經影響到線上服務的可用率了。網絡
看到這兒,你有沒有想到什麼好的處理方案呢?接下來,咱們就以這個問題爲背景,一塊兒看看 RPC 框架的負載均衡。app
什麼是負載均衡?負載均衡
我先來簡單地介紹下負載均衡。當咱們的一個服務節點沒法支撐現有的訪問量時,咱們會部署多個節點,組成一個集羣,而後經過負載均衡,將請求分發給這個集羣下的每一個服務節點,從而達到多個服務節點共同分擔請求壓力的目的。框架
負載均衡示意圖負載均衡主要分爲軟負載和硬負載,軟負載就是在一臺或多臺服務器上安裝負載均衡的軟件,如 LVS、Nginx 等,硬負載就是經過硬件設備來實現的負載均衡,如 F5 服務器等。負載均衡的算法主要有隨機法、輪詢法、最小鏈接法等。ide
我剛纔介紹的負載均衡主要仍是應用在 Web 服務上,Web 服務的域名綁定負載均衡的地址,經過負載均衡將用戶的請求分發到一個個後端服務上。性能
RPC 框架中的負載均衡spa
那 RPC 框架中的負載均衡是否是也是如此呢?和我上面講的負載均衡,你以爲會有區別嗎?
爲何不經過 DNS 來實現「服務發現」?爲何不採用添加負載均衡設備或者 TCP/IP 四層代理,域名綁定負載均衡設備的 IP 或者四層代理 IP 的方式?
個人回答是這種方式會面臨這樣幾個問題:
搭建負載均衡設備或 TCP/IP 四層代理,須要額外成本;
請求流量都通過負載均衡設備,多通過一次網絡傳輸,會額外浪費一些性能;
負載均衡添加節點和摘除節點,通常都要手動添加,當大批量擴容和下線時,會有大量的人工操做,「服務發現」在操做上是個問題;
咱們在服務治理的時候,針對不一樣接口服務、服務的不一樣分組,咱們的負載均衡策略是須要可配的,若是你們都通過這一個負載均衡設備,就不容易根據不一樣的場景來配置不一樣的負載均衡策略了。
我相信看到這兒,你應該已經知道了 RPC 實現的負載均衡所採用的策略與傳統的 Web 服務實現負載均衡所採用策略的不一樣之處了。
RPC 的負載均衡徹底由 RPC 框架自身實現,RPC 的服務調用者會與「註冊中心」下發的全部服務節點創建長鏈接,在每次發起 RPC 調用時,服務調用者都會經過配置的負載均衡插件,自主選擇一個服務節點,發起 RPC 調用請求。
RPC框架負載均衡示意圖RPC 負載均衡策略通常包括隨機權重、Hash、輪詢。固然,這仍是主要看 RPC 框架自身的實現。其中的隨機權重策略應該是咱們最經常使用的一種了,經過隨機算法,咱們基本能夠保證每一個節點接收到的請求流量是均勻的;同時咱們還能夠經過控制節點權重的方式,來進行流量控制。好比咱們默認每一個節點的權重都是 100,但當咱們把其中的一個節點的權重設置成 50 時,它接收到的流量就是其餘節點的 1/2。
因爲負載均衡機制徹底是由 RPC 框架自身實現的,因此它再也不須要依賴任何負載均衡設備,天然也不會發生負載均衡設備的單點問題,服務調用方的負載均衡策略也徹底可配,同時咱們能夠經過控制權重的方式,對負載均衡進行治理。
瞭解完 RPC 框架的負載均衡,如今咱們就能夠回到這講最開頭業務提的那個需求:有沒有什麼辦法能夠動態地、智能地控制線上服務節點所接收到的請求流量?
如今答案是否是就顯而易見了,解決問題的關鍵就在於 RPC 框架的負載均衡上。對於這個問題,咱們當時的方案就是,設計一種自適應的負載均衡策略。
如何設計自適應的負載均衡?我剛纔講過,RPC 的負載均衡徹底由 RPC 框架自身實現,服務調用者發起請求時,會經過配置的負載均衡插件,自主地選擇服務節點。那是否是隻要調用者知
如何設計自適應的負載均衡?
我剛纔講過,RPC 的負載均衡徹底由 RPC 框架自身實現,服務調用者發起請求時,會經過配置的負載均衡插件,自主地選擇服務節點。那是否是隻要調用者知道每一個服務節點處理請求的能力,再根據服務處理節點處理請求的能力來判斷要打給它多少流量就能夠了?當一個服務節點負載太高或響應過慢時,就少給它發送請求,反之則多給它發送請求。
這就有點像平常工做中的分配任務,要多考慮實際狀況。當一位下屬身體欠佳,就少給他些工做;若恰好另外一位下屬狀態很好,手頭工做又不是不少,就多分給他一點。
那服務調用者節點又該如何斷定一個服務節點的處理能力呢?
這裏咱們能夠採用一種打分的策略,服務調用者收集與之創建長鏈接的每一個服務節點的指標數據,如服務節點的負載指標、CPU 核數、內存大小、請求處理的耗時指標(如請求平均耗時、TP9九、TP999)、服務節點的狀態指標(如正常、亞健康)。經過這些指標,計算出一個分數,好比總分 10 分,若是 CPU 負載達到 70%,就減它 3 分,固然了,減 3 分只是個類比,須要減多少分是須要一個計算策略的。
咱們又該若是根據這些指標來打分呢?
這就有點像公司對員工進行年終考覈。假設我是老闆,我要考覈專業能力、溝通能力和工做態度,這三項的佔比分別是 30%、30%、40%,我給一個員工的評分是 十、八、8,那他的綜合分數就是這樣計算的:10*30%+8*30%+8*40%=8.6 分。
給服務節點打分也同樣,咱們能夠爲每一個指標都設置一個指標權重佔比,而後再根據這些指標數據,計算分數。
服務調用者給每一個服務節點都打完分以後,會發送請求,那這時候咱們又該如何根據分數去控制給每一個服務節點發送多少流量呢?
咱們能夠配合隨機權重的負載均衡策略去控制,經過最終的指標分數修改服務節點最終的權重。例如給一個服務節點綜合打分是 8 分(滿分 10 分),服務節點的權重是 100,那麼計算後最終權重就是 80(100*80%)。服務調用者發送請求時,會經過隨機權重的策略來選擇服務節點,那麼這個節點接收到的流量就是其餘正常節點的 80%(這裏假設其餘節點默認權重都是 100,且指標正常,打分爲 10 分的狀況)。
到這兒,一個自適應的負載均衡咱們就完成了,總體的設計方案以下圖所示:
關鍵步驟我來解釋下:
添加服務指標收集器,並將其做爲插件,默認有運行時狀態指標收集器、請求耗時指標收集器。
運行時狀態指標收集器收集服務節點 CPU 核數、CPU 負載以及內存等指標,在服務調用者與服務提供者的心跳數據中獲取。
請求耗時指標收集器收集請求耗時數據,如平均耗時、TP9九、TP999 等。
能夠配置開啓哪些指標收集器,並設置這些參考指標的指標權重,再根據指標數據和指標權重來綜合打分。
經過服務節點的綜合打分與節點的權重,最終計算出節點的最終權重,以後服務調用者會根據隨機權重的策略,來選擇服務節點。
總結
咱們詳細講解了 RPC 框架的負載均衡,它與 Web 服務的負載均衡的不一樣之處在於:RPC 框架並非依賴一個負載均衡設備或者負載均衡服務器來實現負載均衡的,而是由 RPC 框架自己實現的,服務調用者能夠自主選擇服務節點,發起服務調用。
這樣的好處是,RPC 框架再也不須要依賴專門的負載均衡設備,能夠節約成本;還減小了與負載均衡設備間額外的網絡傳輸,提高了傳輸效率;而且均衡策略可配,便於服務治理。
除此以外,重點還涉及到「如何設計一個自適應的負載均衡」,經過它,咱們能夠就能根據服務調用者依賴的服務集羣中每一個節點的自身狀態,智能地控制發送給每一個服務節點的請求流量,防止因某個服務節點負載太高、請求處理過慢而影響到整個服務集羣的可用率。