本文根據5月28日晚 Service Mesh Webinar#1 多點生活平臺架構組研發工程師陳鵬,線上主題分享《多點生活在 Service Mesh 上的實踐 – Istio + MOSN 在 Dubbo 場景下的探索之路》整理,文末包含本次分享的視頻回顧鏈接以及 PPT 下載地址。
前言
隨着多點生活的業務發展,傳統微服務架構的面臨升級困難的問題。在雲原生的環境下,Service Mesh 能給我們帶來什麼好處。如何使用社區解決方案兼容現有業務場景,落地成符合自己的 Service Mesh 成爲一個難點。
今天主要給大家分享一下 Service Mesh 的一些技術點以及多點生活在 Service Mesh 落地過程中適配 Dubbo 的一些探索。
首先我們從三個方面入手:
- 爲什麼需要 Service Mesh 改造;
- 探索 Istio 技術點;
- Dubbo 場景下的改造;
爲什麼需要 Service Mesh 改造
說到爲什麼需要改造,應該先說一下 Service Mesh 和傳統微服務架構的一些特點。
微服務
微服務一般有這些模塊:
- 安全;
- 配置中心;
- 調用鏈監控;
- 網關;
- 監控告警;
- 註冊和發現;
- 容錯和限流;
這些模塊在傳統的微服務架構中有的是和 SDK 結合在一起,有的是一個獨立的中間件。
特點:
- 獨立部署;
- 模塊的邊界;
- 技術多樣性;
正是由於技術多樣性,微服務系統可以使用不同的語言進行開發,比如一個商城系統,訂單系統使用 Java 開發,庫存系統使用 Go 開發,支付系統使用 Python 開發,微服務之間通過輕量級通信機制協作,比如:HTTP/GRPC 等。比如目前多點使用的 Dubbo(服務治理框架),隨着多點生活的業務發展,目前遇到最棘手的問題就是中間件在升級過程中,推進很慢,需要業務方進行配合,接下來我們看看 Service Mesh。
Service Mesh
優點:
- 統一的服務治理;
- 服務治理和業務邏輯解耦;
缺點:
- 增加運維複雜度;
- 增加延時;
- 需要更多技術棧;
看了 Service Mesh 的優缺點,如果我們 Mesh 化了之後就可以解決我們目前的痛點,升級中間件只需要重新發布一下 Sidecar 就好了,不同語言開發的微服務系統可以採用同樣的服務治理邏輯,業務方就可以嘗試更多的技術。
探究 Istio 技術點
在談 Dubbo 場景下的改造之前我們先介紹一下 Istio 相關的技術點,然後結合 Dubbo 場景應該如何進行適配。
MCP
MCP(Mesh Configuration Protocol)提供了一套用於訂閱(Watch)、推送(Push)的 API,分爲 Source 和 Sink 兩個角色。
- Source 是資源提供方(server),資源變化了之後推送給訂閱者(Pilot),Istio 1.5 之前這個角色就是 Galley 或者自定義 MCP Server;
- Sink 是資源的訂閱者(client),在 Istio 1.5 之前這個角色就是 Pilot 和 Mixer,都是訂閱 Galley 或者自定義 MCP Server 的資源;
MCP 的訂閱、推送流程圖:
爲了和實際情況結合,我們就以 MCPServer 作爲 Source,Pilot 作爲 Sink 來介紹訂閱、推送流程,其中 MCP 通信過程中所傳輸的「資源」就是 Istio 定義的 CRD 資源,如:VirtualService、DestinationRules 等。
訂閱
- Pilot 啓動後會讀取 Configmap 的內容,裏面有一個
configSources
的一個數組配置(Istio 1.5 之後沒有這個配置,需要自己添加)、存放的是 MCP Server 的地址; - Pilot 連接 MCPServer 之後發送所關注的資源請求;
- MCPServer 收到資源請求,檢查請求的版本信息(可能爲空),判斷版本信息和當前最新維護的版本信息是否一致,不一致則觸發 Push 操作,一致則不處理;
- Pilot 收到 Push 數據,處理返回的數據(數據列表可能爲空,爲空也標示處理成功),根據處理結果返回 ACK(成功)/ NACK(失敗),返回的應答中包含返回數據的版本信息,如果返回的是 NACK,Pilot 會繼續請求當前資源;
- MCPServer 收到 ACK(和資源請求一致)之後對比版本號,如果一致則不推送,否則繼續推送最新數據;
推送
- MCPServer 自身數據發生變化,主動推送變化的資源給 Pilot;
- Pilot 收到之後處理這些數據,並根據處理結果返回 ACK / NACK;
- MCPServer 收到 ACK(和資源請求一致) 之後對比版本號,如果一致則不推送,否則繼續推送最新數據;
這樣的訂閱、推送流程就保證了 MCPServer 和 Pilot 資源的一致。MCPServer 只能通過 MCP 協議告訴 Pilot 資源發生變化了麼?當然不是,MCPServer 可以使用創建 CR 的方式,Pilot 通過 Kubernetes 的 Informer 機制也能感知到資源發生變化了,只是通過 MCP 傳輸的資源在 Kubernetes 裏面看不到,只是存在於 Pilot 的內存裏面,當然也可以通過 Pilot 提供的 HTTP debug 接口(istiod_ip:8080/debug/configz)來查。
https://github.com/champly/mcpserver 提供了一個 MCPServer 的一個 demo,如果需要更加細緻的瞭解 MCP 原理可以看一看。
更多 debug 接口可以查看:
https://github.com/istio/istio/blob/5b926ddd5f0411aa50fa25c0a6f54178b758cec5/pilot/pkg/proxy/envoy/v2/debug.go#L103
Pilot
Pilot 負責網格中的流量管理以及控制面和數據面之前的配置下發,在 Istio 1.5 之後合併了 Galley、Citadel、Sidecar-Inject 和 Pilot 成爲 Istiod。我們這裏說的是之前 Pilot 的功能,源碼裏面 pilot-discovery 的內容。
功能
- 根據不同平臺(Kubernetes、Console)獲取一些資源,Kubernetes 中使用 Informer 機制獲取 Node、Endpoint、Service、Pod 變化;
- 根據用戶的配置(CR、MCP 推送、文件)觸發推送流程;
- 啓動 gRPC server 用於接受 Sidecar 的連接;
推送流程
- 記錄變化的資源類型;
- 根據變化的資源類型(數組)整理本地數據;
- 根據變化的資源類型判斷需要下發的 xDS 資源;
- 構建 xDS 資源,通過 gRPC 下發到連接到當前 Pilot 的 Sidecar;
xDS
Sidecar 通過動態獲取服務信息、對服務的發現 API 被稱爲 xDS。
- 協議部分(ADS、控制資源下發的順序及返回確認的數據);
- 數據部分(CDS、EDS、LDS、RDS、SDS);
Pilot 資源類型發生變化需要下發的 xDS 資源對照:
MOSN
MOSN 是一款使用 Go 語言開發的網絡代理軟件,作爲雲原生的網絡數據平面,旨在爲服務提供多協議、模塊化、智能化、安全的代理能力。MOSN 是 Modular Open Smart Network 的簡稱。MOSN 可以與任何支持 xDS API 的 Service Mesh 集成,亦可以作爲獨立的四、七層負載均衡,API Gateway,雲原生 Ingress 等使用。
MOSN:https://github.com/mosn/mosn
配置文件:
- mosn_config:MOSN 的配置信息;
- listener:LDS;
- routers:RDS;
- cluster:CDS 和 EDS;
listener
其中 address
就是 MOSN 監聽的地址。
filter chains
filter_chains 在 MOSN 裏面的 network chains
,實現的還有:
- fault_inject;
- proxy;
- tcp_proxy;
和 network chains
同級的還有 listener chains
、 stream chains
, 其中 listener chains
目前只有 original_dst
實現。stream chains
可以對請求中的:
- StreamSender;
- StreamReceiver;
- StreamAccessLog;
進行 BeforeRoute
AfterRoute
這些關鍵步驟進行修改請求信息。
所有的 filter
都只有兩種返回結果:
- Continue:如果後面還有
filter
那就執行後續filter
; - Stop:執行完當前
filter
就不再繼續執行了;
conv
看圖中的配置信息 config
的內容, downstream_protocol
和 upstream_protocol
這裏如果配置不一致,就需要協議轉換。比如 HTTP1
轉換爲 HTTP2
,MOSN 就會先把 HTTP1
轉換爲 common
的中間協議,然後再把 common
轉換爲 HTTP2
,這樣就實現了協議之間的轉換。如果需要自己實現其他協議轉換,那麼只需要編寫轉換 common
的內容和 common
轉換爲當前協議的內容即可實現協議之間的互轉。
proxy
我們再來看 filters
裏面的 proxy
,這個就是一個會經過路由的代理,配置信息裏面配置了 router_config_name
,就是要路由的 router
名字。
routers
根據 listener
裏面的 proxy
的配置信息裏面的 router_config_name
會找到一個 router
,如上圖所示。然後就會根據請求裏面的 domains
去匹配 virtual_hosts
, 這裏的 domains
裏面在 HTTP
裏面就會是 host
,當在 Dubbo 協議裏面我們可以把 service
(有些地方叫做 interface、target,我們這裏統一叫 service) 放到 x-mosn-host
這個 MOSN 的 Header
裏面,MOSN 就可以根據這個去匹配 domains
。
然後匹配到一個 virtual_hosts
之後,就會得到對應的 routers
,這裏又會根據 match
裏面的匹配規則進行匹配, HTTP
協議裏面可以根據 path
、 queryparam
、 header
等信息進行匹配,具體匹配規則通過 VirtualService 下發,如果是 Dubbo 協議,那麼可以套用 HTTPRoute
規則,然後把 Dubbo 的 attachment
解析出來當作 header
去用,目前 MOSN 沒有解析 attachment
,我們自己實現了一個。
匹配到了之後會得到一個 route
,圖中所示只有一個 cluster_name
,如果是有多個 subset
(DestinationRule 定義),那麼就會有 weighted_cluster
,裏面會有 cluster_name
和 weight
構成的對象的數組,例如:
"route":{
"weighted_clusters":[
{
"cluster":{
"name":"outbound|20882|green|mosn.io.dubbo.DemoService.workload",
"weight":20
}
},
{
"cluster":{
"name":"outbound|20882|blue|mosn.io.dubbo.DemoService.workload",
"weight":80
}
}
],
"timeout":"0s",
"retry_policy":{
"retry_on":true,
"retry_timeout":"3s",
"num_retries":2
}
}
其中 weight
之和必須爲 100(Istio 定義的),必須是非負數的整數。
下面有一些 timeout
、 retry_policy
服務策略。
匹配上了之後會得到一個 cluster_name
,然後我們再看 cluster
cluster
在 routers
裏面匹配出來的 cluster_name
作爲 key
在 cluster
裏面會找到這麼一個對象。
其中 lb_type
就是節點的負載均衡策略,目前 MOSN 支持:
- ROUNDROBIN;
- RANDOM;
- WEIGHTED_ROUNDROBIN;
- EAST_REQUEST;
hosts
裏面的 address
裏面也可以配置權重,這個權重必須是大於 0 或小於 129 的整數。可以通過 Istio 1.6 裏面的 WorkloadEntry
來配置權重。然後根據負載均衡策略拿到 host
之後直接請求到對應的節點。
這就完成了流量的轉發。接下來我們看看 Dubbo 場景下應該如何改造。
Dubbo 場景下的改造
所有的改造方案裏面都是要把 SDK 輕量化,關於服務治理的邏輯下沉到 Sidecar,我們在探索的過程中有三種方案。
Istio + Envoy
這個方案是 Istio+Envoy 的方案,是參考的華爲雲的方案:
https://support.huaweicloud.com/bestpractice-istio/istiobestpractice3005.html
- 通過創建 EnvoyFilter 資源來給 xDS 資源打 patch;
- Envoy 解析 Dubbo 協議中的 Service 和 Method;
- 根據路由策略配置把流量轉發到對應的 Provider;
這種方案如果需要解析更多的 Dubbo 內容,可以通過 WASM 擴展。
MOSN + Dubbo-go
- MOSN 提供 Subscribe、Unsubscribe、Publish、Unpublish 的 HTTP 服務;
- SDK 發送請求到 MOSN 提供的這些服務,讓 MOSN 代爲與真正的註冊中心交互;
- MOSN 通過 Dubbo-go 直接和註冊中心連接;
這種方案的話就不需要 Istio。
Istio + MOSN
這種方案就是我們現在採用的方案,包括:
- 數據面改造;
- 控制面適配;
我們有一個理念就是如果能通過標準的 CRD 最好,如果描述不了的話我們就通過 EnvoyFilter 進行修改。這裏特別說一下,我們一開始也有一個誤區就是 EnvoyFilter 是作用於 Envoy,其實不是的,是對生成好的 xDS 資源進行 ADD, MERGE 等操作,目前只可以修改 LDS、RDS、CDS,這個修改也是有一定侷限性的。如果 EnvoyFilter 修改不了某些特定的場景(比如 Istio 1.6 之前的 ServiceEntry 裏面的 Endpoint 不能單獨爲每個實例指定不同的端口),那麼我們只能修改 pilot-discovery 的代碼,xDS 是不會作任何修改的。按照這個理念,我們開始探索如何改造。
數據面改造
首先有三個端口需要說明一下:
- 20880 : provider 監聽端口;
- 20881 : consumer 請求 MOSN 的這個端口,MOSN 做轉發到 provider;
- 20882 : 接受來自下游(MOSN/consumer)的請求,直接轉到 127.0.0.1:20880;
步驟:
- provider 啓動之後請求本地 MOSN 的註冊接口,把服務信息註冊到註冊中心(zk/nacos),註冊請求到達 MOSN 之後,MOSN 會把註冊端口號改爲 20882;
- consumer 啓動之後不需要連接註冊中心,直接把請求發送到 127.0.0.1:20881;
- consumer 端的 MOSN 收到請求之後,根據配置信息 listener->routers->cluster->host,找到合適的 host(可以是 provider 的 MOSN 或者直接是 provider) 發送請求,這裏的匹配過程可以修改 MOSN 讓 Dubbo 的 service 作爲 domains,attachment 作爲 header;
- provider 端 MOSN 收到請求後(20882),直接轉發請求到本地 127.0.0.1:20880;
這個只是通過靜態配置實現的,如果 provider 這些信息如何通過 Pilot 下發呢?
控制面適配
MOSN 本身支持 xDS API,配置信息可以通過 xDS 下發,而不是靜態配置。我們有一個對接配置中心,註冊中心的程序我們叫 Adapter,這個主要獲取註冊中心的服務信息,然後根據配置中心的服務治理策略(比如流程比例,還有一些我們內部的一些單元的信息)構建出 Istio 支持的 CR,然後創建 CR,Pilot 自己感知 CR 變化 或者 通過 MCP 把這些信息直接發送給 Pilot,觸發 Pilot 的資源變化,然後 Pilot 根據資源的變化去下發一些 xDS 資源,Sidecar 收到資源變化後,就可以動態調整路由策略,從而達到服務治理的目的。
最終架構圖如圖所示:
註冊(灰色部分):
- provider 發送註冊信息給 MOSN;
- MOSN 修改註冊信息(端口號等),然後註冊到真正到註冊中心(ZK / Nacos 等);
配置下發(藍色部分):
- Adapter 連接註冊中心和配置中心並感知其變化;
- Adapter 感知到變化之後通過 MCP 把變化的信息傳遞給 Pilot(或者創建 CR 讓 Pilot 自己感知);
- Pilot 感知到資源變化觸發配置下發流程,根據變化到資源類型下發對應到 xDS 資源到 連接到它的 Sidecar;
服務請求(黃色部分):
- consumer 請求本地 127.0.0.1:20881(MOSN 監聽的端口);
- MOSN 根據 listener->router->cluster 找到一個 host,然後把請求轉發到這個 host 上;
以上就完成了服務註冊、發現、治理的所有邏輯。
Istio 1.6 之後可以通過 WorkloadEntry + ServiceEntry 這兩種 CRD 資源來描述集羣外的服務,當實例上線或者下線的時候就會直接觸發 EDS 增量下發 。
Demo 演示
首先要說明一下:
- 由於沒有真正的註冊,所以使用手動添加 ServiceEntry 的方式代替 Adapter 功能;
- Listener 和 Routers 配置信息目前是固定的;
- Provider 只註冊到本地 ZK;
- Sidecar 注入到方式使用的是多個 Container;
具體操作可以按照 mosn-tutorial,裏面的 istio-mosn-adapt-dubbo
。即使你沒有 Kubernetes 環境也可以嘗試的,後期這個會移植到 MOSN 官網,敬請期待。
mosn-tutorial:https://github.com/mosn/mosn-tutorial
以上就是本期分享的全部內容,感謝大家的收看。
回顧資料
PPT 下載:
https://github.com/servicemesher/meetup-slides/tree/master/2020/05/webinar
視頻回顧:
https://www.bilibili.com/video/BV15k4y1r7n8
本文歸檔在 sofastack.tech。
作者介紹:
陳鵬,多點生活平臺架構組研發工程師,開源項目與雲原生愛好者。有多年的網上商城、支付系統相關開發經驗,2019年至今從事雲原生和 Service Mesh 相關開發工作。
本文轉載自公衆號金融級分佈式架構(ID:Antfin_SOFA)。
原文鏈接: