【萬字長文】吃透負載均衡

高效能架構探索發表於2021-10-15

讀前福利,本文的參考內容,均可在下面連結獲取(免費哦)

必備經典書籍

大家好,我是雨樂。

首先告訴大家一件事,在十一國慶期間,引擎的機器又又。。。又扛不住了流量。

經過監控分析,發現某個服務的一個例項所在的虛擬機器扛不住了,所以採取臨時措施流量控制之後,問題解決了,但還是造成了不小的損失。

寫在前面

寫本文的目的:

  • 對負載均衡的理解零零散散,不成體系。

閱讀這篇文章需要的條件:

  • 對OSI模型有些許瞭解
  • 有耐心。本文涉及大量的知識點,且只能用文字才能講清楚,所以文字比較多。

收穫:

  • 讀完此篇文章,從巨集觀的角度理解了負載均衡的原理以及實現機制。加深對分散式架構的瞭解

主要內容:

  • 本文首先從概念開始,講解什麼是負載均衡,以及負載均衡在分散式系統中所承擔的角色以及提供的功能。
  • 講解負載均衡的分類。分別從 軟硬體角度地域範圍角度 以及 OSI模型角度 進行分類講解負載均衡的實現方案。
  • 從負載均衡的策略角度來分析目前業界的負載均衡演算法以及其優缺點

好了,準備好了麼,讓我們開始這次愉快之旅。

引言

首先 撇開對線上的影響,如果線上突發來了流量,後端服務扛不住,我們會怎麼做呢?
無非兩種方式:

  • 提升機器配置(CPU、記憶體、硬碟、頻寬等)
  • 加機器

上面兩種方式,我們稱之為縱向擴充套件和橫向擴充套件。

縱向擴充套件,是從單機的角度通過增加硬體處理能力,比如CPU處理能力,記憶體容量,磁碟等方面,實現伺服器處理能力的提升,不能滿足大型分散式系統(網站),大流量,高併發,海量資料的問題。

橫向擴充套件,通過新增機器來滿足大型網站服務的處理能力。比如:一臺機器不能滿足,則增加兩臺或者多臺機器,共同承擔訪問壓力。

概念

負載均衡,英文名稱為Load Balance,其含義就是指將負載(工作任務或者網路請求)進行平衡,分攤到多個操作單元(伺服器或者元件)上進行執行。目的是儘量將網路流量 平均 傳送到多個伺服器上,以保證整個業務系統的高可用。

負載均衡

在網際網路的早起,網路還不是很發達,流量相對較小,業務也比較簡單,單臺伺服器或者例項就有可能滿足訪問需要。但如今在網際網路發達的今天,流量請求動輒百億、甚至上千億,單臺伺服器或者例項已完全不能滿足需求,這就有了叢集。不論是為了實現高可用還是高效能,都需要用到多臺機器來擴充套件服務能力,使用者的請求不管連線到哪臺伺服器,都能得到相同的相應處理。

另一方面,如何構建和排程服務叢集這事情,又必須對使用者一側保持足夠的透明,即使請求背後是由一千臺、一萬臺機器來共同響應的,也絕非使用者所關心的事情,使用者需記住的只有一個域名地址而已。排程後方的多臺機器,以統一的介面對外提供服務,承擔此職責的技術元件被稱為 負載均衡

負載均衡主要有以下作用:

  • 高併發。通過採取一定的演算法策略,將流量儘可能的均勻傳送給後端的例項,以此提高叢集的併發處理能力。

  • 伸縮性。根據網路流量的大小,增加或者減少後端伺服器例項,由負載均衡裝置進行控制,這樣使得叢集具有伸縮性。

  • 高可用。負載均衡器通過演算法或者其他效能資料來監控候選例項,當例項負載過高或者異常時,減少其流量請求或者直接跳過該例項,將請求傳送個其他可用例項,這使得叢集具有高可用的特性。

  • 安全防護。有些負載均衡器提供了安全防護功能。如:黑白名單處理、防火牆等。

