Istio流量治理的原理——非侵入的流量治理

在Istio 中實現服務治理功能時無需修改任何應用的代碼。較之微服務的SDK方式,Istio以一種更輕便、透明的方式向用戶提供了這些功能。用戶可以使用自己喜歡的任意語言和框架進行開發,專注於自己的業務,完全不用嵌入任何治理邏輯。只要應用運行在Istio的基礎設施上,就可以使用這些治理能力。
一句話總結Istio流量治理的目標:以基礎設施的方式提供給用戶非侵入的流量流量治理能力,用戶只需要關注自己的業務邏輯開發,無需關注服務訪問管理。
Istio了流量治理的概要流程如下:
在控制面會經過如下流程:

  1. 管理員通過命令或API創建流量規則;
  2. Pilot講流量規則轉爲Envoy的標準格式;
  3. Pilot將規則下發給Envoy;

在數據面會經過如下流程:

  1. Envoy 攔截Pod上本地容器的Inbound流量和Outbound流量;
  2. 在流量經過Envoy時執行對應的流量規則,對流量進行治理;

下面具體賴看下Istio提供了哪些流量治理功能。

1、負載均衡

負載均衡從嚴格意義上講兵不應該算治理能力,因爲它只做了服務間互訪的基礎工作,在服務調用方使用一個服務名發起訪問的時候能夠找到一個合適的後端,把流量導過去。
傳統的負載均衡一般是在服務端提供的,例如訪問一個Web服務,一般在網站入口處有一個負載均衡器在請求的匯聚和轉發。服務的虛擬IP和後端實例一般是通過靜態配置文件維護,負載均衡器通過健康檢查保證客戶端的請求被路由到健康的後端實例上。

在微服務場景下,負載均衡一般和服務發現配合使用,每個服務都有多個對等的服務實例,需要一種機制將請求的服務名解析到服務實例地址上。服務發現負責從服務名稱解析一組服務實例的列表,負載均衡負責從中選擇一個實例。
不管是微服務的SDK架構,還是Istio這樣的Service mesh架構,服務發現和負載均衡的工資流程都是類似的,如下所述:

  1. 服務註冊。各服務講服務名和服務實例的對應信息註冊到服務註冊中心(Istio 沒有服務註冊功能)。
  2. 服務發現。在客戶端發起服務訪問時,以同步或異步的方式從服務註冊中心獲取服務對應的實例列表。
  3. 負載均衡。根據配置的負載均衡算法從實例列表中選擇一個服務實例。

Istio的負載均衡正是其中的一個具體應用。在Istio中,Pilot負責維護服務發現數據,Pilot講服務發現數據通過Envoy的標準接口下發給數據面的Envoy,Envoy則根據配置的負載均衡策略選擇一個實例轉發請求。Istio當前支持的主要負載均衡算法包括:輪詢、隨機和最小連接數算法。

在kubernetes上支持Service的重要組件KubeProxy,實際上也是運行在工作節點的一個網絡代理和負載均衡器,它實現了Service模型,默認通過輪詢等方式把Service訪問轉發到後端實例Pod上。

2、服務熔斷

1)Hystrix 熔斷

關於熔斷,大家比較熟悉的一個落地產品就是Hystrix。Hystrix是Netflix提供的衆多服務治理工具集中的一個,在形態上是一個Java庫,在2011年出現,後來躲在spring cloud中配合其他微服務治理工具集一起使用。
Hystrix 的主要功能包括:

  • 阻斷級聯失敗,防止雪崩;
  • 提供延遲和失敗保護;
  • 快速失敗並及時恢復;
  • 對每個服務調用都進行隔離;
  • 對每個服務都維護一個連接池,在連接池滿時直接拒絕訪問;
  • 配置熔斷閾值,對服務訪問直接走失敗處理Fallback,可以定義失敗處理邏輯;
  • 在熔斷生效後,在設定時間後探測是否恢復,若恢復則關閉熔斷;
  • 提供實時監控、告警和操作控制;

