趙化冰,騰訊云高級工程師,Istio Member,ServiceMesher管理委員,Istio 專案貢獻者, Aerika 專案創建者 ,熱衷于開源、網路和云計算,目前主要從事服務網格的開源和研發作業,
唐陽,知憾訓礎架構工程師,Istio 專案貢獻者,Argo 專案貢獻者,專注于開源,云原生與微服務,目前負責知乎服務網格的研發作業,
備注:本文根據騰訊云趙化冰和知乎唐陽在 IstioCon 2021 中的演講 “How to Manage Any Layer-7 Traffic in an Istio Service Mesh?” 整理而成,
大家好,今天我們想和大家分享的主題是如何擴展 Istio 以支持任何七層協議?作為云原生領域中一個人氣非常高的開源專案, Istio 目前已經基本成為了 Service Mesh 的事實標準,騰訊云上也提供了基于 Istio 進行增強,和 Istio API 完全兼容的 Service Mesh 管理服務 TCM(Tencent Cloud Mesh),以幫助我們的用戶以較小的遷移成本和維護代價快速利用到 Service Mesh 提供的流量管理和服務治理能力,今天非常高興能夠有這個機會來和大家一起分享一下我們在此程序中的一些經驗,
Service Mesh 提供了一個對應用透明的基礎設施層,可以解決我們在分布式應用/微服務中遇到的常見挑戰,例如:如何找到服務提供者?如何保證服務之間的通信安全?如何得知服務之間的呼叫關系?如何進行流量管理如灰度發布?等等,Service Mesh 的實作方式是伴隨應用部署一個 Sidecar Proxy,該 Sidecar Proxy 會攔截應用的出向和入向流量, 對這些流量進行分析和處理,以達到在不修改應用代碼的情況下對服務進行流量管理、安全加密,遙測資料收集的目的,為了實作這些服務治理能力,Sidecar Proxy 不只需要在 OSI 網路模型的三、四層上對流量進行處理,更重要的是需要在七層上進行處理,在七層上,Istio 預設只支持了 HTTP 和 gPRC 兩種協議,但我們在微服務中經常還會使用到的其他七層協議,當將這些微服務應用遷移到 Service Mesh 時,我們希望使用一致的方式對所有的這些七層協議進行統一管理,以充分利用 Service Mesh 基礎設施提供的云原生能力,
在今天的分享中,我將會介紹幾種將 Istio 流量管理能力擴展到其他七層協議的方法,并對比分析這幾種方法各自的優缺點,我會介紹如何利用 Aeraki 開源專案來在 Istio 中管理任何七層協議,包括 Dubbo、Thrift、Redis 等,為了讓大家了解 Aeraki 是如何作業的,會展示一個采用 Aeraki 實作 Thrift 服務 Traffic Splitting 的例子,來自知乎的唐陽還會為我們展示如何使用 Aeraki 的一些有趣的真實案例,
Service Mesh 中常見的七層協議
如下圖所示,一個典型的微服務應用中通常會使用到這些七層協議:
- 同步呼叫:不同服務之間會采用 RPC (遠程方法呼叫)進行相互呼叫,常見的 RPC 呼叫協議包括 gRPC,Thrift,Dubbo,HTTP 也可以看做一種 RPC (只支持 GET/SET/POST 這幾種標準方法) ,一些大的公司為了滿足自己特定業務場景的需求,往往還會采用一些私用的 RPC 協議,
- 異步訊息:除了 RPC 之外,異步訊息也是微服務通信的一種常見模式,包括 Kafka,RabbitMQ,ActiveMQ 等,
- 各種資料庫和快取系統:例如 Redis, MySQL,MongoDB 等等,

那么當將這樣一個微服務應用加入到 Service Mesh 以后,我們希望能夠通過 Service Mesh 得到哪些管理能力呢?
理想情況下,我們希望 Service Mesh 能夠管理微服務中用到的所有七層協議的流量,包括 RPC、Messaging、Cache、DB等,例如:
- 基于請求的負載均衡:可以將來自同一個 TCP 鏈接的多個獨立的請求分發到不同的后端服務器,以實作更智能,更合理的負載均衡,
- 基于七層 Header 的流量路由:根據七層 Header 中的屬性進行路由,例如根據 Dubbo 請求中的服務名或者 Redis 請求的 Key 進行路由,
- 對客戶端的請求回應注入延遲或者錯誤,以測驗應微服務用的彈性,
- 提供應用級安全,例如基于 HTTP Header 中的 JWT Token 進行認證,或者對 Redis 服務器進行認證,
- 請求層面的遙測資料,包括請求成功率、請求耗時、呼叫跟蹤等等,