分類

根據載體型別分類

從支援負載均衡的載體來看,可以將負載均衡分為兩類:

  • 硬體負載均衡
  • 軟體負載均衡
硬體負載均衡

硬體負載平衡器是一種硬體裝置,具有專門的作業系統。硬體負載平衡器位於傳入流量和內部伺服器之間,本質上充當“流量警察”。當使用者訪問網站或者使用app某個功能時,它們首先被髮送到負載均衡器,然後負載均衡器根據一定的策略,將流量轉發到後端不同的伺服器。為確保最佳效能,硬體負載均衡器根據自定義規則分配流量,以免後端例項不堪重負。

傳統上,硬體負載平衡器和應用伺服器部署在本地資料中心,負載平衡器的數量取決於預期的峰值流量。負載均衡器通常成對部署,以防其中一個失敗。

目前業界領先的兩款硬體負載均衡器:F5和A10

硬體負載均衡

優點

功能強大:支援全域性負載均衡並提供較全面的、複雜的負載均衡演算法。

效能強悍:硬體負載均衡由於是在專用處理器上執行,因此吞吐量大,可支援單機百萬以上的併發。

安全性高:往往具備防火牆,防 DDos 攻擊等安全功能。

缺點

成本昂貴:購買和維護硬體負載均衡的成本都很高(:F5價格在15w~55w不等,A10價格在55w-100w不等)。

擴充套件性差:當訪問量突增時,超過限度不能動態擴容。

軟體負載均衡

軟體負載均衡指的是在伺服器的作業系統上安裝負載均衡軟體,從此伺服器發出的請求經軟體負載均衡演算法路由到後端叢集的某一臺機器上。

常見負載均衡軟體有:LVS、Nginx、Haproxy。

軟體負載均衡

優點

擴充套件性好:適應動態變化,可以通過新增軟體負載均衡例項,動態擴充套件到超出初始容量的能力。

成本低廉:軟體負載均衡可以在任何標準物理裝置上執行,降低了購買和運維的成本。

缺點

效能略差:相比於硬體負載均衡,軟體負載均衡的效能要略低一些。

軟硬體負載均衡器的區別

  • 硬體負載平衡器與軟體負載平衡器之間最明顯的區別在於,硬體負載平衡器需要專有的機架堆疊硬體裝置,而軟體負載平衡器只需安裝在標準 x86 伺服器或虛擬機器上。網路負載平衡器硬體通常是過度配置的——換句話說,它們的大小能夠處理偶爾的高峰流量負載。此外,每個硬體裝置都必須與一個額外的裝置配對以獲得高可用性,以防其他負載均衡器出現故障。

  • 硬體和軟體負載平衡器之間的另一個關鍵區別在於擴充套件能力。隨著網路流量的增長,資料中心必須提供足夠的負載均衡器以滿足峰值需求。對於許多企業來說,這意味著大多數負載均衡器在高峰流量時間(例如黑色星期五)之前一直處於空閒狀態。

  • 如果流量意外超出容量,終端使用者體驗會受到顯著影響。另一方面,軟體負載平衡器能夠彈性擴充套件以滿足需求。無論網路流量是低還是高,軟體負載平衡器都可以簡單地實時自動擴充套件,消除過度配置成本和對意外流量激增的擔憂。

  • 此外,硬體負載平衡器配置可能很複雜。基於軟體定義原則構建的軟體負載平衡器跨多個資料中心和混合/多雲環境。事實上,硬體裝置與雲環境不相容,而軟體負載均衡器與裸機、虛擬、容器和雲平臺相容。

根據地域範圍分類

負載均衡從其應用的地理結構上分為本地負載均衡(Local Load Balance)和全域性負載均衡(Global Load Balance,也叫地域負載均衡)。

地域負載均衡

本地負載均衡

