趙化冰,騰訊云高級(jí)工程師,Istio Member,ServiceMesher管理委員,Istio 項(xiàng)目貢獻(xiàn)者, Aerika 項(xiàng)目創(chuàng)建者 ,熱衷于開(kāi)源、網(wǎng)絡(luò)和云計(jì)算。目前主要從事服務(wù)網(wǎng)格的開(kāi)源和研發(fā)工作。
唐陽(yáng),知乎基礎(chǔ)架構(gòu)工程師。Istio 項(xiàng)目貢獻(xiàn)者,Argo 項(xiàng)目貢獻(xiàn)者,專注于開(kāi)源,云原生與微服務(wù)。目前負(fù)責(zé)知乎服務(wù)網(wǎng)格的研發(fā)工作。
備注:本文根據(jù)騰訊云趙化冰和知乎唐陽(yáng)在 IstioCon 2021 中的演講 “How to Manage Any Layer-7 Traffic in an Istio Service Mesh?” 整理而成。
大家好,今天我們想和大家分享的主題是如何擴(kuò)展 Istio 以支持任何七層協(xié)議?作為云原生領(lǐng)域中一個(gè)人氣非常高的開(kāi)源項(xiàng)目, Istio 目前已經(jīng)基本成為了 Service Mesh 的事實(shí)標(biāo)準(zhǔn)。騰訊云上也提供了基于 Istio 進(jìn)行增強(qiáng),和 Istio API 完全兼容的 Service Mesh 管理服務(wù) TCM(Tencent Cloud Mesh),以幫助我們的用戶以較小的遷移成本和維護(hù)代價(jià)快速利用到 Service Mesh 提供的流量管理和服務(wù)治理能力。今天非常高興能夠有這個(gè)機(jī)會(huì)來(lái)和大家一起分享一下我們?cè)诖诉^(guò)程中的一些經(jīng)驗(yàn)。
Service Mesh 提供了一個(gè)對(duì)應(yīng)用透明的基礎(chǔ)設(shè)施層,可以解決我們?cè)诜植际綉?yīng)用/微服務(wù)中遇到的常見(jiàn)挑戰(zhàn),例如:如何找到服務(wù)提供者?如何保證服務(wù)之間的通信安全?如何得知服務(wù)之間的調(diào)用關(guān)系?如何進(jìn)行流量管理如灰度發(fā)布?等等。Service Mesh 的實(shí)現(xiàn)方式是伴隨應(yīng)用部署一個(gè) Sidecar Proxy,該 Sidecar Proxy 會(huì)攔截應(yīng)用的出向和入向流量, 對(duì)這些流量進(jìn)行分析和處理,以達(dá)到在不修改應(yīng)用代碼的情況下對(duì)服務(wù)進(jìn)行流量管理、安全加密,遙測(cè)數(shù)據(jù)收集的目的。為了實(shí)現(xiàn)這些服務(wù)治理能力,Sidecar Proxy 不只需要在 OSI 網(wǎng)絡(luò)模型的三、四層上對(duì)流量進(jìn)行處理,更重要的是需要在七層上進(jìn)行處理。在七層上,Istio 缺省只支持了 HTTP 和 gPRC 兩種協(xié)議。但我們?cè)谖⒎?wù)中經(jīng)常還會(huì)使用到的其他七層協(xié)議,當(dāng)將這些微服務(wù)應(yīng)用遷移到 Service Mesh 時(shí),我們希望使用一致的方式對(duì)所有的這些七層協(xié)議進(jìn)行統(tǒng)一管理,以充分利用 Service Mesh 基礎(chǔ)設(shè)施提供的云原生能力。
在今天的分享中,我將會(huì)介紹幾種將 Istio 流量管理能力擴(kuò)展到其他七層協(xié)議的方法,并對(duì)比分析這幾種方法各自的優(yōu)缺點(diǎn)。我會(huì)介紹如何利用 Aeraki 開(kāi)源項(xiàng)目來(lái)在 Istio 中管理任何七層協(xié)議,包括 Dubbo、Thrift、Redis 等。為了讓大家了解 Aeraki 是如何工作的,會(huì)展示一個(gè)采用 Aeraki 實(shí)現(xiàn) Thrift 服務(wù) Traffic Splitting 的例子。來(lái)自知乎的唐陽(yáng)還會(huì)為我們展示如何使用 Aeraki 的一些有趣的真實(shí)案例。
如下圖所示,一個(gè)典型的微服務(wù)應(yīng)用中通常會(huì)使用到這些七層協(xié)議:
那么當(dāng)將這樣一個(gè)微服務(wù)應(yīng)用加入到 Service Mesh 以后,我們希望能夠通過(guò) Service Mesh 得到哪些管理能力呢?
理想情況下,我們希望 Service Mesh 能夠管理微服務(wù)中用到的所有七層協(xié)議的流量,包括 RPC、Messaging、Cache、DB等。例如:
要實(shí)現(xiàn)以上這些流量管理和服務(wù)治理能力,Service Mesh 需要分析和處理 TCP 數(shù)據(jù)包中的七層協(xié)議的 Header。即 Service Mesh 必須具有七層協(xié)議的管理能力,而不只是在 TCP 層面上進(jìn)行處理。
然而在 Istio 中,對(duì)于除了 HTTP 和 gRPC 之外的協(xié)議,我們只能在 OSI 三到六層對(duì)這些協(xié)議進(jìn)行處理。這意味著我們只能基于三層的 IP 地址,四層的 TCP 端口或者六層的 SNI(Server Name Indication)對(duì)這些協(xié)議進(jìn)行路由。只能收集到 TCP 層面的指標(biāo),例如 TCP 收發(fā)包數(shù)量或者打開(kāi)/關(guān)閉的 TCP 鏈接數(shù)量。只能采用 mTLS 進(jìn)行鏈路層面的認(rèn)證和權(quán)限控制。換而言之,對(duì)于這些協(xié)議,我們依然需要在應(yīng)用代碼中處理流量控制、可觀測(cè)性、安全認(rèn)證這些本應(yīng)該由 Service Mesh 基礎(chǔ)設(shè)施來(lái)統(tǒng)一處理的共性問(wèn)題。這違背了我們將微服務(wù)遷移到 Service Mesh 的初衷:將微服務(wù)通信和治理的共性問(wèn)題從應(yīng)用代碼下沉到 Service Mesh 基礎(chǔ)設(shè)施層。
如果我們希望能夠在 Istio 中管理這些七層協(xié)議,我們應(yīng)該如何實(shí)現(xiàn)呢?假設(shè)我們有一個(gè) BookInfo 微服務(wù),但該微服務(wù)采用了一種稱為 AwesomeRPC 的協(xié)議而不是 HTTP 來(lái)實(shí)現(xiàn)服務(wù)間的遠(yuǎn)程調(diào)用。
我們來(lái)看一下如何才能夠在 Istio 中實(shí)現(xiàn) AwesomeRPC 協(xié)議的流量管理,例如根據(jù)請(qǐng)求 header 中的 user name 字段將來(lái)自 ProductPage 的請(qǐng)求路由到不同版本的 Reviews 中,以實(shí)現(xiàn)一個(gè)灰度發(fā)布的場(chǎng)景。
我們想到的最顯而易見(jiàn)的方式就是直接修改 Istio 代碼。首先我們需要在 Istio 的 VirtualService CRD 中支持 AwesomeRPC 協(xié)議。增強(qiáng)后的 VirtualService CRD 如下圖中最左的規(guī)則配置所示。 AwesomeRPC 和 HTTP 路由的語(yǔ)義類似,都是根據(jù) Header 中某些屬性的值進(jìn)行路由。因此我們只需要將 HTTP 協(xié)議類型改為 AwesomeRPC,可以直接采用 VirtualService 中的 HTTPRoute 結(jié)構(gòu)來(lái)表示 AwesomeRPC 的路由規(guī)則。然后我們需要在 Pilot 代碼中根據(jù) AwesomeRPC 的服務(wù)定義和 VirtualService 定義的路由規(guī)則生成 Envoy 所需的真實(shí)配置,并通過(guò) xDS 下發(fā)給數(shù)據(jù)面的 Envoy。當(dāng)然,以上的前提是我們已經(jīng)通過(guò) Envoy 的 Filter 擴(kuò)展機(jī)制編寫了 AwesomeRPC 的 Filter 插件,實(shí)現(xiàn) AwesomeRPC 的編解碼,Header 解析,動(dòng)態(tài)路由等數(shù)據(jù)面所需的功能。
采用這種方式,在 Envoy Filter 已經(jīng)實(shí)現(xiàn)了的情況下,在控制面增加一個(gè)新的七層協(xié)議的過(guò)程是相對(duì)比較簡(jiǎn)單的。但是由于我們修改了 Istio 的源碼,因此需要自己維護(hù)一個(gè) Istio 的私有分支,這導(dǎo)致了額外的維護(hù)代價(jià),并且很難跟上 Istio 快速的迭代步伐。
如果不希望維護(hù)自己的 Istio 代碼分支,一種可行的替代方式是采用 Istio EnvoyFilter CRD:EnvoyFilter 是 Istio 提供的一種靈活強(qiáng)大的配置機(jī)制。我們可以使用 EnvoyFilter為 Pilot 生成的缺省 Envoy 配置打一個(gè)補(bǔ)丁,添加、修改或者刪除缺省 Envoy 配置中的部分內(nèi)容,以按我們的要求修改 Envoy 在 Istio Service Mesh 中的缺省行為。
如下圖所示,由于 Pilot 并不理解 AwesomeRPC 協(xié)議,對(duì)于 Pilot 來(lái)說(shuō), AwesomeRPC 服務(wù)只是一個(gè) TCP 服務(wù)。在 Pilot 生成的缺省配置中,AwesomeRPC 服務(wù)對(duì)應(yīng)的 Outbound Listener 的 FilterChain 中采用了一個(gè) TCP Proxy 來(lái)處理其流量。我們?cè)?EnvoyFilter 的 Match 部分中選中該 TCP Proxy,并在 Operation 部分將其替換為一個(gè)配置了 Traffic Splitting 規(guī)則的 AwesomeRPC Filter。Pilot 會(huì)根據(jù) EnvoyFilter 修改其生成的缺省 Envoy 配置,然后下發(fā)到數(shù)據(jù)面的 Envoy 上。這樣我們就通過(guò) EnvoyFilter 在 Istio 中實(shí)現(xiàn)了對(duì) AwesomeRPC 協(xié)議的支持。
下面我們來(lái)看一個(gè)采用 Thrift 協(xié)議的真實(shí)案例。Thrift 是 Apache 基金會(huì)下一個(gè)輕量級(jí)、支持多語(yǔ)言的開(kāi)源 RPC 框架。Envoy 中已經(jīng)支持 Thrift,但 Istio 中只對(duì) Thrift 提供了有限的支持,并不能實(shí)現(xiàn) Traffic Splitting 等高級(jí)流量管理功能。如果我們希望在 Istio 中提供下圖中右下角所示 Thrif 服務(wù)的 Traffic Splitting 流量控制,我們可以通過(guò) EnvoyFilter 來(lái)實(shí)現(xiàn)。
(本示例相關(guān)源碼可以從 https://github.com/aeraki-framework/thrift-envoyfilter-example 下載)
首先,我們需要?jiǎng)?chuàng)建一個(gè)圖中左邊所示的 EnvoyFilter 來(lái)處理客戶端的出向流量,該 EnvoyFilter 的 Match 條件選中了 $(thrift-sample-server-vip)_9090 這個(gè) Outbound Listener 中 的 tcp_proxy,在 Patch 部分將其替換為一個(gè) thrift_proxy。在該 thrift_proxy 中,我們按照 Traffic Splitting 的要求為其配置了相應(yīng)的路由:將 30% 的流量路由到 Server v1版本,70% 的流量路由到 Server v2 版本。我們也需要為 Thrift Server 端創(chuàng)建一個(gè)如圖右上所示的 EnvoyFilter 來(lái)處理服務(wù)器端的入向流量。相比客戶端的 EnvoyFilter 而言,服務(wù)器端的 EnvoyFilter 配置要簡(jiǎn)單一些,因此我們不需要在服務(wù)器端配置任何路由規(guī)則,只需要將 tcp_proxy 替換為 thrift_proxy 即可。這個(gè) thrift_proxy 雖然沒(méi)有路由規(guī)則,但提供了大量七層的服務(wù)通信和治理能力,包括請(qǐng)求層面的負(fù)載均衡、產(chǎn)生請(qǐng)求層面的 Metrics 數(shù)據(jù)等。
從上面的介紹和示例可以看到, EnvoyFilter CRD 好比是 Istio 中的一把瑞士軍刀,可以對(duì) Pilot 生成的 Envoy 配置進(jìn)行非常靈活的定制,以達(dá)到對(duì)七層協(xié)議進(jìn)行管理的目的。但是 EnvoyFilter 也帶來(lái)了一些難以處理的問(wèn)題:
由于上述的種種問(wèn)題,我們可以看到,雖然可以使用 EnvoyFilter 來(lái)在 Istio 中實(shí)現(xiàn)七層協(xié)議的管理,但是在一個(gè)生產(chǎn)系統(tǒng),特別是一個(gè)中大型的 Service Mesh 中管理和維護(hù)這些 EnvoyFilter 是非常困難的。
由于難以手動(dòng)對(duì) EnvoyFilter 進(jìn)行管理和維護(hù) ,我們創(chuàng)建了Aeraki (發(fā)音:[Air-rah-ki])項(xiàng)目來(lái)自動(dòng)化這個(gè)流程。Aeraki 是希臘語(yǔ)中“微風(fēng)”的意思,我們希望 Aeraki 這股微風(fēng)能幫助 Istio 在云原生的旅程中航行得更遠(yuǎn)。
Aeraki 的基本工作原理如下圖所示:Aeraki 從 Istio 中拉取服務(wù)數(shù)據(jù),根據(jù) ServiceEntry 和 Aeraki 流量規(guī)則生成 Envoy 配置,并采用 EnvoyFilter 將生成的配置推送到 Istio 中。簡(jiǎn)而言之,你可以把 Aeraki 看做 Istio 中管理的七層協(xié)議的 Operator 。
相比于直接修改 Istio 代碼和采用 EnvoyFilter 這兩種擴(kuò)展 Istio 流量管理能力的方式,采用 Aeraki 為我們帶來(lái)了以下的好處:
和 Istio 類似,Aeraki 也采用了端口名稱來(lái)識(shí)別協(xié)議類型。端口取名需要遵循 “tcp-七層協(xié)議名-xxx” 的命名規(guī)則。例如,一個(gè) Thrift 服務(wù)應(yīng)取名為 “tcp-thrift-service”。需要注意的是,我們必須保留端口名中的“tcp-”前綴,因?yàn)閷?duì)于 Istio 而言,這是一個(gè) TCP 協(xié)議的服務(wù)。Aeraki 則會(huì)根據(jù)端口名中的七層協(xié)議來(lái)生成相應(yīng)的 Envoy 配置,并替換 Istio 缺省生成的 tcp_proxy。
我們來(lái)看看如何采用 Aeraki 來(lái)實(shí)現(xiàn)上面 Thrift 服務(wù)的 Traffic Splitting 用例。首先我們需要在 Thrift Service 定義的 Port 命名中聲明該 Service 的七層協(xié)議類型:“tcp-thrift-hello-server”,然后創(chuàng)建一個(gè) VirtualService 將 Thrift 請(qǐng)求按照指定比例路由到不同的服務(wù)版本中。Aeraki 將根據(jù)服務(wù)定義和 VirtualService 生成所需的 Envoy 配置,并通過(guò) EnvoyFilter 發(fā)送給 Istio。
可以看到,相對(duì)于手動(dòng)創(chuàng)建 EnvoyFilter,采用 Aeraki 來(lái)管理 Thrift 要簡(jiǎn)單得多。如果不需要特殊的流量規(guī)則,則會(huì)更簡(jiǎn)單,只需要按照命名規(guī)范在 Port 名稱中聲明 Thrift 協(xié)議即可,Aeraki 會(huì)生成所需的 Envoy 配置,無(wú)需任何額外的工作。
想自己試試 Aeraki 的 Thrift、Dubbo、Redis 服務(wù)管理能力?非常簡(jiǎn)單,只需在一個(gè)連接到 K8s 集群的命令行終端上運(yùn)行下面兩行代碼,就可以安裝一個(gè)帶有 Aeraki 插件的 Istio 集群以及相應(yīng)的 Demo 程序,歡迎大家嘗試!
`git clone https:``//github``.com``/aeraki-framework/aeraki``.git``aeraki``/demo/install-demo``.sh`
也可以訪問(wèn) Aeraki 的在線 Demo,查看從 Thrift、Dubbo、Redis 等服務(wù)收集到的監(jiān)控指標(biāo)面板:http://aeraki.zhaohuabing.com:3000/d/pgz7wp-Gz/aeraki-demo?orgId=1&refresh=10s&kiosk
下面我們來(lái)看一下使用 Aeraki 的七層協(xié)議管理能力來(lái)增強(qiáng) Service Mesh 的一些案例。
我們?cè)陂_(kāi)發(fā)、測(cè)試和生產(chǎn)環(huán)境中通常需要訪問(wèn)不同的后端資源,例如需要連接到不同的 Redis 緩存或者不同的 mySQL 數(shù)據(jù)庫(kù)。一般來(lái)說(shuō),我們需要修改隨應(yīng)用程序發(fā)布的配置文件中的后端資源地址,以達(dá)到在不同環(huán)境中切換后端資源的目的。通過(guò) Aeraki 的幫助,我們可以用 Service Mesh 來(lái)屏蔽不同后端資源的配置差異,使得應(yīng)用程序可以用相同的方式訪問(wèn)不同環(huán)境中的后端資源。
如下圖所示,我們?cè)?Dev、Staging 和 Prod 三個(gè)環(huán)境中都需要訪問(wèn) Redis 服務(wù),這三個(gè) Redis 服務(wù)有不同的 IP 地址和訪問(wèn)密碼,部署方式也可能不同:在開(kāi)發(fā)環(huán)境中,為了節(jié)約資源和簡(jiǎn)化部署,我們可能使用單個(gè) Redis 實(shí)例;在測(cè)試和生產(chǎn)環(huán)境中,我們會(huì)使用 Redis 集群來(lái)保證 Redis 服務(wù)的高可用和擴(kuò)展性,我們也可能直接使用云服務(wù)商提供的 Redis 托管服務(wù)。當(dāng)在這三個(gè)環(huán)境中進(jìn)行切換時(shí),我們需要配置不同的 IP 地址和訪問(wèn)密碼,如果 Redis 部署的方式不同,我們甚至可能需要修改客戶端代碼來(lái)切換 Redis 單實(shí)例模式和集群模式,這極大影響了我們開(kāi)發(fā)、測(cè)試和上線的效率。
通過(guò) Aeraki 提供的 RedisService 和 RedisDestination CRD,我們可以屏蔽這些不同 Redis 服務(wù)提供者之間的差異,允許客戶端以統(tǒng)一的方式訪問(wèn)后端的 Redis 服務(wù)。
在采用 Aeraki 之前,我們?cè)诓煌沫h(huán)境中需要配置不同的 IP 地址和 Redis 訪問(wèn)密碼。采用 Aeraki 之后,在客戶端可以采用相同的代碼和配置,通過(guò)修改 Aeraki CRD 來(lái)切換不同環(huán)境中的 Redis 配置,大大減少在不同環(huán)境之間進(jìn)行切換的成本。即使 Redis 從單實(shí)例改為了 Redis 集群,客戶端也可以采用相同的方式進(jìn)行訪問(wèn)。
有一些數(shù)據(jù)庫(kù)或者數(shù)據(jù)庫(kù)代理采用相同的網(wǎng)絡(luò)協(xié)議。例如 TiDB、Oceanbase、Aurora、Kingshard等都兼容 MySQL 協(xié)議;Twemproxy、Codis、Tendis、Pika等都采用了 Redis 協(xié)議。由于業(yè)務(wù)需求,我們有時(shí)需要從一個(gè)實(shí)現(xiàn)遷移到另一個(gè)實(shí)現(xiàn)上。在遷移之前,我們需要進(jìn)行對(duì)比測(cè)試,以對(duì)比不同實(shí)現(xiàn)的性能、功能及兼容性。
例如下面的場(chǎng)景:我們最初只用了一個(gè)單實(shí)例 Redis 來(lái)做緩存,隨著線上業(yè)務(wù)的不斷擴(kuò)展,該 Redis 實(shí)例已經(jīng)出現(xiàn)了訪問(wèn)瓶頸,我們希望切換為采用 Twemproxy 來(lái)對(duì) Redis 進(jìn)行水平擴(kuò)展。通過(guò)采用 Aeraki 來(lái)將線上的 Redis 流量鏡像到 Twemproxy 測(cè)試環(huán)境,我們可以采用真實(shí)的業(yè)務(wù)數(shù)據(jù)對(duì) Twemproxy 進(jìn)行充分的測(cè)試,以評(píng)估其對(duì)線上業(yè)務(wù)的影響。
Istio 可以實(shí)現(xiàn) HTTP 和 gRPC 的故障注入,但這還不夠。在一個(gè)分布式系統(tǒng)中,應(yīng)用服務(wù)、數(shù)據(jù)庫(kù)、緩存、消息系統(tǒng)等都可能由于網(wǎng)絡(luò)或者其他原因出現(xiàn)不可用的情況。采用 Aeraki,我們可以對(duì)系統(tǒng)中的所有這些可能的故障點(diǎn)進(jìn)行完整的模擬,以測(cè)試系統(tǒng)的彈性,保證我們的系統(tǒng)在一部分出現(xiàn)問(wèn)題后可以自愈或者通過(guò)降級(jí)保證系統(tǒng)基本可用,而不至于整個(gè)系統(tǒng)崩潰。
Service Mesh 中有大量的七層協(xié)議流量,包括 RPC、Database、Cache、Messaging 等類型的七層協(xié)議,但 Istio 只提供了 HTTP 和 gRPC 的七層管理能力,對(duì)其他七層協(xié)議的支持非常有限。Aerkai 開(kāi)源項(xiàng)目通過(guò)非侵入的方式為 Istio 提供了任意七層協(xié)議的支持能力,并提供了面向用戶的高級(jí)配置 CRD,可以很方便地對(duì)這些協(xié)議的流量進(jìn)行管理,實(shí)現(xiàn)灰度發(fā)布等高級(jí)流量管理能力。目前 Aeraki 已經(jīng)支持了 Thrift、Dubbo、Redis、Kafka、Zookeeper,并即將支持更多的協(xié)議。Aeraki 的定位是做成一個(gè)非侵入式 Istio 功能增強(qiáng)工具集,除了協(xié)議擴(kuò)展之外,還會(huì)關(guān)注解決在 Istio 使用過(guò)程中遇到的其他常見(jiàn)問(wèn)題,包括效率優(yōu)化、配置簡(jiǎn)化、第三方服務(wù)發(fā)現(xiàn)接入、功能擴(kuò)展等。如果您希望了解更多關(guān)于 Aeraki 的內(nèi)容,歡迎訪問(wèn) Github 主頁(yè) https://github.com/aeraki-framework/aeraki 。
**招聘信息
騰訊云 Service Mesh 團(tuán)隊(duì)正在火熱招聘中,Base 成都、北京、深圳或者西安,要求候選者熟悉 Kubernetes/Istio/Envoy。歡迎大家發(fā)送簡(jiǎn)歷到 huabingzhao@tencent.com 或者微信聯(lián)系 zhao_huabing。
參考鏈接:
【騰訊云原生】云說(shuō)新品、云研新術(shù)、云游新活、云賞資訊,掃碼關(guān)注同名公眾號(hào),及時(shí)獲取更多干貨?。?br>
聯(lián)系客服