作者 | Amir Souchami
譯者 | 王強
策劃 | Tina
要點
跨多個可用區的分散式系統可能會產生大量的資料傳輸成本和效能瓶頸。
組織可以透過區域感知路由技術來降低成本和延遲,同時不會犧牲可靠性和高可用性。
區域感知路由是一種策略,透過儘可能將流量引導到同一可用區內的服務來最佳化網路成本和延遲。
端到端實現區域感知路由需要多種工具,例如 Istio,還要選擇支援此功能的。
要留心當你的服務分佈不均勻時出現的問題。請處理叢集熱點並具備在特定區域範圍內擴充套件服務的能力。
微服務架構方法已成為構建成功產品的核心因素。這種方法是透過服務網格、容器和無伺服器計算等先進雲技術的應用來實現的。快速增長、可維護性、彈性和高可用性的需求,使構建“深度”分散式系統(具有許多微服務層,跨多個可用區甚至區域的系統)成為了團隊的標準操作。這些系統常見的特徵是有數十個必須透過網路頻繁相互通訊的,聒噪 的微服務。
將我們的資源分佈在不同的物理位置(區域和 AZ)對於實現彈性和高可用性是非常重要的。但是,在某些部署中可能會產生大量的資料傳輸成本和效能瓶頸。本文旨在提高對這些潛在問題的認識,並提供在克服這些挑戰的同時保持彈性的指南。
問 題
使用多個 AZ 是一種最佳實踐,也是保持服務可用性的重要因素。無論是我們的微服務、負載均衡器、資料庫還是訊息佇列,我們都必須跨多個區(AZ)配置它們,以確保我們的應用程式在地理上分佈開來,並能承受各種中斷事件。
在一些關鍵系統中,為了實現容錯,將資源和資料分佈在多個區域(region)甚至多個雲提供商之間也很常見。
將我們的服務分佈在多個可用區,就需要我們在這些可用區之間傳輸資料。每當兩個微服務相互通訊,或每當一個服務從分散式資料庫讀取資料時,通訊就可能跨越可用區邊界。這是由於負載均衡的性質使然。
通常,負載均衡器會在上游服務(被呼叫的服務)的例項之間均勻分配流量,而無需瞭解原始服務所在的可用區是哪一個。因此實際上,每當在多個可用區上配置系統時,跨可用區流量就可能大量出現。
但為什麼它會成為雲成本負擔甚至效能瓶頸呢?讓我們來分析一下。
圖 1:跨多個可用區的請求流圖示
成本負擔
每次在兩個可用區之間傳輸資料時,大型雲提供商通常會對傳入和傳出的跨可用區資料傳輸操作收取雙向資料傳輸費用。例如,如果每個方向的費用為 0.01 美元 /GB,則兩個位於相同區域的可用區之間傳輸 1TB 資料將花費 10 美元(傳出)和 10 美元(傳入),總計 20 美元。但是,這些成本在分散式系統上很快就會失控。想象一下,作為請求的一部分,AZ-1 上的負載均衡器例項可能會聯絡 AZ-2 中的服務 A,後者又呼叫 AZ-3 上的服務 B,B 又從 AZ-2 上的資料庫讀取鍵 / 值記錄,並且經常消費來自 AZ-1 上的一個 Kafka 代理的更新(見圖 1)。
因此,雖然這種架構選擇優先考慮可用性,但它容易出現極端情況,即單個請求的所有服務之間的通訊都是跨可用區進行的。所以現實情況是,在具有各種資料庫、訊息佇列和許多相互通訊的微服務的系統中,資料必須頻繁移動,並且成本可能會變得非常高昂。每次向堆疊新增服務時,負擔都會增加。
效能瓶頸
每個可用區與同一資料中心或區域內的其他可用區之間,在物理上會相隔一段不短的距離,雖說它們之間的距離最多都在幾英里之內。這通常會在可用區之間產生至少個位數毫秒的往返延遲,有時甚至更長。所以,回到我們的示例,對 AZ-1 上的負載均衡器例項的請求可能會到達 AZ-2 中的服務 A,後者又呼叫 AZ-3 上的服務 B,B 又從 AZ-2 上的資料庫中讀取鍵 / 值記錄,並且經常消費來自 AZ-1 上的一個 Kafka 代理的更新。這樣,我們很容易為每個請求增加十幾毫秒的時間。當服務位於同一可用區時,這段寶貴的時間可能會降至不到一毫秒。與成本負擔一樣,你向堆疊中新增的服務越多,這種負擔就越大。
那麼,我們如何才能在不犧牲效能的情況下獲得跨可用區的可靠性?
有什麼辦法可以解決這些額外的資料傳輸成本嗎?
讓我們深入探討這些問題。
解決方法:區域感知路由
區域感知路由(又稱拓撲感知路由)是解決這些問題的方法。在 Unity 的 Aura 中,我們在過去一年逐步推出了此功能。我們發現它在某些系統中節省了 60% 的跨可用區流量。我們瞭解瞭如何利用它來最佳化效能並顯著降低頻寬成本。我們還發現了它不適合用於哪些場景,哪裡應該避免使用它。那麼就讓我們來介紹區域感知路由,以及想要充分利用它需要考慮哪些因素。
什麼是區域感知路由?
區域感知路由是一種策略,旨在透過儘可能將流量引導到同一可用區內的服務來最佳化網路成本和延遲。它最大限度地減少了跨區資料傳輸的需求,從而降低了相關成本和延遲。
區域感知路由的宗旨是透過本地區將來自原始服務的所有或大部分流量傳送到上游服務。理想情況下,透過本地區進行路由還是執行跨區路由,應取決於源服務本地區中上游服務的健康例項百分比。此外,如果當前可用區中的上游服務發生故障或中斷,區域感知路由元件應能夠自動跨可用區對請求重新路由,以保持高可用性和容錯能力。
區域感知路由器的核心應充當一個智慧負載均衡器。在嘗試保持對區域區域性性的感知的同時,它還負責在服務的所有上游例項之間分配每秒相同數量的請求。其目的是避免特定例項受到流量轟炸的情況。這種流量偏差可能導致區域性過載或利用不足,從而導致效率低下並可能產生額外成本。
由於這種性質,區域感知路由在區域流量和資源分佈均勻的環境中非常有用(例如,當你將流量 50/50 分配到具有相同資源量的兩個可用區時)。但是,對於不均勻的區域分佈,由於需要平衡多個區的流量並克服熱點(轟炸和過載例項 - 見圖 2),它可能變得不那麼有效。
圖 2:不均勻區域分佈的圖示。兩個服務位於兩個區。當服務 B 為來自 AZ-2 的所有請求提供服務時,它能否堅持下去?
我如何採用區域感知路由?
區域感知路由的概念有多種實現方式。因此,採用它時要找到適合你的設定和技術棧的實現方式。我們來看一些選項:
Istio 本地負載均衡
Istio 是一個開源的 Kubernetes 服務網格平臺。Istio 可能擁有目前最有前途的區域感知路由實現:本地負載均衡。它是 Istio 中的一項特性,允許根據服務和上游服務例項的本地性,將請求有效地路由到服務最近的可用例項。在 Kubernetes 叢集中安裝和配置 Istio 時,可以根據地理區域、可用區域和子區域因素來定義位置。
Istio 的本地負載均衡使請求可以優先路由到與原始服務位於同一位置(即區域)的上游服務例項。如果與原始服務位於同一位置的服務沒有可用的健康例項,Istio 可以進行故障轉移並將請求重新路由到最近可用位置(例如另一個區甚至另一個區域)的例項。這確保了高可用性和容錯能力。
此外,Istio 允許你為不同的位置定義權重,使你能夠根據容量或優先順序等因素控制跨可用區的流量分佈。這樣,你就可以調整每個區域中保持本地化的流量規模與跨區域傳送的流量規模,從而更輕鬆地平衡不均勻的區域分佈。
拓撲感知路由(又稱拓撲感知提示)
如果你在沒有 Istio 的情況下使用 Kubernetes,可以使用 Kubernetes 的一項原生特性,拓撲感知路由,在版本 1.17 中引入(名為拓撲感知提示)。雖然它比 Istio 提供的功能稍微簡單一些,但它允許 Kubernetes 排程程式根據叢集的拓撲做出智慧路由決策。它考慮拓撲資訊,例如節點的地理位置(例如區域)或可用區,以最佳化 pod 的放置和流量的路由。
Kubernetes 還圍繞此特性提供了一些必要的保護措施。Kubernetes 控制平面將在使用該特性之前應用這些保護規則。如果這些規則不成立,Kubernetes 將不會本地化請求。相反,它將選擇一個例項,不管它在哪個區或區域,以保持高可用性並避免特定區域或例項過載。規則可以評估每個區是否都有可用的服務例項,或者是否確實有可能在區之間實現平衡分配,從而防止在叢集上產生不均勻的流量分佈。
雖然拓撲感知路由可以最佳化跨區流量,並處理使用多個可用區的隱藏效能負擔和成本,但它的能力略遜於 Istio 的區域性負載均衡。主要缺點是它不能像 Istio 那樣處理故障轉移。相反,它的保護措施方法會完全關閉服務的區域區域性性,這是一種更嚴格的設計選擇,要求服務均勻分佈在各個區才能從這些規則中受益。
端到端區域感知路由
使用 Istio 的本地負載均衡或 Kubernetes 拓撲感知路由來維護區域感知路由是解決分散式系統資料傳輸成本和效能瓶頸的重要一步。但是,要實現端到端區域感知路由,並將跨可用區的資料傳輸降至最低,我們還必須確定我們的服務是否能透過本地區從 DB 和訊息佇列(MQ)讀取其資料(見圖 3)。
圖 3:端到端單個可用區本地化的請求流圖示
DB 和 MQ 通常分佈在多個可用區中以實現高可用性,在每個可用區中維護每條資料的副本。這就是為什麼 DB 和 MQ 容易被跨區訪問,從而給系統帶來效能和成本負擔。那麼,我們能否透過本地區訪問資料來最佳化資料庫讀取延遲並降低資料傳輸成本,同時又不影響彈性?
以下是一些可以支援區域感知路由的資料庫和 MQ 示例:
Kafka 的 Follower Fetching 特性
Apache Kafka 是一個開源分散式事件流平臺,用於高效能資料管道、流分析和資料整合。與其他 MQ 一樣,它通常用於連線多個微服務並在分散式系統之間移動資料。
Follower Fetching 是 Kafka 客戶端庫的一項特性,允許消費者優先從本地可用區讀取資料,可以從領導者節點或副本節點讀取。此特性基於 Kafka 的 Rack Awareness 特性,後者旨在透過利用資料中心的物理或邏輯拓撲來增強資料可靠性和可用性。
Kafka 的 Rack Awareness 要求為叢集中的每個代理分配其對應的機架資訊(例如其可用區 ID),以確保主題分割槽的副本分佈在不同的可用區中,從而儘可能降低在可用區或節點發生故障時資料丟失或服務中斷的風險。雖然機架感知不能直接控制客戶端讀取的位置,但它確實允許 Kafka 代理透過機架標籤提供其位置資訊,以便客戶端庫可以使用它來嘗試從位於同一機架或區中的副本讀取資料,或者在本地代理不可用時回退到另一個區。因此,它遵循區域感知路由的概念,可最佳化資料傳輸成本和延遲。要利用 Follower Fetching,我們必須為消費者分配機架標籤,指示它當前從哪個可用區執行,以便客戶端庫可以使用它來定位同一可用區上的代理。
請注意,當使用 Kafka 的 Follower Fetching 特性並且本地代理的複製落後於領導者時,它將增加消費者在該本地區內的等待時間,而不是影響跨區的隨機消費者,從而將某些問題的爆炸半徑限制在本地區。此外,與其他區域感知實現一樣,它對消費者的區域分佈不均情況非常敏感,這可能會導致某些代理過載並要求消費者處理故障轉移。
Redis 和其他區域感知資料庫
Redis 是分散式系統中常用的鍵值資料庫。它是用於高吞吐量、大規模應用程式的快取和其他亞毫秒級查詢的資料庫之一。出於冗餘原因,資料庫通常會分佈在多個可用區中。因此,任何從 Redis 讀取的,分佈在多個地理位置的應用程式都會因為本地區讀取獲得出色的效能和成本效益。
Redis 沒有內建根據客戶端的可用區自動將讀取請求路由到本地副本的能力。但是,我們可以透過某些 Redis 客戶端庫獲得此功能。例如,在使用 Lettuce(一個 Java 庫)時,將客戶端的“ReadFrom”設定為 LOWEST_LATENCY,將讓客戶端從資料延遲最低的副本讀取資料,無論它是在副本還是主節點上。此副本通常駐留在本地區中,因此減少了跨區資料傳輸。
如果你使用的客戶端庫不支援選擇最近的副本,則可以實現自定義邏輯,透過從本地 Redis 端點檢索資料來實現相同的目的。最好在需要時回退到跨可用區端點。
還有一些更流行的資料庫技術支援區域感知路由;以下兩種值得一提:
Aerospike:一種專為高效能資料操作而設計的分散式鍵值資料庫。它具有機架感知功能,與 Kafka 一樣,它為資料庫客戶端提供了一種機制,使其優先從最近的機架或區讀取資料。
Vitess:MySQL 的分散式可擴充套件版本,最初由 Youtube 開發,透過其本地拓撲服務啟用區域感知路由,使其能夠透過本地區域路由查詢。
雖然我們可能會注意到區域感知路由的概念在每項技術中都有略微不同的名稱,但所有這些實現都有相同的目標——在不犧牲服務可靠性的情況下改善讀取延遲和資料傳輸成本。
將我們的 DB 和 MQ 分佈在多個可用區的另一個成本負擔是,我們寫入的每條資料都需要在 DB 叢集本身內複製到每個區域。複製本身可能會導致大量的資料傳輸成本。雖然從技術上來說這是沒辦法的,但必須注意的是,常見的託管 DB 服務(例如 AWS MSK(亞馬遜的 Apache Kafka 託管流)、AWS RDS(亞馬遜關係資料庫服務)、Elasticache(亞馬遜的託管 Redis)等)不會向用戶收取叢集內跨可用區資料傳輸的費用,而只收取進出叢集的資料的費用。因此,如果你計劃複製大量資料,選擇託管服務可能會成為一個重要的成本考慮因素。
處理熱點和不均勻的服務分佈
雖然我們強烈建議大家保持服務在多個區上的均勻分佈,但這並不總是那麼簡單或可行。處理熱點是一個複雜的話題,但解決它的一種方法是考慮為每個區單獨部署和單獨設定自動擴充套件策略。允許服務根據特定區內的流量獨立擴充套件,可以確保如果負載集中在特定區,它將得到充分擴充套件以使用專用資源處理該負載,從而無需回退到其他區。
總 結
在高可用性分散式系統中應對資料傳輸成本和效能是一項真正的挑戰。為了解決這個問題,我們首先需要找出哪些微服務容易發生頻繁的跨可用區資料傳輸。我們需要以資料為導向,衡量跨可用區成本,並跟蹤微服務通訊的延遲,以確保我們的努力方向正確。
然後,我們必須採用適當的工具來消除或最小化這些跨可用區呼叫。採用哪些工具和最佳化取決於我們的技術棧。要端到端採用區域感知路由,我們必須針對不同的用例採用不同的工具。某些工具(如 Istio 和拓撲感知路由規則)旨在為相互通訊的 Kubernetes pod 解鎖區域感知能力。但是,它們不適用於你的微服務從資料庫或訊息佇列跨可用區使用資料的情況。因此,我們必須選擇正確的 DB 和 MQ,並在其客戶端庫中嵌入區域感知路由。
最後,我們必須確保自己不會在不均勻的區域分佈設定中部署這些工具和最佳化,結果破壞系統的高可用性和彈性,這會導致熱點(被流量轟炸的例項)。這樣的部署可能會違背初衷,意味著我們為了解決成本和效能問題卻引入了新的問題。
總體而言,最佳化跨可用區流量至關重要;它會影響我們應用程式的效能、延遲和成本,但必須謹慎處理,以確保我們不會犧牲應用程式的可靠性和高可用性。
作者介紹
Amir Souchami 是 Unity 的 Aura 首席架構師。他對技術充滿熱情,不斷學習最新知識以保持敏銳,創造、擴充套件和推動積極的業務投資回報率。關注他來討論 Gen AI、機器學習、流處理、微服務和 AdTech。
How to Minimize Latency and Cost in Distributed Systems (https://www.infoq.com/articles/minimize-latency-cost-distributed-systems/)
宣告:本文由 InfoQ 翻譯,未經許可禁止轉載。