要實作以上這些流量管理和服務治理能力,Service Mesh 需要分析和處理 TCP 資料包中的七層協議的 Header,即 Service Mesh 必須具有七層協議的管理能力,而不只是在 TCP 層面上進行處理,
然而在 Istio 中,對于除了 HTTP 和 gRPC 之外的協議,我們只能在 OSI 三到六層對這些協議進行處理,這意味著我們只能基于三層的 IP 地址,四層的 TCP 埠或者六層的 SNI(Server Name Indication)對這些協議進行路由,只能收集到 TCP 層面的指標,例如 TCP 收發包數量或者打開/關閉的 TCP 鏈接數量,只能采用 mTLS 進行鏈路層面的認證和權限控制,換而言之,對于這些協議,我們依然需要在應用代碼中處理流量控制、可觀測性、安全認證這些本應該由 Service Mesh 基礎設施來統一處理的共性問題,這違背了我們將微服務遷移到 Service Mesh 的初衷:將微服務通信和治理的共性問題從應用代碼下沉到 Service Mesh 基礎設施層,

如何擴展 Istio 的協議管理能力?
如果我們希望能夠在 Istio 中管理這些七層協議,我們應該如何實作呢?假設我們有一個 BookInfo 微服務,但該微服務采用了一種稱為 AwesomeRPC 的協議而不是 HTTP 來實作服務間的遠程呼叫,

我們來看一下如何才能夠在 Istio 中實作 AwesomeRPC 協議的流量管理,例如根據請求 header 中的 user name 欄位將來自 ProductPage 的請求路由到不同版本的 Reviews 中,以實作一個灰度發布的場景,
我們想到的最顯而易見的方式就是直接修改 Istio 代碼,首先我們需要在 Istio 的 VirtualService CRD 中支持 AwesomeRPC 協議,增強后的 VirtualService CRD 如下圖中最左的規則配置所示, AwesomeRPC 和 HTTP 路由的語意類似,都是根據 Header 中某些屬性的值進行路由,因此我們只需要將 HTTP 協議型別改為 AwesomeRPC,可以直接采用 VirtualService 中的 HTTPRoute 結構來表示 AwesomeRPC 的路由規則,然后我們需要在 Pilot 代碼中根據 AwesomeRPC 的服務定義和 VirtualService 定義的路由規則生成 Envoy 所需的真實配置,并通過 xDS 下發給資料面的 Envoy,當然,以上的前提是我們已經通過 Envoy 的 Filter 擴展機制撰寫了 AwesomeRPC 的 Filter 插件,實作 AwesomeRPC 的編解碼,Header 決議,動態路由等資料面所需的功能,

采用這種方式,在 Envoy Filter 已經實作了的情況下,在控制面增加一個新的七層協議的程序是相對比較簡單的,但是由于我們修改了 Istio 的原始碼,因此需要自己維護一個 Istio 的私有分支,這導致了額外的維護代價,并且很難跟上 Istio 快速的迭代步伐,
如果不希望維護自己的 Istio 代碼分支,一種可行的替代方式是采用 Istio EnvoyFilter CRD:EnvoyFilter 是 Istio 提供的一種靈活強大的配置機制,我們可以使用 EnvoyFilter為 Pilot 生成的預設 Envoy 配置打一個補丁,添加、修改或者洗掉預設 Envoy 配置中的部分內容,以按我們的要求修改 Envoy 在 Istio Service Mesh 中的預設行為,
如下圖所示,由于 Pilot 并不理解 AwesomeRPC 協議,對于 Pilot 來說, AwesomeRPC 服務只是一個 TCP 服務,在 Pilot 生成的預設配置中,AwesomeRPC 服務對應的 Outbound Listener 的 FilterChain 中采用了一個 TCP Proxy 來處理其流量,我們在 EnvoyFilter 的 Match 部分中選中該 TCP Proxy,并在 Operation 部分將其替換為一個配置了 Traffic Splitting 規則的 AwesomeRPC Filter,Pilot 會根據 EnvoyFilter 修改其生成的預設 Envoy 配置,然后下發到資料面的 Envoy 上,這樣我們就通過 EnvoyFilter 在 Istio 中實作了對 AwesomeRPC 協議的支持,