本地負載均衡是指對本地的伺服器群做負載均衡。

本地負載均衡針對本地範圍的伺服器群做負載均衡,本地負載均衡不需要花費高額成本購置高效能伺服器,只需利用現有裝置資源,就可有效避免伺服器單點故障造成資料流量的損失,通常用來解決資料流量過大、網路負荷過重的問題。同時它擁有形式多樣的均衡策略把資料流量合理均衡的分配到各臺伺服器。如果需要在現在伺服器上升級擴充,不需改變現有網路結構、停止現有服務,僅需要在服務群中簡單地新增一臺新伺服器。

本地負載均衡能有效地解決資料流量過大、網路負荷過重的問題,並且不需花費昂貴開支購置效能卓越的伺服器,充分利用現有裝置,避免伺服器單點故障造成資料流量的損失。

其有靈活多樣的均衡策略把資料流量合理地分配給伺服器群內的伺服器共同負擔。即使是再給現有伺服器擴充升級,也只是簡單地增加一個新的伺服器到服務群中,而不需改變現有網路結構、停止現有的服務。

全域性負載均衡

全域性負載均衡是指對分別放置在不同的地理位置、有不同網路結構的伺服器群間作負載均衡。

全域性負載均衡主要用於在一個多區域擁有自己伺服器的站點,為了使全球使用者只以一個IP地址或域名就能訪問到離自己最近的伺服器,從而獲得最快的訪問速度,也可用於子公司分散站點分佈廣的大公司通過Intranet(企業內部網際網路)來達到資源統一合理分配的目的。

全域性負載均衡,目前實現方式有以下幾種:

  • 通過運營商線路排程:這個主要是指國內,由於特殊原因國內不同運營商互聯互通存在很大問題,比如聯通使用者訪問電信機房伺服器延遲很大,甚至有可能無法訪問的情況。假如您的業務部署在不同運營商機房,可以通過運營商線路解析來實現排程,聯通線路使用者域名解析到聯通機房IP,電信線路使用者域名解析電信機房IP,這樣保證不同使用者訪問最佳的伺服器。

  • 通過地域線路排程:

    • 我們都知道,網站伺服器越近,訪問速度越快,比如天津使用者訪問北京伺服器會比廣州伺服器快很多。假如您的業務部署在華北,華南兩個Region,可以通過地域線路解析,設定華北,東北,西北,華中使用者訪問域名解析到北京伺服器IP,華東,華南,西南使用者訪問域名解析到廣州伺服器IP,這樣使用者訪問離自己最近的伺服器可以提升訪問體驗。
    • 假如您的業務是面向全球的,國內部署有業務,海外也部署有業務,可以選擇中國使用者訪問域名解析到國內伺服器,海外使用者訪問域名解析到海外伺服器。當然海外的還可以細分,比如選擇亞太--新加坡的使用者等,可以具體到洲,國家。
  • 權重輪詢:比如一個域名解析到多個IP,可以根據不同IP伺服器的配置,業務情況設定解析比重,比如2:1或者1:1等等。

  • 健康檢查,故障轉移:可以建立監控任務實時監控後端伺服器IP的健康狀態,如果發現後端伺服器異常,可以把解析流量切換到其他正常的伺服器或者備用伺服器,保證業務不會中斷。

CDN的全稱是Content Delivery Network,即內容分發網路。其就是採用的全域性負載均衡。假如我們將圖片儲存在CDN上,且該CDN所在廠家在北京、杭州均有伺服器。那麼:

  • 當天津的使用者需要下載該圖片的時候,會自動將流量請求轉發至距離其最近的CDN伺服器,也就是北京
  • 當安徽的使用者需要下載圖片的時候,就會將流量請求轉發至杭州。

根據OSI網路模型分類


OSI是一個開放性的通訊系統互連參考模型,如上圖所示。在OSI參考模型中,分別有:

  • 應用層
  • 表示層
  • 會話層
  • 傳輸層
  • 網路層
  • 資料鏈路層
  • 物理層

