服務級故障是雲上雲原生業務可能遭遇到的一類較為常見的故障類型,故障範圍將小於可用性區域層級,但仍會因為服務單點故障造成業務不可用或降級問題。服務網格ASM支援打通多個叢集的服務發現以及網路互訪,結合多地區、多叢集的服務對等部署模式,在任意的服務發生故障時,只要叢集中還存在可用的服務工作負載執行個體,Service Mesh (ASM)都可以秒級對流量目標實現無感切換,保證業務應用在全域的可用性。本文介紹如何使用服務網格應對服務級故障容災。
容災架構
容錯移轉機制:服務網格基於地理位置的容錯移轉
ASM支援基於地理位置的容錯移轉機制。通過持續檢測一段時間視窗內,工作負載是否連續發生響應錯誤來判斷工作負載的故障狀態,並在工作負載故障時自動將流量目標轉移到其他可用的工作負載上。
以下以分別位於兩個不同地區的叢集為例,在其中對等部署兩套應用。每個叢集的每個服務的工作負載通過拓撲分布約束(Topology Spread Constraints)均勻分布在不同可用性區域。
-
正常流量拓撲。
在服務均為正常的情況下,服務網格會將流量保持在同一可用性區域,以最小化調用目標位置對請求延遲的影響。
-
工作負載異常時,按照地理位置規劃自動容錯移轉。
當ASM檢測到工作負載連續出現響應錯誤的情況,會將該服務剔除出負載平衡池,以將請求目標轉移到其它可用的工作負載上。流量容錯移轉會按照如下的優先順序順序進行:
-
其他同可用性區域的工作負載。
-
同地區不同可用性區域的工作負載。
同時,通過配置Prometheus執行個體採集服務網格相關指標,當容錯移轉發生時,可通過指標警示通知到相關業務連絡人。
-
-
跨地區流量轉移。
當同地區下的可用性區域都沒有可用的工作負載時,還可以將流量轉移到另一個地區下其他叢集中對等部署的相同服務。此過程由服務網格自動完成。
在這種情況下,需要依賴兩個叢集之間的路由打通:即從A叢集的Pod可以連通B叢集的Pod。對於阿里雲多地區的情境,此時可以選擇使用CEN(雲企業網)打通叢集之間的物理網路、實現叢集互連。此方案需要對叢集網路(Pod、Service、VPC CIDR等)進行規劃,並藉助雲企業網執行個體實現跨地區網路打通,適用於對跨地區流量具有高品質要求的客戶。
而IDC/三方雲廠商的叢集,往往存在由於網路規劃無法將物理網路打通的限制。針對這種情況,ASM提供了通過跨叢集網路代理程式的方式,在叢集間建立一條mTLS的安全通道,用於必要的跨叢集通訊和實現安全的跨地區流量轉移。但基於品質有限的公網通訊,該方案適用於對叢集間通訊具有非強需求、或因現實原因導致叢集物理網路衝突的使用者。
應用部署拓撲:多種叢集拓撲的支援方式及對比
ASM基於地理位置的容錯移轉機制可以無縫應用在多種應用部署的拓撲方式之中,不同的部署拓撲會有故障維度支援範圍以及資源成本、營運門檻上的區別。可根據實際資源及應用狀況選擇。
-
單叢集多可用性區域部署。
此方式為容災中最簡單的部署方式。通過配置多可用性區域(AZ)節點池,為節點池選擇多AZ的虛擬交換器,並在配置擴縮容策略時選擇均衡分布策略,即可在伸縮組指定的多可用性區域之間均勻分配ECS執行個體。
此方式的優缺點對比:
優點
缺點
只需要開通一個包含多可用性區域節點池的ACK叢集、並通過拓撲分布約束(Topology Spread Constraints)在可用性區域間均勻部署應用。
無法處理由於Kubernetes錯誤配置、應用程式依賴等造成的故障。
負載平衡、資料庫、Kubernetes叢集、服務網格等雲資源只需要在同一地區內準備一份。
無法處理地區層級的故障。
-
單地區多可用性區域多叢集部署。
在單叢集多可用性區域基礎上,將單叢集擴充為多叢集,每個叢集各自擁有一套配置。當容錯移轉發生時,ASM會優先尋找同可用性區域的其他工作負載、接著會在同地區不同可用性區域的其他可用工作負載中任選一個作為容錯移轉目標。同時,建議為兩個叢集分別選擇各自獨立的可用性區域。如果兩個叢集的可用性區域重合,可能會造成同可用性區域的工作負載優於同叢集工作負載的狀況,這對業務來說有可能是非預期的。
此方式的優缺點對比:
優點
缺點
相比單叢集部署來說,該拓撲拓展了覆蓋的故障成因維度,進一步提高了系統整體的可用性。
需要將服務對等地部署在兩個Kubernetes叢集環境內,部署和營運複雜度較高。負載平衡、Kubernetes叢集等雲資源基礎設施需要部署多份,成本較高。
只需要兩個叢集在同一VPC內部即可。當需要將流量容錯移轉到另一個叢集中的服務時,此種部署拓撲具有較低的叢集互連成本。
無法處理地區層級的故障。
說明-
在此種部署拓撲下,您需要對多個叢集的網路設定進行規劃、避免出現網路衝突的情況。具體操作,請參見多叢集網路規劃。
-
不建議將多叢集多可用性區域單地區部署作為首選方案,因為其在顯著增加部署營運複雜度的同時,沒有帶來與之相應的最進階別可用性。
-
-
多地區多叢集部署。
在多叢集的基礎上,將單地區部署變為多地區部署。可以保證每個服務的部署在不同的維度上都是分散的:它們擁有不同的可用性區域、部署地區、部署叢集、部署依賴。通過這種方式,可以儘可能地保證在發生任何可能原因導致的故障時,都有正常的工作負載在提供服務。
此方式的優缺點對比:
優點
缺點
可以將同一服務的工作負載分散到不同地區、不同可用性區域、不同叢集,以提高服務的可用性。
需要將服務對等地部署在兩個Kubernetes叢集環境內、且為了更好的推送延遲表現,服務網格執行個體也需要準備兩份。
基於多主控制面架構,可以有效控制延遲問題。
跨地區網路互連較為複雜。
當您有高可用層級的需求時,推薦採用這種拓撲進行業務應用的部署。在需要跨叢集網路打通情境下,可選用以下兩種方式進行叢集網路的打通:
-
使用雲企業網直接打通跨地區叢集底層網路。首先您需要對多個叢集的網路設定進行規劃,以避免出現網路衝突的情況。具體操作,請參見多叢集網路規劃。接下來,使用雲企業網打通跨地區網路。具體操作,請參見跨地區串連。
-
使用ASM跨叢集網路代理程式實現跨叢集網路打通和容錯移轉,以最佳化資源成本並解決複雜網路互連問題。使用這種方式,兩個叢集的網路可以不直接互連、不需要進行叢集網路規劃,有關ASM跨叢集網路代理程式的細節,請參見不同VPC下多ACK叢集的容災情境(基於ASM跨叢集網格代理實現網路互連)。
-
-
多雲多地區多叢集部署。
此部署拓撲是最進階別的部署拓撲方式。ASM完全支援管理任意雲供應商以及線下IDC的Kubernetes叢集,通過在不同雲供應商之間、或是雲上和雲下兩套Kubernetes叢集環境,以保證任一基礎設施在發生故障時仍可以由其他基礎設施提供服務。
與多地區多叢集類似,多雲多地區多叢集部署的方式同樣需要進行叢集網路的打通。但ASM無法在非阿里雲環境提供託管控制面,可以使用ASM遠端控制面來解決服務網格在跨雲情況下的推送延遲問題。具體操作,請參見使用ASM遠端控制面降低推送延遲。
此方式的優缺點對比:
優點
缺點
可以將同一服務的工作負載分散到不同地區、不同可用性區域、不同叢集、不同雲廠商,以提高服務的可用性。
需要將服務對等地部署在兩個Kubernetes叢集環境內。同時,由於雲廠商之間基礎架構以及雲產品能力的不同,在多雲環境下的部署可能遭遇大量的相容性以及其他未知問題。
基於多主控制面架構,可以有效控制延遲問題。
跨地區網路互連較為複雜。
容災配置實踐
以下以多地區多叢集部署方式為例,示範服務級容災實踐流程。
步驟一:環境準備
-
在兩個地區分別建立一個Kubernetes叢集,命名為cluster-1和cluster-2,並且都配置了多個可用性區域和開啟了使用 EIP 暴露 API server。具體操作,請參見建立ACK託管叢集。
-
在與ACK叢集相同的兩個地區,分別建立ASM執行個體mesh-1和mesh-2,並確保建立時交換器選擇了與ACK叢集相同的可用性區域。具體操作,請參見通過ASM多主控制面架構實現多叢集容災的步驟一、步驟二與步驟三。
-
部署ASM網關和樣本服務。
-
在mesh-1、mesh-2中分別建立名為ingressgateway的NLB類型入口網關,NLB可用性區域選擇和ASM執行個體與ACK叢集同樣的兩個可用性區域。具體操作,請參見在ASM入口網關中使用網路型負載平衡NLB。
-
在mesh-1、mesh-2中為兩個叢集的default命名空間開啟Sidecar自動注入。具體操作,請參見管理全域命名空間。
-
在兩個ACK叢集內對等部署樣本應用,樣本使用的四個可用性區域分別是:cn-hangzhou-h、cn-hangzhou-k、ap-northeast-1a、ap-northeast-1b。您可以按照實際情況調整部署命令中的YAML。
上述命令分別在兩個叢集中執行後,會在兩個叢集中對等部署了一個包含名為mocka、mockb、mockc的服務的應用,每個服務下包含兩個只有1副本的無狀態部署,分別通過不同的NodeSelector分布到不同可用性區域的節點上,並通過配置環境變數來返回自己所在的可用性區域。
說明出於直觀示範的目的,本樣本使用了NodeSelector欄位來手動選擇Pod所在的可用性區域。在實際高可用環境的構建中,您應該配置拓撲分布約束,來保證Pod儘可能分布在不同的可用性區域中。具體配置方法,請參見工作負載高可用配置。
-
-
配置全域流量管理GTM,結合NLB執行個體實現入口網關多活容災。具體操作,請參見GTM如何?多活負載並容災。
步驟二:開啟基於地理位置的容錯移轉
ASM預設開啟了基於地理位置的容錯移轉能力,但需要結合目標規則中設定的主機級熔斷規則才可以生效。
-
分別在cluster-1和cluster-2叢集中部署主機級熔斷規則。
kubectl apply -f- <<EOF apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: mocka spec: host: mocka trafficPolicy: outlierDetection: splitExternalLocalOriginErrors: true consecutiveLocalOriginFailures: 1 baseEjectionTime: 5m consecutive5xxErrors: 1 interval: 30s maxEjectionPercent: 100 --- apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: mockb spec: host: mockb trafficPolicy: outlierDetection: splitExternalLocalOriginErrors: true consecutiveLocalOriginFailures: 1 baseEjectionTime: 5m consecutive5xxErrors: 1 interval: 30s maxEjectionPercent: 100 --- apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: mockc spec: host: mockc trafficPolicy: outlierDetection: splitExternalLocalOriginErrors: true consecutiveLocalOriginFailures: 1 baseEjectionTime: 5m consecutive5xxErrors: 1 interval: 30s maxEjectionPercent: 100 EOF其中outlierDetection是服務網格對於服務故障的檢測及故障端點驅逐機制,配置項說明如下:
配置項
說明
interval
故障檢測的時間。
baseEjectionTime
端點被判斷為故障後,需要多久將端點從負載平衡池中驅逐。
maxEjectionPercent
最大被驅逐端點比例。
consecutive5xxErrors
端點被判斷為故障前連續返回
5xx錯誤的數量。splitExternalLocalOriginErrors
是否將串連失敗、連線逾時等情況算作故障情況。
consecutiveLocalOriginFailures
端點被判斷為故障前連續產生非5xx錯誤(即串連失敗、連線逾時等情況)的數量。
-
驗證服務狀態。
向服務網域名稱發出請求。
curl mock.asm-demo.work/mock -v預期輸出:
* Host mock.asm-demo.work:80 was resolved. * IPv6: (none) * IPv4: 8.xxx.xxx.47, 8.xxx.xxx.42 * Trying 8.xxx.xxx.47:80... * Connected to mock.asm-demo.work (8.209.XXX.XX) port 80 > GET /mock HTTP/1.1 > Host: mock.asm-demo.work > User-Agent: curl/8.7.1 > Accept: */* > * Request completely sent off < HTTP/1.1 200 OK < date: Wed, 11 Dec 2024 12:10:56 GMT < content-length: 153 < content-type: text/plain; charset=utf-8 < x-envoy-upstream-service-time: 3 < server: istio-envoy < * Connection #0 to host mock.asm-demo.work left intact -> mocka(version: ap-northeast-1b, ip: 10.1.225.40)-> mockb(version: ap-northeast-1b, ip: 10.1.225.31)-> mockc(version: ap-northeast-1b, ip: 10.1.225.32)%可以看到,服務調用鏈路始終保持在同一可用性區域的工作負載上。
步驟三:故障演練
以下通過手動替換mockb服務在某個可用性區域的容器鏡像來類比工作負載故障的情況。
-
替換cluster-2中的mockb-ap-northeast-1a的鏡像類比故障。
登入Container Service管理主控台,在左側導覽列選擇叢集列表。
在叢集列表頁面,單擊目的地組群名稱,然後在左側導覽列,選擇。
-
挑選清單中mockb工作負載右側操作列的編輯,更換鏡像為
registry.cn-hangzhou.aliyuncs.com/acs/curl:8.1.2,同時在啟動執行的命令中增加["sleep","3600"],讓容器可以正常啟動。單擊更新。
-
持續訪問應用網域名稱,查看發生故障後的請求鏈路。
curl mock.asm-demo.work/mock -v預期1:請求發送到非
ap-northeast-1a可用性區域時。* Host mock.asm-demo.work:80 was resolved. * IPv6: (none) * IPv4: 8.209.XXX.XX, 8.221.XXX.XX * Trying 8.209.247.47:80... * Connected to mock.asm-demo.work (8.209.247.47) port 80 > GET /mock HTTP/1.1 > Host: mock.asm-demo.work > User-Agent: curl/8.7.1 > Accept: */* > * Request completely sent off < HTTP/1.1 200 OK < date: Wed, 11 Dec 2024 12:10:56 GMT < content-length: 153 < content-type: text/plain; charset=utf-8 < x-envoy-upstream-service-time: 3 < server: istio-envoy < * Connection #0 to host mock.asm-demo.work left intact -> mocka(version: ap-northeast-1b, ip: 10.1.225.40)-> mockb(version: ap-northeast-1b, ip: 10.1.225.31)-> mockc(version: ap-northeast-1b, ip: 10.1.225.32)%可以看到,請求仍然保持在正常可用性區域內。
預期2:請求首次發送到
ap-northeast-1a可用性區域時。* Host mock.asm-demo.work:80 was resolved. * IPv6: (none) * IPv4: 112.124.XX.XXX, 121.41.XXX.XXX * Trying 112.124.65.120:80... * Connected to mock.asm-demo.work (112.124.65.120) port 80 > GET /mock HTTP/1.1 > Host: mock.asm-demo.work > User-Agent: curl/8.7.1 > Accept: */* > * Request completely sent off < HTTP/1.1 200 OK < date: Wed, 11 Dec 2024 12:08:45 GMT < content-length: 220 < content-type: text/plain; charset=utf-8 < x-envoy-upstream-service-time: 48 < server: istio-envoy < * Connection #0 to host mock.asm-demo.work left intact -> mocka(version: cn-hangzhou-h, ip: 192.168.122.135)upstream connect error or disconnect/reset before headers. reset reason: remote connection failure, transport failure reason: delayed connect error: Connection refused%可以看到,請求到達mockb服務時發生串連被拒絕的情況。
預期3:請求再次發送到
ap-northeast-1a可用性區域時。* Host mock.asm-demo.work:80 was resolved. * IPv6: (none) * IPv4: 8.209.XXX.XX, 8.221.XXX.XX * Trying 8.209.247.47:80... * Connected to mock.asm-demo.work (8.209.247.47) port 80 > GET /mock HTTP/1.1 > Host: mock.asm-demo.work > User-Agent: curl/8.7.1 > Accept: */* > * Request completely sent off < HTTP/1.1 200 OK < date: Wed, 11 Dec 2024 12:10:59 GMT < content-length: 154 < content-type: text/plain; charset=utf-8 < x-envoy-upstream-service-time: 4 < server: istio-envoy < * Connection #0 to host mock.asm-demo.work left intact -> mocka(version: ap-northeast-1a, ip: 10.0.239.141)-> mockb(version: ap-northeast-1b, ip: 10.1.225.31)-> mockc(version: ap-northeast-1b, ip: 10.1.225.32)%可以看到,請求轉移到了同地區不同可用性區域的
ap-northeast-1b。
(可選)步驟四:佈建服務級故障產生時的警示
-
您可以通過配置Sidecar代理的proxyStatsMatcher,使Sidecar代理上報相關指標,然後使用Prometheus採集並查看熔斷相關指標。
-
通過proxyStatsMatcher配置Sidecar代理上報熔斷指標。在配置proxyStatsMatcher時,選中正則匹配,配置為
.*outlier_detection.*。具體操作,請參見proxyStatsMatcher。部分熔斷指標說明如下:
指標
指標類型
描述
envoy_cluster_outlier_detection_ejections_active
Gauge
當前被驅逐的主機的數量。
envoy_cluster_outlier_detection_ejections_enforced_total
Counter
發生主機被驅逐事件的次數。
envoy_cluster_outlier_detection_ejections_overflow
Counter
因超過最大驅逐百分比而放棄驅逐主機的次數。
ejections_detected_consecutive_5xx
Counter
檢測到主機連續產生5xx錯誤的次數。
-
重新部署httpbin無狀態工作負載。具體操作,請參見重新部署工作負載。
-
-
建立針對主機級熔斷的警示規則。
-
為資料面叢集接入阿里雲ASM組件或升級至最新版,以保證可觀測監控Prometheus版可以採集到暴露的熔斷指標。有關更新接入組件的具體操作,請參見接入組件管理。(若您已經通過整合自建Prometheus實現網格監控配置了通過自建Prometheus採集服務網格指標,則本步驟可以忽略。)
-
建立針對主機級熔斷的警示規則。具體操作,請參見建立Prometheus警示規則。
配置警示規則的關鍵參數的填寫樣本如下,其餘參數可參考上述文檔根據自身需求填寫。
參數
樣本
說明
自訂PromQL語句
(sum (envoy_cluster_outlier_detection_ejections_active) by (cluster_name, namespace)) > 0
樣本通過查詢envoy_cluster_outlier_detection_ejections_active指標來判斷當前叢集中是否有正在被驅逐的主機,並將查詢結果按照服務所在命名空間和服務名稱進行分組。
警示內容
觸發主機級熔斷,有工作負載連續發生錯誤,從服務負載平衡池中被驅逐!命名空間:{{$labels.namespace}},驅逐發生的服務:{{$labels.cluster_name}}。驅逐數量:{{ $value }}
樣本的警示資訊展示了觸發熔斷的服務所在命名空間以及服務名稱,以及當前該服務被驅逐的數量。
-