流量引導:網路世界的負載均衡解密

2018-12-01 21:17:00

均衡網路流量的常用技術,它們的優勢和利弊權衡。

大型的多站點網際網路系統,包括內容分發網路(CDN)和雲服務提供商,用一些方法來均衡來訪的流量。這篇文章我們講一下常見的流量均衡設計,包括它們的技術手段和利弊權衡。

早期的雲端計算服務提供商,可以提供單一一台客戶 Web 伺服器,分配一個 IP 地址,然後用一個便於人讀的域名設定一個 DNS 記錄指向這個 IP 地址,再將 IP 地址通過邊界閘道器協定(BGP)宣告出去,BGP 是在不同網路之間交換路由資訊的標準方式。

這本身並不是負載均衡,但是能在冗餘的多條網路路徑中進行流量分發,而且可以利用網路技術讓流量繞過不可用的網路,從而提高了可用性(也引起了非對稱路由的現象)。

簡單的 DNS 負載均衡

隨著來自客戶的流量變大,老闆希望服務是高可用的。你上線第二台 web 伺服器,它有自己獨立的公網 IP 地址,然後你更新了 DNS 記錄,把使用者流量引到兩台伺服器上(內心希望它們均衡地提供服務)。在其中一台伺服器出故障之前,這樣做一直是沒有問題的。假設你能很快地監測到故障,可以更新一下 DNS 設定(手動更新或者通過軟體)刪除解析到故障機器的記錄。

不幸的是,因為 DNS 記錄會被快取,在用戶端快取和它們依賴的 DNS 伺服器上的快取失效之前,大約一半的請求會失敗。DNS 記錄都有一個幾分鐘或更長的生命週期(TTL),所以這種方式會對系統可用性造成嚴重的影響。

更糟糕的是,部分用戶端會完全忽略 TTL,所以有一些請求會持續被引導到你的故障機器上。設定很短的 TTL 也不是個好辦法,因為這意味著更高的 DNS 服務負載,還有更長的存取時延,因為用戶端要做更多的 DNS 查詢。如果 DNS 服務由於某種原因不可用了,那設定更短的 TTL 會讓服務的存取量更快地下降,因為沒那麼多用戶端有你網站 IP 地址的快取了。

增加網路負載均衡

要解決上述問題,可以增加一對相互冗餘的四層(L4)網路負載均衡器,設定一樣的虛擬 IP 地址(VIP)。均衡器可以是硬體的,也可以是像 HAProxy 這樣的軟體。域名的 DNS 記錄指向 VIP,不再承擔負載均衡的功能。

Layer 4 load balancers balance connections across webservers.

四層負載均衡器能夠均衡使用者和兩台 web 伺服器的連線

四層均衡器將網路流量均衡地引導至後端伺服器。通常這是基於對 IP 封包的五元組做雜湊(數學函數)來完成的,五元組包括:源地址、源埠、目的地址、目的埠、協定(比如 TCP 或 UDP)。這種方法是快速和高效的(還維持了 TCP 的基本屬性),而且不需要均衡器維持每個連線的狀態。(更多資訊請閱讀谷歌發表的 Maglev 論文,這篇論文詳細討論了四層軟體負載均衡器的實現細節。)

四層均衡器可以對後端服務做健康檢查,只把流量分發到健康的機器上。和使用 DNS 做負載均衡不同的是,在某個後端 web 服務故障的時候,它可以很快地把流量重新分發到其他機器上,雖然故障機器的已有連線會被重置。

當後端伺服器的能力不同時,四層均衡器可以根據權重做流量分發。它為運維人員提供了強大的能力和靈活性,而且硬體成本相對較小。

擴充套件到多站點

系統規模在持續增長。你的客戶希望能一直使用服務,即使是資料中心發生故障的時候。所以你建設了一個新的資料中心,另外獨立部署了一套服務和四層負載均衡器叢集,仍然使用同樣的 VIP。DNS 的設定不變。