從上圖可以看出:

TELNET、HTTP、FTP、NFS、SMTP、DNS等屬於第七層應用層的概念。

TCP、UDP、SPX等屬於第四層傳輸層的概念。

IP、IPX等屬於第三層網路層的概念。

ATM、FDDI等屬於第二層資料鏈路層的概念。

根據負載均衡技術實現在OSI七層模型的不同層次,我們給負載均衡分類:

  • 七層負載均衡:工作在應用層的負載均衡稱
  • 四層負載均衡:工作在傳輸層的負載均衡稱
  • 三層負載均衡:工作在網路層的負載均衡,
  • 二層負載均衡:工作在資料鏈路層的負載均衡。

下面內容非常重要,關注下再往下看

其中最常用的是四層和七層負載均衡

下面我們將從OSI模型從下往上的順序,來想西講解上述幾種負載均衡。

二層負載均衡

工作在資料鏈路層的負載均衡稱之為二層負載均衡(又稱為資料鏈路層負載均衡),通過在通訊協議的資料鏈路層修改mac地址進行負載均衡。

二層負載均衡是基於資料鏈路層的負載均衡,即讓負載均衡伺服器和業務伺服器繫結同一個虛擬IP(即VIP),客戶端直接通過這個VIP進行請求叢集。叢集中不同的機器採用相同IP地址,但是機器的MAC地址不一樣。當負載均衡伺服器接受到請求之後,通過改寫報文的目標MAC地址的方式將請求轉發到目標機器實現負載均衡。

資料鏈路層負載均衡所做的工作,是修改請求的資料幀中的 MAC 目標地址,讓使用者原本是傳送給負載均衡器的請求的資料幀,被二層交換機根據新的 MAC 目標地址轉發到伺服器叢集中對應的伺服器(真實伺服器)的網路卡上,這樣真實伺服器就獲得了一個原本目標並不是傳送給它的資料幀。

為了便於理解,我們假設負載均衡器所在的ip地址為192.168.1.1,後端服務例項的mac地址分別為52:54:00:A1:CB:F7,61:52:00:A2:BD, 71:63:52:A3:CA。如下圖所示:

二層負載均衡

在上圖中,使用者的請求首先到達ip為192.168.1.1的二層負載均衡器,然後二層負載均衡器通過採取一定的策略,選中了mac地址為71:63:52:A3:CA,然後將流量轉發至該服務例項。

需要注意的是,上述只有請求經過負載均衡器,而服務的響應無須從負載均衡器原路返回的工作模式,整個請求、轉發、響應的鏈路形成一個“三角關係”,所以這種負載均衡模式也常被很形象地稱為“三角傳輸模式”,也有叫“單臂模式”或者“直接路由”。

二層負載均衡器直接改寫目標 MAC 地址的工作原理決定了它與真實的伺服器的通訊必須是二層可達的,通俗地說就是必須位於同一個子網當中,無法跨 VLAN。優勢(效率高)和劣勢(不能跨子網)共同決定了資料鏈路層負載均衡最適合用來做資料中心的第一級均衡裝置,用來連線其他的下級負載均衡器。

三層負載均衡

三層負載均衡是基於網路層的負載均衡,因此又叫網路層負載均衡。通俗的說就是按照不同機器不同IP地址進行轉發請求到不同的機器上。

根據 OSI 七層模型,在第三層網路層傳輸的單位是分組資料包,這是一種在分組交換網路中傳輸的結構化資料單位。以IP協議為例,一個IP 資料包由 Headers 和 Payload 兩部分組成, Headers 長度最大為60Bytes,其中包括了20Bytes的固定資料和最長不超過40Bytes 的可選的額外設定組成。

三層負載均衡伺服器對外依然提供一個VIP(虛IP),但是叢集中不同的機器採用不同的IP地址。當負載均衡伺服器接受到請求之後,根據不同的負載均衡演算法,通過IP將請求轉發至不同的真實伺服器。

