流量引導:網絡世界的負載均衡解密
均衡網絡流量的常用技術,它們的優勢和利弊權衡。
大型的多站點互聯網系統,包括內容分發網絡(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,不再承擔負載均衡的功能。
四層負載均衡器能夠均衡用戶和兩臺 web 服務器的連接
四層均衡器將網絡流量均衡地引導至后端服務器。通常這是基于對 IP 數據包的五元組做散列(數學函數)來完成的,五元組包括:源地址、源端口、目的地址、目的端口、協議(比如 TCP 或 UDP)。這種方法是快速和高效的(還維持了 TCP 的基本屬性),而且不需要均衡器維持每個連接的狀態。(更多信息請閱讀谷歌發表的 Maglev 論文,這篇論文詳細討論了四層軟件負載均衡器的實現細節。)
四層均衡器可以對后端服務做健康檢查,只把流量分發到健康的機器上。和使用 DNS 做負載均衡不同的是,在某個后端 web 服務故障的時候,它可以很快地把流量重新分發到其他機器上,雖然故障機器的已有連接會被重置。
當后端服務器的能力不同時,四層均衡器可以根據權重做流量分發。它為運維人員提供了強大的能力和靈活性,而且硬件成本相對較小。
擴展到多站點
系統規模在持續增長。你的客戶希望能一直使用服務,即使是數據中心發生故障的時候。所以你建設了一個新的數據中心,另外獨立部署了一套服務和四層負載均衡器集群,仍然使用同樣的 VIP。DNS 的設置不變。
兩個站點的邊緣路由器都把自己的地址空間宣告出去,包括 VIP 地址。發往該 VIP 的請求可能到達任何一個站點,取決于用戶和系統之間的網絡是如何連接的,以及各個網絡的路由策略是如何配置的。這就是泛播。大部分時候這種機制可以很好的工作。如果一個站點出問題了,你可以停止通過 BGP 宣告 VIP 地址,客戶的請求就會迅速地轉移到另外一個站點去。
多個站點使用泛播提供服務
這種設置有一些問題。最大的問題是,不能控制請求流向哪個站點,或者限制某個站點的流量。也沒有一個明確的方式把用戶的請求轉到距離他最近的站點(為了降低網絡延遲),不過,網絡協議和路由選路配置在大部分情況下應該能把用戶請求路由到最近的站點。
控制多站點系統中的入站請求
為了維持穩定性,需要能夠控制每個站點的流量大小。要實現這種控制,可以給每個站點分配不同的 VIP 地址,然后用簡單的或者有權重的 DNS 輪詢來做負載均衡。
多站點提供服務,每個站點使用一個主 VIP,另外一個站點作為備份。基于能感知地理位置的 DNS。
現在有兩個問題。
第一、使用 DNS 均衡意味著會有被緩存的記錄,如果你要快速重定向流量的話就麻煩了。
第二、用戶每次做新的 DNS 查詢,都可能連上任意一個站點,可能不是距離最近的。如果你的服務運行在分布廣泛的很多站點上,用戶會感受到響應時間有明顯的變化,取決于用戶和提供服務的站點之間有多大的網絡延遲。
讓每個站點都配置上其他所有站點的 VIP 地址,并宣告出去(因此也會包含故障的站點),這樣可以解決第一個問題。有一些網絡上的小技巧,比如備份站點宣告路由時,不像主站點使用那么具體的目的地址,這樣可以保證每個 VIP 的主站點只要可用就會優先提供服務。這是通過 BGP 來實現的,所以我們應該可以看到,流量在 BGP 更新后的一兩分鐘內就開始轉移了。
即使離用戶最近的站點是健康而且有服務能力的,但是用戶真正訪問到的卻不一定是這個站點,這個問題還沒有很好的解決方案。很多大型的互聯網服務利用 DNS 給不同地域的用戶返回不同的解析結果,也能有一定的效果。不過,因為網絡地址的結構和地理位置無關,一個地址段也可能會改變所在位置(例如,當一個公司重新規劃網絡時),而且很多用戶可能使用了同一個 DNS 緩存服務器。所以這種方案有一定的復雜度,而且容易出錯。
增加七層負載均衡
又過了一段時間,你的客戶開始要更多的高級功能。
雖然四層負載均衡可以高效地在多個 web 服務器之間分發流量,但是它們只針對源地址、目標地址、協議和端口來操作,請求的內容是什么就不得而知了,所以很多高級功能在四層負載均衡上實現不了。而七層(L7)負載均衡知道請求的內容和結構,所以能做更多的事情。
七層負載均衡可以實現緩存、限速、錯誤注入,做負載均衡時可以感知到請求的代價(有些請求需要服務器花更多的時間去處理)。
七層負載均衡還可以基于請求的屬性(比如 HTTP cookies)來分發流量,可以終結 SSL 連接,還可以幫助防御應用層的拒絕服務(DoS)攻擊。規模大的 L7 負載均衡的缺點是成本 —— 處理請求需要更多的計算,而且每個活躍的請求都占用一些系統資源。在一個或者多個 L7 均衡器前面運行 L4 均衡器集群,對擴展規模有幫助。
結論
負載均衡是一個復雜的難題。除了上面說過的策略,還有不同的負載均衡算法,用來實現負載均衡器的高可用技術、客戶端負載均衡技術,以及最近興起的服務網絡等等。
核心的負載均衡模式隨著云計算的發展而不斷發展,而且,隨著大型 web 服務商致力于讓負載均衡技術更可控和更靈活,這項技術會持續發展下去。