下面我們來看一個采用 Thrift 協議的真實案例,Thrift 是 Apache 基金會下一個輕量級、支持多語言的開源 RPC 框架,Envoy 中已經支持 Thrift,但 Istio 中只對 Thrift 提供了有限的支持,并不能實作 Traffic Splitting 等高級流量管理功能,如果我們希望在 Istio 中提供下圖中右下角所示 Thrif 服務的 Traffic Splitting 流量控制,我們可以通過 EnvoyFilter 來實作,
(本示例相關原始碼可以從 https://github.com/aeraki-framework/thrift-envoyfilter-example 下載)

首先,我們需要創建一個圖中左邊所示的 EnvoyFilter 來處理客戶端的出向流量,該 EnvoyFilter 的 Match 條件選中了 $(thrift-sample-server-vip)_9090 這個 Outbound Listener 中 的 tcp_proxy,在 Patch 部分將其替換為一個 thrift_proxy,在該 thrift_proxy 中,我們按照 Traffic Splitting 的要求為其配置了相應的路由:將 30% 的流量路由到 Server v1版本,70% 的流量路由到 Server v2 版本,我們也需要為 Thrift Server 端創建一個如圖右上所示的 EnvoyFilter 來處理服務器端的入向流量,相比客戶端的 EnvoyFilter 而言,服務器端的 EnvoyFilter 配置要簡單一些,因此我們不需要在服務器端配置任何路由規則,只需要將 tcp_proxy 替換為 thrift_proxy 即可,這個 thrift_proxy 雖然沒有路由規則,但提供了大量七層的服務通信和治理能力,包括請求層面的負載均衡、產生請求層面的 Metrics 資料等,
從上面的介紹和示例可以看到, EnvoyFilter CRD 好比是 Istio 中的一把瑞士軍刀,可以對 Pilot 生成的 Envoy 配置進行非常靈活的定制,以達到對七層協議進行管理的目的,但是 EnvoyFilter 也帶來了一些難以處理的問題:
- EnvoyFilter 將 Envoy 的底層實作細節直接暴露給了運維人員:運維人員必須非常了解 Envoy 的配置細節,而這些配置細節往往和 Envoy Filter 內部的實作機制緊密相關,例如 Filter 的名稱和 Filter 內部的配置格式等,這導致創建 EnvoyFilter 成為了一種和代碼細節高度耦合的作業,難以直接交付給運維人員,更為合理的方式則應該是采用一種面向用戶的高級配置語言來屏蔽這些實作細節,例如 Istio 中的 VirtualService 和 DestinationRule,
- EnvoyFilter 中的匹配條件依賴于 Pilot 生成的 Envoy 配置中的結構組成和元素命名,例如 Listener 的名稱,FilterChain 的構成等,而這些結構和命名在不同的 Istio 版本之間可能發生變化,導致原本能夠正常作業的 EnvoyFilter 在新版本中出現問題,
- EnvoyFilter 中的匹配條件還依賴于一些和特定 K8s 集群相關的內容,例如 Service Cluster IP,這意味著一個 EnvoyFilter 不能用于多個不同集群中的相同服務,當 Service 被重建時,由于 Cluster IP 會發生變化,相應的 EnvoyFilter 也必須進行改動,修改 Match 條件中的 Cluster IP,
- 我們需要為每個 Service 創建相應的 EnvoyFilter,當 Mesh 中管理的服務較多時,手動創建成百上千的 EnvoyFilter 的作業是非常繁瑣而且及易出錯的,
- 對 Istio 而言,EnvoyFilter 中的 Patch 部分基本上是一個黑盒,因此 Istio 只能對 EnvoyFilter 的正確性進行非常有限的驗證,這導致 EnvoyFilter 的除錯非常困難,當 Envoy 未能按照你的設想作業時,你很難知道到底是 EnvoyFilter 的什么地方出現了問題,
由于上述的種種問題,我們可以看到,雖然可以使用 EnvoyFilter 來在 Istio 中實作七層協議的管理,但是在一個生產系統,特別是一個中大型的 Service Mesh 中管理和維護這些 EnvoyFilter 是非常困難的,
Aeraki:在 Istio 中管理任何七層協議
由于難以手動對 EnvoyFilter 進行管理和維護 ,我們創建了Aeraki (發音:[Air-rah-ki])專案來自動化這個流程,Aeraki 是希臘語中“微風”的意思,我們希望 Aeraki 這股微風能幫助 Istio 在云原生的旅程中航行得更遠,
Aeraki 的基本作業原理如下圖所示:Aeraki 從 Istio 中拉取服務資料,根據 ServiceEntry 和 Aeraki 流量規則生成 Envoy 配置,并采用 EnvoyFilter 將生成的配置推送到 Istio 中,簡而言之,你可以把 Aeraki 看做 Istio 中管理的七層協議的 Operator ,

相比于直接修改 Istio 代碼和采用 EnvoyFilter 這兩種擴展 Istio 流量管理能力的方式,采用 Aeraki 為我們帶來了以下的好處:
- 不需要修改 Istio 代碼,因此節省了單獨維護一個 Istio 的私有代碼分支的額外作業量,可以快速跟隨 Istio 的版本迭代進行升級,
- Aeraki 作為一個獨立組件部署在 Mesh 的控制面,可以很方便地作為一個插件和 Istio 進行集成,對 Istio 的流量管理能力進行擴展,
- 協議相關的預設配置由 Aeraki 自動生成,并且這些配置可以根據 Istio 版本和 K8s 集群相關資訊自動進行調整,節約了大量 EnvoyFilter 的手動創建和維護作業,
- Aeraki 在 Envoy 配置之上進行了抽象,提供了一層面向用戶的配置 CRD 來對這些七層協議進行管理,這些高級 CRD 隱藏了 Envoy 的配置細節,屏蔽了不同 Istio 版本生成的預設 Envoy 配置的差異,對于運維非常友好,對于 Thrift 和 Dubbo 這樣的 RPC 協議,由于其語意和 HTTP 類似,Aeraki 直接采用了 Istio VirtualService 和 DestinationRule;對于非 RPC 協議,Aeraki 則定義了一些新的 CRD 來進行管理,例如 RedisService 和 RedisDestination,我們后面將進一步介紹如何使用這些配置 CRD 來定制規則,例如實作 Traffic Splitting,
和 Istio 類似,Aeraki 也采用了埠名稱來識別協議型別,埠取名需要遵循 “tcp-七層協議名-xxx” 的命名規則,例如,一個 Thrift 服務應取名為 “tcp-thrift-service”,需要注意的是,我們必須保留埠名中的“tcp-”前綴,因為對于 Istio 而言,這是一個 TCP 協議的服務,Aeraki 則會根據埠名中的七層協議來生成相應的 Envoy 配置,并替換 Istio 預設生成的 tcp_proxy,
我們來看看如何采用 Aeraki 來實作上面 Thrift 服務的 Traffic Splitting 用例,首先我們需要在 Thrift Service 定義的 Port 命名中宣告該 Service 的七層協議型別:“tcp-thrift-hello-server”,然后創建一個 VirtualService 將 Thrift 請求按照指定比例路由到不同的服務版本中,Aeraki 將根據服務定義和 VirtualService 生成所需的 Envoy 配置,并通過 EnvoyFilter 發送給 Istio,

可以看到,相對于手動創建 EnvoyFilter,采用 Aeraki 來管理 Thrift 要簡單得多,如果不需要特殊的流量規則,則會更簡單,只需要按照命名規范在 Port 名稱中宣告 Thrift 協議即可,Aeraki 會生成所需的 Envoy 配置,無需任何額外的作業,
想自己試試 Aeraki 的 Thrift、Dubbo、Redis 服務管理能力?非常簡單,只需在一個連接到 K8s 集群的命令列終端上運行下面兩行代碼,就可以安裝一個帶有 Aeraki 插件的 Istio 集群以及相應的 Demo 程式,歡迎大家嘗試!
`git clone https:``//github``.com``/aeraki-framework/aeraki``.git``aeraki``/demo/install-demo``.sh`
也可以訪問 Aeraki 的在線 Demo,查看從 Thrift、Dubbo、Redis 等服務收集到的監控指標面板:http://aeraki.zhaohuabing.com:3000/d/pgz7wp-Gz/aeraki-demo?orgId=1&refresh=10s&kiosk
使用 Aeraki 增強 Service Mesh
下面我們來看一下使用 Aeraki 的七層協議管理能力來增強 Service Mesh 的一些案例,
屏蔽開發/生產環境的差異
我們在開發、測驗和生產環境中通常需要訪問不同的后端資源,例如需要連接到不同的 Redis 快取或者不同的 mySQL 資料庫,一般來說,我們需要修改隨應用程式發布的組態檔中的后端資源地址,以達到在不同環境中切換后端資源的目的,通過 Aeraki 的幫助,我們可以用 Service Mesh 來屏蔽不同后端資源的配置差異,使得應用程式可以用相同的方式訪問不同環境中的后端資源,
如下圖所示,我們在 Dev、Staging 和 Prod 三個環境中都需要訪問 Redis 服務,這三個 Redis 服務有不同的 IP 地址和訪問密碼,部署方式也可能不同:在開發環境中,為了節約資源和簡化部署,我們可能使用單個 Redis 實體;在測驗和生產環境中,我們會使用 Redis 集群來保證 Redis 服務的高可用和擴展性,我們也可能直接使用云服務商提供的 Redis 托管服務,當在這三個環境中進行切換時,我們需要配置不同的 IP 地址和訪問密碼,如果 Redis 部署的方式不同,我們甚至可能需要修改客戶端代碼來切換 Redis 單實體模式和集群模式,這極大影響了我們開發、測驗和上線的效率,

通過 Aeraki 提供的 RedisService 和 RedisDestination CRD,我們可以屏蔽這些不同 Redis 服務提供者之間的差異,允許客戶端以統一的方式訪問后端的 Redis 服務,

在采用 Aeraki 之前,我們在不同的環境中需要配置不同的 IP 地址和 Redis 訪問密碼,采用 Aeraki 之后,在客戶端可以采用相同的代碼和配置,通過修改 Aeraki CRD 來切換不同環境中的 Redis 配置,大大減少在不同環境之間進行切換的成本,即使 Redis 從單實體改為了 Redis 集群,客戶端也可以采用相同的方式進行訪問,

采用流量鏡像進行對比測驗
有一些資料庫或者資料庫代理采用相同的網路協議,例如 TiDB、Oceanbase、Aurora、Kingshard等都兼容 MySQL 協議;Twemproxy、Codis、Tendis、Pika等都采用了 Redis 協議,由于業務需求,我們有時需要從一個實作遷移到另一個實作上,在遷移之前,我們需要進行對比測驗,以對比不同實作的性能、功能及兼容性,
例如下面的場景:我們最初只用了一個單實體 Redis 來做快取,隨著線上業務的不斷擴展,該 Redis 實體已經出現了訪問瓶頸,我們希望切換為采用 Twemproxy 來對 Redis 進行水平擴展,通過采用 Aeraki 來將線上的 Redis 流量鏡像到 Twemproxy 測驗環境,我們可以采用真實的業務資料對 Twemproxy 進行充分的測驗,以評估其對線上業務的影響,

采用全流量故障注入測驗系統彈性
Istio 可以實作 HTTP 和 gRPC 的故障注入,但這還不夠,在一個分布式系統中,應用服務、資料庫、快取、訊息系統等都可能由于網路或者其他原因出現不可用的情況,采用 Aeraki,我們可以對系統中的所有這些可能的故障點進行完整的模擬,以測驗系統的彈性,保證我們的系統在一部分出現問題后可以自愈或者通過降級保證系統基本可用,而不至于整個系統崩潰,

小結
Service Mesh 中有大量的七層協議流量,包括 RPC、Database、Cache、Messaging 等型別的七層協議,但 Istio 只提供了 HTTP 和 gRPC 的七層管理能力,對其他七層協議的支持非常有限,Aerkai 開源專案通過非侵入的方式為 Istio 提供了任意七層協議的支持能力,并提供了面向用戶的高級配置 CRD,可以很方便地對這些協議的流量進行管理,實作灰度發布等高級流量管理能力,目前 Aeraki 已經支持了 Thrift、Dubbo、Redis、Kafka、Zookeeper,并即將支持更多的協議,Aeraki 的定位是做成一個非侵入式 Istio 功能增強工具集,除了協議擴展之外,還會關注解決在 Istio 使用程序中遇到的其他常見問題,包括效率優化、配置簡化、第三方服務發現接入、功能擴展等,如果您希望了解更多關于 Aeraki 的內容,歡迎訪問 Github 主頁 https://github.com/aeraki-framework/aeraki ,
**招聘資訊
騰訊云 Service Mesh 團隊正在火熱招聘中,Base 成都、北京、深圳或者西安,要求候選者熟悉 Kubernetes/Istio/Envoy,歡迎大家發送簡歷到 [email protected] 或者微信聯系 zhao_huabing,
參考鏈接:
- IstioCon talk “How to Manage Any Layer-7 Traffic in an Istio Service Mesh?” 視頻回放 https://www.bilibili.com/video/BV1XN41197Sq
- IstioCon talk “How to Manage Any Layer-7 Traffic in an Istio Service Mesh? 講稿下載 https://zhaohuabing.com/slides/how-to-manage-any-layer-7-traffic-in-istio.pdf
- Aeraki Github 主頁 https://github.com/aeraki-framework/aeraki
- Aeraki 在線 Demo http://aeraki.zhaohuabing.com:3000/d/pgz7wp-Gz/aeraki-demo?orgId=1&refresh=10s&kiosk
【騰訊云原生】云說新品、云研新術、云游新活、云賞資訊,掃碼關注同名公眾號,及時獲取更多干貨!!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/270781.html
標籤:其他