學過計算機網路的都知道,在IP分組的資料包header中有 源IP目標IP。源IP和目標IP代表分組交換中從資料是從哪臺機器到哪臺機器的,那麼,我們可以採用跟修改二層負載均衡中MAC地址的方式一樣,直接修改目標IP,以達到資料轉發的目的。

修改目標IP的方式有兩種:
1、原有的資料包保持不變,生成一個新的資料包,原資料包的Header和Payload作為新資料包的Payload,在這個新資料包的 Headers 中寫入真實伺服器的 IP 作為目標地址,然後把它傳送出去。

真實伺服器收到資料包後,必須在接收入口處設計一個針對性的拆包機制,把由負載均衡器自動新增的那層 Headers 扔掉,還原出原來的資料包來進行使用。這樣,真實伺服器就同樣拿到了一個原本不是發給它(目標 IP 不是它)的資料包,達到了流量轉發的目的。這種資料傳輸方式叫做 IP隧道 傳輸。

儘管因為要封裝新的資料包,IP 隧道的轉發模式比起直接路由模式效率會有所下降,但由於並沒有修改原有資料包中的任何資訊,所以 IP 隧道的轉發模式仍然具備三角傳輸的特性,即負載均衡器轉發來的請求,可以由真實伺服器去直接應答,無須在經過均衡器原路返回。而且由於 IP 隧道工作在網路層,所以可以跨越 VLAN,因此擺脫了直接路由模式中網路側的約束。

此模式從請求到響應如下圖所示:

IP隧道模式負載均衡

優點:

  • 可以跨越 VLAN
    缺點:
  • 要求真實伺服器必須支援IP隧道協議,也就是說伺服器得自己會拆包
  • 必須通過專門的配置,必須保證所有的真實伺服器與均衡器有著相同的虛擬 IP 地址,因為回覆該資料包時,需要使用這個虛擬 IP 作為響應資料包的源地址,這樣客戶端收到這個資料包時才能正確解析。

基於以上原因,就有了第二中修改方式。
2、改變目標資料包。

直接把資料包 Headers 中的目標地址改為真實伺服器地址,修改後原本由使用者發給均衡器的資料包,也會被三層交換機轉傳送到真實伺服器的網路卡上,而且因為沒有經過 IP 隧道的額外包裝,也就無須再拆包了。

因為這種模式是通過修改目標 IP 地址才到達真實伺服器的,如果真實伺服器直接將應答包返回客戶端的話,這個應答資料包的源 IP 是真實伺服器的 IP,也即均衡器修改以後的 IP 地址,客戶端不可能認識該 IP,自然就無法再正常處理這個應答了。因此,只能讓應答流量繼續回到負載均衡,由負載均衡把應答包的源 IP 改回自己的 IP,再發給客戶端,這樣才能保證客戶端與真實伺服器之間的正常通訊。

這種修改目標IP的方式叫NAT模式,這種通過修改目標IP的方式達到負載均衡目的的方式叫做NAT負載均衡。如下圖所示:

NAT模式負載均衡

四層負載均衡

所謂四層負載均衡,也就是主要通過報文中的目標地址和埠,再加上負載均衡裝置設定的伺服器選擇方式,決定最終選擇的內部伺服器。

由於四層負載均衡是作用在傳輸層,因此,我們就以常見的TCP進行舉例。

負載均衡裝置在接收到第一個來自客戶端的SYN 請求時,即通過上述方式選擇一個最佳的伺服器,並對報文中目標IP地址進行修改(改為後端伺服器IP),直接轉發給該伺服器。TCP的連線建立,即三次握手是客戶端和伺服器直接建立的,負載均衡裝置只是起到一個類似路由器的轉發動作。在某些部署情況下,為保證伺服器回包可以正確返回給負載均衡裝置,在轉發報文的同時可能還會對報文原來的源地址進行修改。