Hystrix的熔斷機制基本上與Martin的熔斷機制一致。Hystrix將要保護的過程封裝在一個HystrixCommand中,講熔斷功能應用到調用方法上,並監視對該方法的失敗調用,當失敗次數達到閾值時,後續調用自動失敗並被轉到一個Fallback方法上。在HystrixCommand中封裝的要保護的方法並不要求是一個對遠端服務的請求,可以是任何需要保護的過程。每個HystrixCommand都可以被設置一個Fallback方法,用戶可以寫代碼定義Fallback方法處理邏輯。
在Hystrix的資源隔離方式中除了提供熔斷,還提供了對線程池的管理,減少和限制了單個服務故障對整個系統的影響,提高整個系統的彈性。
在使用上,不管是直接使用Netflix的工具還是Spring Cloud中的包裝,都建議在代碼中寫熔斷處理邏輯,有針對性地進行處理,但是侵入了業務代碼,這也是與Istio比較大的差別。
業界一直以Hystrix作爲熔斷的實現模板,尤其是基於Spring Cloud。但遺憾的是,Hystrix在1.5.18版本後停止了開發和代碼併入,轉爲維護狀態,其代替者是不太知名的Resilience4J。

2)Istio 熔斷

雲原生場景下的服務調用關係更加複雜,前文提到的若干問題也更加嚴峻,Istio提供了一套非侵入的熔斷能力來應對這種挑戰。
與Hystrix類似,在Istio中也提供了連接池和故障實例隔離的能力,只是概念術語稍有不同:前者在Istio的配置中叫做連接池管理,後者叫做異常點檢測,分別對應Envoy的熔斷和異常點檢測。
在Istio 0.8版本前使用V1alpha1接口,其中專門有個CircuitBreaker配置,包含對連接池和故障實例隔離的全部配置。在Istio1.1 V1alpha3 接口中,CircuitBreaker功能被拆分成連接池管理(ConnectionPoolSettings)和異常點檢測(OutlierDetection)這兩種配置,由用戶選擇搭配使用。
首先看看解決的問題,如下所述:

  • 在Istio中通過限制某個客戶端對目標服務的連接數、訪問請求數等,避免對一個服務的過量訪問,如果超過配置的閾值,則快速斷路請求。還會限制重試次數,避免重試次數過多導致系統壓力變大並加劇故障的傳播;
  • 如果某個服務實例頻繁超時或者出錯,則將該實例隔離,避免影響整個服務。

以上兩個應用場景正好對應連接池管理和異常實例隔離功能。
Istio的連接池管理工作機制對TCP提供了最大連接數、連接超時等管理方式,對HTTP提供了最大請求數、最大等待請求數、最大重試次數、每連接最大請求數等管理方式,它控制客戶端對目標服務的連接訪問,在超過配置時快速拒絕。

通過Istio的連接池管理科員控制一個服務對目標服務的請求:

  1. 當該服務對目標服務的請求不超過配置的最大連接數時,放行;
  2. 當該服務對目標服務的請求不超過配置的最大等待請求數時,進入連接池等待;
  3. 當該服務對目標服務的請求超過配置的最大等待請求數時,直接拒絕;

Istio 提供異常點檢測機制動態的將異常實例從負載均衡池中移除,當連續的錯誤數超過配置的閾值時,後端實例會被移除。異常點檢測會在實現上對每個上游服務都進行追蹤,對於HTTP服務,如果有主機連續返回了5XX,則會被提出服務池;TCP6服務,如果有目標服務的連接超時和失敗,則會被標記爲出錯。
另外,被移除的實例在一段時間後,還會被加回來再次嘗試訪問,如果可以訪問成功,則認爲實例正常;如果訪問不成功,則實例不正常,重新被逐出,後面驅逐的時間等於一個基礎時間乘以驅逐的次數。這樣,一個實例經過以上過程的多次嘗試訪問一直不可用,則下次會被隔離的更久。可以看到,Istio的這個流程也是基於Martin的熔斷模型設計和實現的,不同之處在於這裏沒有熔斷半開狀態,熔斷器要打開多長時間取決於失敗的次數。
另外,在Istio中可以控制驅逐比例,既有多少比例的服務實例在不滿足要求時被驅逐。當大多數實例被移除時,就會進入恐慌模式,這時會忽略負載均衡池上實例的健康標記,任然會向所有實例發送請求,以保證一個服務的整體可用性。
下面是Istio和Hystrix的熔斷簡單對比。可以看到與Hystrix相比,Istio實現的熔斷器其實是一個黑盒,和業務沒有耦合,不涉及代碼,只要對服務訪問的保護就可以用,配置比較簡單直接。

