趙化冰,騰訊雲高級工程師,Istio Member,ServiceMesher管理委員,Istio 項目貢獻者, Aerika 項目建立者 ,熱衷於開源、網絡和雲計算。目前主要從事服務網格的開源和研發工做。ios
唐陽,知乎基礎架構工程師。Istio 項目貢獻者,Argo 項目貢獻者,專一於開源,雲原生與微服務。目前負責知乎服務網格的研發工做。git
備註:本文根據騰訊雲趙化冰和知乎唐陽在 IstioCon 2021 中的演講 「How to Manage Any Layer-7 Traffic in an Istio Service Mesh?」 整理而成。github
你們好,今天咱們想和你們分享的主題是如何擴展 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 網絡模型的3、四層上對流量進行處理,更重要的是須要在七層上進行處理。在七層上,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。歡迎你們發送簡歷到 huabingzhao@tencent.com 或者微信聯繫 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
【騰訊雲原生】雲說新品、雲研新術、雲遊新活、雲賞資訊,掃碼關注同名公衆號,及時獲取更多幹貨!!