四層負載均衡

四層負載均衡主要是基於tcp協議報文,可以做任何基於tcp/ip協議的軟體的負載均衡,比如Haproxy、LVS等。

七層負載均衡

所謂七層負載均衡,也稱為“內容交換”,也就是主要通過報文中的真正有意義的應用層內容,再加上負載均衡裝置設定的伺服器選擇方式,決定最終選擇的內部伺服器。

應用層協議較多,常用http、radius、dns等。七層負載就可以基於這些協議來負載。

我們仍然以TCP為例。負載均衡裝置如果要根據真正的應用層內容再選擇伺服器,只能先代理最終的伺服器和客戶端建立連線(三次握手)後,才可能接受到客戶端傳送的真正應用層內容的報文,然後再根據該報文中的特定欄位,再加上負載均衡裝置設定的伺服器選擇方式,決定最終選擇的內部伺服器。負載均衡裝置在這種情況下,更類似於一個代理伺服器。負載均衡和前端的客戶端以及後端的伺服器會分別建立TCP連線。所以從這個技術原理上來看,七層負載均衡明顯的對負載均衡裝置的要求更高,處理七層的能力也必然會低於四層模式的部署方式。

七層負載均衡器會與客戶端 以及 後端的服務例項分別建立連線

七層負載均衡

七層負載均衡基本都是基於http協議的,適用於web伺服器的負載均衡,比如Nginx等。

對比(四層和七層)

  • 智慧性

    • 七層負載均衡由於具備OIS七層的所有功能,所以在處理使用者需求上能更加靈活,從理論上講,七層模型能對使用者的所有跟服務端的請求進行修改。例如對檔案header新增資訊,根據不同的檔案型別進行分類轉發。
    • 四層模型僅支援基於網路層的需求轉發,不能修改使用者請求的內容。
  • 安全性

    • 七層負載均衡由於具有OSI模型的全部功能,能更容易抵禦來自網路的攻擊
    • 四層模型從原理上講,會直接將使用者的請求轉發給後端節點,無法直接抵禦網路攻擊。
  • 複雜度

    • 四層模型一般比較簡單的架構,容易管理,容易定位問題
    • 七層模型架構比較複雜,通常也需要考慮結合四層模型的混用情況,出現問題定位比較複雜。
  • 效率比

    • 四層模型基於更底層的設定,通常效率更高,但應用範圍有限
    • 七層模型需要更多的資源損耗,在理論上講比四層模型有更強的功能,現在的實現更多是基於http應用。

演算法與實現

常用的負載均衡演算法分為以下兩類:

  • 靜態負載均衡
  • 動態負載均衡

常見的靜態均衡演算法:輪詢法、隨機法、源地址雜湊法、一致性雜湊法、加權輪詢法、加權隨機法。

常見的動態負載均衡演算法:最小連線數法、最快響應速度法。

隨機法(Random)

將請求隨機分配到各個節點。由概率統計理論得知,隨著客戶端呼叫服務端的次數增多,其實際效果越來越接近於平均分配,也就是輪詢的結果。

隨機策略會導致配置較低的機器Down機,從而可能引起雪崩,一般採用隨機演算法時建議後端叢集機器配置最好同等的,隨機策略的效能取決與隨機演算法的效能。

  • 優點:簡單高效,易於水平擴充套件,每個節點滿足字面意義上的均衡;
  • 缺點:沒有考慮機器的效能問題,根據木桶最短木板理論,叢集效能瓶頸更多的會受效能差的伺服器影響。

隨機法

實現:

std::string Select(const std::vector<int> &ips) {
  size_t size = ips.size();
  if (size == 0) {
    return "";
  }
  
  return ips[random() % size];
}

輪詢法(Round Robin)

每一次來自網路的請求輪流分配給內部中的伺服器,從1至N然後重新開始。此種均衡演算法適合於伺服器組中的所有伺服器都有相同的軟硬體配置並且平均服務請求相對均衡的情況。