比較內容 Hystrix Istio
管理方式 白盒 黑盒
熔斷使用方法 可以實現精細的定製行爲,例如寫Fallbreak處理方法 只用簡單配置即可
和業務代碼結合 業務調用要包裝在熔斷保護的HystrixCommand內,對代碼有侵入、要求時Java代碼 非侵入,語言無關
功能對照 熔斷、隔離倉 異常點檢測、 連接池
熔斷保護內容 大部分是微服務間的服務請求保護,但也可以處理非訪問故障場景 主要控制服務間的請求

熔斷功能本來就是疊加上去的服務保護啊,並不能完全替代代碼中的異常處理。業務代碼本來也公共做好各種異常處理,在發生異常時候通知調用方的代碼或者最終的用戶。
Istio的熔斷能力是對業務透明的,不影響也不關心業務代碼的寫法。當Hystrix開發的服務運行在Istio環境時,兩種熔斷機制疊加在一起。在故障發生時,如果兩者的規則同時存在,則嚴格的規則生效。當然不推薦這種做法,建議業務代碼處理好業務,把治理的事情交給Istio處理。

3、故障注入

對於一個系統,尤其是一個複雜的系統,重要的不是故障會不會發生,二十什麼時候發生。開發人員需要花80%的時間來處理非正常場景。測試人員甚至要花大於80%的時間來執行這些異常測試項,並構造各種故障場景,尤其是那種理論上纔出現的故障,讓人苦不堪言。
故障注入在軟件場景下,使用一種手段故意在待測試的系統中引入故障,以測試其健壯性和應對故障的能力,例如異常處理、故障恢復等。只有當系統的所有服務都經過故障測試且具備容錯能力時,整個應用才健壯可靠。
故障注入從方法上來講有編譯期故障注入和運行期故障注入,前者需要通過修改代碼模擬故障,後者在運行階段出發故障。在分佈式系統中,比較常用的方法是在網絡協議棧中注入對應的協議故障,干預服務間的調用,不用修改業務代碼。Istio的故障注入就是這樣一種機制的實現,但不是在底層網絡層破壞數據包,而是在網絡中對特定的應用層協議進行故障注入,雖然在網絡訪問階段進行注入,但其作用於應用層。這樣,基於Istio故障注入就可以模擬出應用層的故障場景。可以對某種請求注入一個特定的HTTP code。這樣。對於訪問的客戶端來說,就跟服務發生異常一樣。
還可以注入一個指定的延時,這樣客戶端看到的就跟服務端真的響應慢一樣,我們無須爲了達到這種效果在服務端的代碼裏添一段sleep(500)。
實際上,在Istio的故障注入中可以對故障的條件進行各種設置,例如只對某種特定請求注入故障,其他請求任然正常。

4、灰度發佈

在新版本上線時,不管是技術上的考慮產品的穩定性等因素,還是在商業上考慮新版本被用戶接受的程度上,直接全部升級爲新版本是非常有風險的。所以一般的做法是,新老版本同時在線,新版本只切分少量流量出來,在確認新版沒問題後,再逐步加大流量比例。這正是灰度發佈要解決的問題。其核心是能配置一定的流量策略,將用戶在同一個訪問入口的流量導到不同的版本上。有如下幾種典型場景。

  • 藍綠髮布

藍綠髮布主要是,讓新版本部署在另一套獨立的資源上,在新版本可用後,將所有流量從老闆切換到新版本上。當新版本工作正常時,刪除老版本;當新版本工作有問題的時候,快速切回老版本,因此藍綠髮布更像是一種熱部署方式。升級切換和回退的速度都可以非常快,但是快速切換的代價是配置冗餘的資源,既有兩倍的原有資源,分別部署新老版本。另外,流量時全部切換的,所以新版本如果有問題,則所有用戶都受影響。

  • AB測試

