多點生活在 Service Mesh 上的實踐 -- Istio + Mosn 在 Dubbo 場景下的探索之路

Service Mesh Webinar 是由 ServiceMesher 社區和 CNCF 聯合發起的線上直播活動,活動將不按期舉行,爲你們帶來 Service Mesh 領域的知識和實踐分享。

本文根據5月28日晚 Service Mesh Webinar#1 多點生活平臺架構組研發工程師陳鵬,線上主題分享《多點生活在 Service Mesh 上的實踐 -- Istio + Mosn 在 Dubbo 場景下的探索之路》整理,文末包含本次分享的視頻回顧連接以及 PPT 下載地址。html

前言

隨着多點生活的業務發展,傳統微服務架構的面臨升級困難的問題。在雲原生的環境下,Service Mesh 能給咱們帶來什麼好處。如何使用社區解決方案兼容現有業務場景,落地成符合本身的 Service Mesh 成爲一個難點。git

今天主要給你們分享一下 Service Mesh 的一些技術點以及多點生活在 Service Mesh 落地過程當中適配 Dubbo 的一些探索。github

首先咱們從三個方面入手:web

  • 爲何須要 Service Mesh 改造;
  • 探索 Istio 技術點;
  • Dubbo 場景下的改造;

爲何須要 Service Mesh 改造

說到爲何須要改造,應該先說一下 Service Mesh 和傳統微服務架構的一些特色。json

微服務

微服務通常有這些模塊:數組

  • 安全;
  • 配置中心;
  • 調用鏈監控;
  • 網關;
  • 監控告警;
  • 註冊和發現;
  • 容錯和限流;

這些模塊在傳統的微服務架構中有的是和 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 的訂閱、推送流程圖:

mcp.png

爲了和實際狀況結合,咱們就以 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 資源對照:

資源名稱 CDS EDS LDS RDS
Virtualservices
Gateways
Serviceentries
Destinationrules
Envoyfilters
Sidecars
ConfigClientQuotaspecs
ConfigClientQuotaspecbindings
Authorizationpolicies
Requestauthentications
Peerauthentications
Other
以上內容是根據 源碼 整理的

MOSN

MOSN 是一款使用 Go 語言開發的網絡代理軟件,做爲雲原生的網絡數據平面,旨在爲服務提供多協議、模塊化、智能化、安全的代理能力。MOSN 是 Modular Open Smart Network 的簡稱。MOSN 能夠與任何支持 xDS API 的 Service Mesh 集成,亦能夠做爲獨立的4、七層負載均衡,API Gateway,雲原生 Ingress 等使用。

MOSN:https://github.com/mosn/mosn

配置文件:

  • mosn_config:MOSN 的配置信息;
  • listener:LDS;
  • routers:RDS;
  • cluster:CDS 和 EDS;

listener

listener.png

其中 address 就是 MOSN 監聽的地址。

filter chains

filter_chains 在 MOSN 裏面的 network chains,實現的還有:

  • fault_inject;
  • proxy;
  • tcp_proxy;

network chains 同級的還有 listener chainsstream chains, 其中
listener chains 目前只有 original_dst 實現。stream chains 能夠對請求中的

  • StreamSender;
  • StreamReceiver;
  • StreamAccessLog;

進行 BeforeRoute AfterRoute 這些關鍵步驟進行修改請求信息。

全部的 filter 都只有兩種返回結果:

  • Continue:若是後面還有 filter 那就執行後續 filter
  • Stop:執行完當前 filter 就再也不繼續執行了;
conv

看圖中的配置信息 config 的內容, downstream_protocolupstream_protocol 這裏若是配置不一致,就須要協議轉換。好比 HTTP1 轉換爲 HTTP2,MOSN 就會先把 HTTP1 轉換爲 common 的中間協議,而後再把 common轉換爲 HTTP2,這樣就實現了協議之間的轉換。若是須要本身實現其餘協議轉換,那麼只須要編寫轉換 common 的內容和 common 轉換爲當前協議的內容便可實現協議之間的互轉。

proxy

咱們再來看 filters 裏面的 proxy,這個就是一個會通過路由的代理,配置信息裏面配置了router_config_name,就是要路由的router名字。

routers

routers.png

根據 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 協議裏面能夠根據 pathqueryparamheader 等信息進行匹配,具體匹配規則經過 VirtualService 下發,若是是 Dubbo 協議,那麼能夠套用 HTTPRoute 規則,而後把 Dubbo 的 attachment 解析出來看成 header去用,目前 MOSN 沒有解析 attachment,咱們本身實現了一個。

匹配到了以後會獲得一個 route,圖中所示只有一個 cluster_name,若是是有多個 subset(DestinationRule 定義),那麼就會有 weighted_cluster ,裏面會有 cluster_nameweight 構成的對象的數組,例如:

"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 定義的),必須是非負數的整數。

下面有一些 timeoutretry_policy 服務策略。

匹配上了以後會獲得一個cluster_name,而後咱們再看 cluster

cluster

routers 裏面匹配出來的 cluster_name 做爲 keycluster 裏面會找到這麼一個對象。

cluster.png

其中 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/istio_bestpractice_3005.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-狗直接和註冊中心鏈接;

這種方案的話就不須要 Istio。

Istio + MOSN

這種方案就是咱們如今採用的方案,包括:

  • 數據面改造;
  • 控制面適配;

咱們有一個理念就是若是能經過標準的 CRD 最好,若是描述不了的話咱們就經過 EnvoyFilter 進行修改。這裏特別說一下,咱們一開始也有一個誤區就是 EnvoyFilter 是做用於 Envoy,其實不是的,是對生成好的 xDS 資源進行 ADD, MERGE 等操做,目前只能夠修改 LDS、RDS、CDS,這個修改也是有必定侷限性的。若是 EnvoyFilter 修改不了某些特定的場景(好比 Istio 1.6 以前的 ServiceEntry 裏面的 Endpoint 不能單獨爲每一個實例指定不一樣的端口),那麼咱們只能修改 pilot-discovery 的代碼,xDS 是不會做任何修改的。按照這個理念,咱們開始探索如何改造。

數據面改造

mosn.png

首先有三個端口須要說明一下:

  • 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 收到資源變化後,就能夠動態調整路由策略,從而達到服務治理的目的。

最終架構圖如圖所示:

architecture.png

註冊(灰色部分):

  1. provider 發送註冊信息給 MOSN;
  2. MOSN 修改註冊信息(端口號等),而後註冊到真正到註冊中心(ZK / Nacos 等);

配置下發(藍色部分):

  1. Adapter 鏈接註冊中心和配置中心並感知其變化;
  2. Adapter 感知到變化以後經過 MCP 把變化的信息傳遞給 Pilot(或者建立 CR 讓 Pilot 本身感知);
  3. Pilot 感知到資源變化觸發配置下發流程,根據變化到資源類型下發對應到 xDS 資源到 鏈接到它的 Sidecar;

服務請求(黃色部分):

  1. consumer 請求本地 127.0.0.1:20881(MOSN 監聽的端口);
  2. 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

以上就是本期分享的所有內容,感謝你們的收看。

本期嘉賓介紹

陳鵬,多點生活平臺架構組研發工程師,開源項目與雲原生愛好者。有多年的網上商城、支付系統相關開發經驗,2019年至今從事雲原生和 Service Mesh 相關開發工做。

回顧資料

PPT 下載:https://github.com/servicemesher/meetup-slides/tree/master/2020/05/webinar
視頻回顧:https://www.bilibili.com/video/BV15k4y1r7n8

相關文章
相關標籤/搜索