假設10臺機器,從0-9,請求來臨時從0號機器開始,後續每來一次請求對編號加1,這樣一直迴圈,上面的隨機策略其實最後就變成輪詢了,這兩種策略都不關心機器的負載和執行情況,而且對變數操作會引入鎖操作,效能也會下會下降。

  • 優點:簡單高效,易於水平擴充套件,每個節點滿足字面意義上的均衡;
  • 缺點:沒有考慮機器的效能問題,根據木桶最短木板理論,叢集效能瓶頸更多的會受效能差的伺服器影響。

輪詢法

程式碼實現:

static int idx = 0;
std::string Select(const std::vector<int> &ips) {
  size_t size = ips.size();
  if (size == 0) {
    return "";
  }
  
  if (idx == ips.size()) {
    idx = 0;
  }
  
  return ips[idx++];
}

加權輪詢法(Weighted Round Robin)

不同的後端伺服器可能機器的配置和當前系統的負載並不相同,因此它們的抗壓能力也不相同。給配置高、負載低的機器配置更高的權重,讓其處理更多的請;而配置低、負載高的機器,給其分配較低的權重,降低其系統負載,加權輪詢能很好地處理這一問題,並將請求順序且按照權重分配到後端。

假設後端有3臺伺服器,分別為a b c,現在在負載均衡器中配置a伺服器的權重為7,b服務的權重為2,c服務的權重為1。當來了10次請求的時候,其中有7次請求a,2次請求b,1次請求c。即最終結果是

aaaaaaabbc
  • 優點:可以將不同機器的效能問題納入到考量範圍,叢集效能最優最大化;
  • 缺點:生產環境複雜多變,伺服器抗壓能力也無法精確估算,靜態演算法導致無法實時動態調整節點權重,只能粗糙優化。

加權輪詢

不同的後端伺服器可能機器的配置和當前系統的負載並不相同,因此它們的抗壓能力也不相同。給配置高、負載低的機器配置更高的權重,讓其處理更多的請;而配置低、負載高的機器,給其分配較低的權重,降低其系統負載,加權輪詢能很好地處理這一問題,並將請求順序且按照權重分配到後端。

加權隨機法(Weighted Random)

在之前的文章權重隨機分配器我們有詳細講過各種實現方案,此處我們不再贅述,從裡面摘抄了一種實現方案作為本方案的實現。

加權隨機

  • 優點:可以將不同機器的效能問題納入到考量範圍,叢集效能最優最大化;
  • 缺點:生產環境複雜多變,伺服器抗壓能力也無法精確估算,靜態演算法導致無法實時動態調整節點權重,只能粗糙優化。

程式碼實現

srtuct Item {
  std::string ip;
  int weight;
};
std::string select(const std::vector<item> &items) {
  int sum = 0;
  for (auto elem : items) {
    sum += elem.weight;
  }
  
  int rd = rand() % sum;
  int s = 0;
  std::string res;
  for (auto elem : items) {
    s += elem.weight;
    if (s >= rd) {
      res = elem.ip;
      break;
    }
  }
  return res;
}

最快響應速度法(Response Time)

根據請求的響應時間,來動態調整每個節點的權重,將響應速度快的服務節點分配更多的請求,響應速度慢的服務節點分配更少的請求

負載均衡裝置對內部各伺服器發出一個探測請求(例如Ping),然後根據內部中各伺服器對探測請求的最快響應時間來決定哪一臺伺服器來響應客戶端的服務請求。此種均衡演算法能較好的反映伺服器的當前執行狀態,但這最快響應時間僅僅指的是負載均衡裝置與伺服器間的最快響應時間,而不是客戶端與伺服器間的最快響應時間。

  • 優點:動態,實時變化,控制的粒度更細,跟靈敏;
  • 缺點:複雜度更高,每次需要計算請求的響應速度;