AB測試的場景比較明確,就是同時在線上部署A和B兩個對等的版本賴接受流量,按一定的目標選取策略讓一部分用戶使用A版本,讓一部分用戶使用B版本,手機這兩部分用戶的使用反饋,即對用戶採用後做相關比較,通過分析數據來最終決定採用哪個版本。
對於有一定用戶規模的產品,在上線新特性時都比較謹慎,一般都需要經過一輪測試,在AB測試裏面比較重要的是對評價的規劃;要規劃什麼樣的用戶訪問,採集什麼樣的訪問指標,尤其是,指標的選取是與業務相關的複雜過程,所以一般都有一個平臺在支撐,包括業務指標埋點、收集和評價。

  • 金絲雀發佈

金絲雀發佈比較直接,上線一個新版本,從老版本中切分一部分線上流量到新版賴判定新版本在生產環境中的實際表現。先讓一部分用戶嘗試新版本,在觀察到新版沒有問題後再增加切換的比例,直到全部切換完成,是一個漸變、嘗試的過程。
藍綠髮布、AB測試個金絲雀發佈的差別比較細微,有時只有金絲雀才被成爲灰度發佈,這裏不用條糾結這些劃分,只需關注其共同的需求,就是要支持對流量的管理。能否提供靈活的流量策略是判斷基礎設施灰度發佈支持能力的重要指標。

灰度發佈技術上的核心要求時提供一種機制滿足多不同版本同時在線,並能夠靈活配置規則給不同的版本分配流量,可以採用以下幾種方式。
1)基於負載均衡器的灰度發佈
比較傳統的灰度發佈方式是在入口的負載均衡器上配置流量策略,這種方式要求負載均衡器必須支持相應的流量策略,並且只能對入口的服務做灰度發佈,不支持對後端服務單獨做灰度發佈。例如,可以在負載均衡器上配置流量規則對服務A進行灰度發佈,但是沒有地方給服務A的後端服務B配置分流策略,因此無法對服務B做灰度發佈。

2)基於Kubernetes 的灰度發佈
在Kubernetes 環境下可以基於Pod的數量比例分配流量。例如服務A的兩個版本V1和V2分別有兩個和三個實例,當流量被均衡地分發到每個實例上時,前者可以獲得40%的流量,後者60% ,從而達到流量在兩個版本間分配的效果。
給V1和V2版本設置對應比例的Pod數量,依靠Kube-proxy 把流量均衡地分發到目標後端,可以解決一個服務的多個版本分配流量的問題,但是限制也比較明顯:首先。要分配的流量必須和Pod數量成比例;另外,這種方式不支持根據請求的內容來分配流量,比如要求Chrome瀏覽器發來的請求和IE瀏覽器發來的請求分別訪問不同的版本。

3)基於Istio的灰度發佈
不同於前面介紹的熔斷、故障注入、負載均衡等功能,Istio本身並沒有關於灰度發佈的規則定義,灰度發佈只是流量治理規則的一種典型應用,在灰度發佈時,只需要寫個簡單的流量規則配置即可。
Istio在每個Pod都注入了一個Envoy,因爲只要在控制面配置分流策略,對目標服務發起訪問的每個Envoy便都可以執行流量策略,完成灰度發佈功能。
例如對服務A進行灰度發佈,配置20%的流量到V2版本,保留80%的流量在V1版本。通過Istio控制面Pilot下發配置到數據面的各個Envoy,調用服務A的兩個服務B與服務C都會執行同樣的策略,對服務A發起的請求會被各自的Envoy攔截並執行同樣的分流策略。
在Istio中除了支持這種基於流量比例的策略,還支持非常靈活的基於請求內容的灰度策略。比如某個特性是專門爲Mac操作系統開發的,則在該版本的流量策略中需要匹配請求方的操作系統。瀏覽器、請求的Header等請求內容在Istio中都可以作爲灰度發佈的特徵條件。

5、服務訪問入口