兩個站點的邊緣路由器都把自己的地址空間宣告出去,包括 VIP 地址。發往該 VIP 的請求可能到達任何一個站點,取決於使用者和系統之間的網路是如何連線的,以及各個網路的路由策略是如何設定的。這就是泛播。大部分時候這種機制可以很好的工作。如果一個站點出問題了,你可以停止通過 BGP 宣告 VIP 地址,客戶的請求就會迅速地轉移到另外一個站點去。

Serving from multiple sites using anycast

多個站點使用泛播提供服務

這種設定有一些問題。最大的問題是,不能控制請求流向哪個站點,或者限制某個站點的流量。也沒有一個明確的方式把使用者的請求轉到距離他最近的站點(為了降低網路延遲),不過,網路協定和路由選路設定在大部分情況下應該能把使用者請求路由到最近的站點。

控制多站點系統中的入站請求

為了維持穩定性,需要能夠控制每個站點的流量大小。要實現這種控制,可以給每個站點分配不同的 VIP 地址,然後用簡單的或者有權重的 DNS 輪詢來做負載均衡。

Serving from multiple sites using a primary VIP

多站點提供服務,每個站點使用一個主 VIP,另外一個站點作為備份。基於能感知地理位置的 DNS。

現在有兩個問題。

第一、使用 DNS 均衡意味著會有被快取的記錄,如果你要快速重定向流量的話就麻煩了。

第二、使用者每次做新的 DNS 查詢,都可能連上任意一個站點,可能不是距離最近的。如果你的服務執行在分布廣泛的很多站點上,使用者會感受到響應時間有明顯的變化,取決於使用者和提供服務的站點之間有多大的網路延遲。

讓每個站點都設定上其他所有站點的 VIP 地址,並宣告出去(因此也會包含故障的站點),這樣可以解決第一個問題。有一些網路上的小技巧,比如備份站點宣告路由時,不像主站點使用那麼具體的目的地址,這樣可以保證每個 VIP 的主站點只要可用就會優先提供服務。這是通過 BGP 來實現的,所以我們應該可以看到,流量在 BGP 更新後的一兩分鐘內就開始轉移了。

即使離使用者最近的站點是健康而且有服務能力的,但是使用者真正存取到的卻不一定是這個站點,這個問題還沒有很好的解決方案。很多大型的網際網路服務利用 DNS 給不同地域的使用者返回不同的解析結果,也能有一定的效果。不過,因為網路地址的結構和地理位置無關,一個地址段也可能會改變所在位置(例如,當一個公司重新規劃網路時),而且很多使用者可能使用了同一個 DNS 快取伺服器。所以這種方案有一定的複雜度,而且容易出錯。

增加七層負載均衡

又過了一段時間,你的客戶開始要更多的高階功能。

雖然四層負載均衡可以高效地在多個 web 伺服器之間分發流量,但是它們只針對源地址、目標地址、協定和埠來操作,請求的內容是什麼就不得而知了,所以很多高階功能在四層負載均衡上實現不了。而七層(L7)負載均衡知道請求的內容和結構,所以能做更多的事情。

七層負載均衡可以實現快取、限速、錯誤注入,做負載均衡時可以感知到請求的代價(有些請求需要伺服器花更多的時間去處理)。

七層負載均衡還可以基於請求的屬性(比如 HTTP cookies)來分發流量,可以終結 SSL 連線,還可以幫助防禦應用層的拒絕服務(DoS)攻擊。規模大的 L7 負載均衡的缺點是成本 —— 處理請求需要更多的計算,而且每個活躍的請求都占用一些系統資源。在一個或者多個 L7 均衡器前面執行 L4 均衡器叢集,對擴充套件規模有幫助。

結論

負載均衡是一個複雜的難題。除了上面說過的策略,還有不同的負載均衡演算法,用來實現負載均衡器的高可用技術、用戶端負載均衡技術,以及最近興起的服務網路等等。

核心的負載均衡模式隨著雲端計算的發展而不斷發展,而且,隨著大型 web 服務商致力於讓負載均衡技術更可控和更靈活,這項技術會持續發展下去。