最快響應速度

最少連線數法(Least Connections)

將請求分發到連線數/請求數最少的候選伺服器,已達到負載均衡的目的

客戶端的每一次請求服務在伺服器停留的時間可能會有較大的差異,隨著工作時間加長,如果採用簡單的輪循或隨機均衡演算法,每一臺伺服器上的連線程式可能會產生極大的不同,並沒有達到真正的負載均衡。最少連線數均衡演算法對內部中需負載的每一臺伺服器都有一個資料記錄,記錄當前該伺服器正在處理的連線數量,當有新的服務連線請求時,將把當前請求分配給連線數最少的伺服器,使均衡更加符合實際情況,負載更加均衡。此種均衡演算法適合長時處理的請求服務,如FTP。

  • 優點:動態,根據節點狀況實時變化
  • 缺點:提高了複雜度,每次連線斷開需要進行計數

最少連線數

源地址雜湊法(Source Hashing)

根據請求源 IP,通過雜湊計算得到一個數值,用該數值在候選伺服器列表的進行取模運算,得到的結果便是選中的伺服器。

能夠讓同一客戶端的請求或者同一使用者的請求總是請求在後端同一臺機器上,這種演算法根據客戶端IP求出Hash值然後對端叢集總數求餘得到值就是伺服器集合的下標,一般這種演算法用於快取命中,或者同一會話請求等,但這種演算法也有一定的缺點,某一使用者訪問量(黑產)非常高時可能造成服務端壓力過大或者後端服務Down掉,那麼客戶端就會無法訪問,所以也需要一定的降級策略。

  • 優點:將來自同一IP地址的請求,同一會話期內,轉發到相同的伺服器;實現會話粘滯
  • 缺點:目標伺服器當機後,會話會丟失

源地址雜湊

一致性雜湊(Consistency hash)

一些場景希望同樣的請求儘量落到一臺機器上,比如訪問快取叢集時,我們往往希望同一種請求能落到同一個後端上,以充分利用其上已有的快取,不同的機器承載不同的穩定請求量(也可以理解為固定批使用者的請求)。而不是隨機地散落到所有機器上,那樣的話會迫使所有機器快取所有的內容,最終由於存不下形成顛簸而表現糟糕。 我們都知道hash能滿足這個要求,比如當有n臺伺服器時,輸入x總是會傳送到第hash(x) % n臺伺服器上。但當伺服器變為m臺時,hash(x) % n和hash(x) % m很可能都不相等,這會使得幾乎所有請求的傳送目的地都發生變化,如果目的地是快取服務,所有快取將失效,繼而對原本被快取遮擋的資料庫或計算服務造成請求風暴,觸發雪崩。一致性雜湊是一種特殊的雜湊演算法,在增加伺服器時,發向每個老節點的請求中只會有一部分轉向新節點,從而實現平滑的遷移。

一致性雜湊

優點:

  • 平衡性: 每個節點被選到的概率是O(1/n)。
  • 單調性: 當新節點加入時, 不會有請求在老節點間移動, 只會從老節點移動到新節點。當有節點被刪除時,也不會影響落在別的節點上的請求。
  • 分散性: 當上遊的機器看到不同的下游列表時(在上線時及不穩定的網路中比較常見), 同一個請求儘量對映到少量的節點中。
  • 負載: 當上遊的機器看到不同的下游列表的時候, 保證每臺下遊分到的請求數量儘量一致。

缺點:

  • 在機器數量較少的時候,區間大小會不平衡。
  • 當一臺機器故障的時候,它的壓力會完全轉移到另外一臺機器, 可能無法承載。

結語

負載均衡並不是真正確保網路流量能夠"均勻"的分配到後端服務例項上。它只是抱著在意外情況發生時候,也能保證使用者體驗。良好的架構設計和彈性擴容,能夠使得負載均衡的功能 事半功倍

相關文章