一組服務組合在一起可以完成一個獨立的業務共患難,一般都會有一個入口服務,從外部可以訪問,主要是接收外部的請求並將其轉發到後端的服務,有時還可以定義通用的過濾器在入口處做權限、限流等功能。
1)Kubernetes 服務的訪問入口
在Kubernetes中可以將服務發佈成Loadbalancer類型的Service,通過一個外部端口就能訪問到集羣中的指定服務。例如,從外部進來的流量不用經過過濾和多餘處理,就被轉發到服務上。這種方式直接、簡單,在雲平臺上部署的服務一般都可以依賴雲廠商提供的Loadbalancer來實現。
Kubernetes支持另一種Ingress方式專門針對七層協議。Ingress作爲一個總的入口,根據七層協議中的路徑將服務指向不同的後端服務。例如,在”weather.com“這個域名下,可以發佈兩個及多個服務,服務test1被髮布到“weather.com/test1”上,服務test2 被髮布到“weather.com/test2”上,這時只需要一個外部地址。
其中Ingress是一套規則定義,將描述某個域名的特定路徑的請求轉發刀片集羣指定的Service後端上。Ingress Controller作爲Kubernetes的一個控制器,監聽Kube-apiserver的Ingress對應的後端服務,實時獲取後端Service的Endpoint等變化,結合Ingress配置的規則動態更新負載均衡器的路由配置。

2)Istio 服務訪問入口
在Istio中通過Gateway訪問網格的服務。這個Gateway和其他網格內的Sidecar一樣,也是一個Envoy,從Istio的控制面接收配置,統一執行配置的規則。Gateway一般被髮布爲Loadbalancer類型的Service,接受外部訪問,執行治理、TLS終止等管理邏輯,並將請求轉發給內部的服務。
網格入口的配置通過定義一個Gateway的資源對象描述,定義將一個外部訪問映射到一組內部服務上。在Istio 0.8版本以前正是使用Kubernetes的Ingress賴描述服務訪問入口的,因爲Ingress七層的功能限制,Istio 在0.8版本的V1alpha3 流量規則中引入了Gateway資源對象,只定義接入點。Gateway只做四層到六層的端口、TLS配置等基本功能,VirtualService 則定義七層路由等豐富內容。這樣就複用了VirtualService,外部及內部的訪問規則都使用VirtualService賴描述。

6、外部接入服務治理

隨着系統越來越複雜,服務間的依賴也越來越多,當實現一個完整的功能時,只依靠內部的服務是無法支撐的,
例如,四個服務組成一個應用,後端依賴一個數據庫服務,這就需要一種機制能將數據庫服務接入並治理。在當前的雲化場景下,這個數據庫可以是部署的一個外部服務,也可以是一個RDS的雲服務。在託管平臺上搭建的應用一般都會訪問數據庫、分佈式緩存等中間服務。
關於這種第三方服務的管理,專門有一種Open Service Broker API來實現第三方軟件的服務化,這種API通過定義Catalog、Provisioning、Updating、Binding、Unbinding等標準的接口接入服務,在和Kubernetes結合的場景下,使用Service Catalog 的擴展機制可以方便地在集羣中管理雲服務商提供的第三方服務。
Istio 可以方便地對網格內部的服務訪問進行治理,那麼如何對這種網格外的服務訪問進行治理呢?從實際需求來看,對一個數據庫訪問進行管理,比對兩個純粹的內部服務訪問進行管理更重要。在Istio中是通過一個ServiceEntry 的資源對象將網格外的服務註冊到網格上,然後像對網格內的普通服務一樣對網格外的服務訪問進行治理。
關於ServiceEntry的配置方式,後續會專門講到。ServiceEntry是Istio中對網格外部的服務的推薦使用方式,當然也可以選擇不治理,直接讓網格內的服務訪問網格外的服務。
在大多數情況下,在訪問網格外的服務時,通過網格內服務的Sidecar就可以執行治理功能,但有時需要一個專門的Egress Gateway 賴支持。出於對安全或者網絡規劃的考慮,要求網絡內所有外發的流量都必須經過這樣一組專門節點,需要定義一個Egress Gateway並分配Egress節點,將所有的出口流量都轉發到Gateway上進行管理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章