天天看點

Dubbo 在 K8s 下的思考K8S介紹RPC介紹和分析遇到的問題和挑戰問題梳理Dubbo 和 Spring CloudDubbo + K8S總結

序言

Dubbo在2011開源之後,一直是國内最受歡迎的RPC架構,之後spring boot和Spring Cloud的面世,助推了微服務的火熱程度。計算機的世界變化很快,自從容器和K8s登上舞台之後,給原有的RPC領域帶來了很大的挑戰。這個文章主要講述RPC領域遇到的問題,以及RPC怎麼去擁抱K8s懷抱的一些思考。

K8S介紹

kubernetes是一個開源的,用于管理雲平台中多個主機上的容器化的應用,Kubernetes的目标是讓部署容器化的應用簡單并且高效,Kubernetes提供了應用部署,規劃,更新,維護的一種機制。kubernetes簡稱K8s。

Dubbo 在 K8s 下的思考K8S介紹RPC介紹和分析遇到的問題和挑戰問題梳理Dubbo 和 Spring CloudDubbo + K8S總結

在Kubernetes中,最小的管理元素不是一個個獨立的容器,而是Pod。Pod的生命周期需要注意以下幾點:

  • 容器和應用可能随時被殺死
  • Pod Ip和主機名可能變化 (除非使用StatefulSet進行定制)
  • 寫到本地的磁盤的檔案可能消失,如果想不失效,需要用存儲卷
應用,容器,Pod的關系
  • 應用部署在容器中,一般情況下一個應用隻部署在一個容器中
  • 一個Pod下可以包含一個或多個容器,一般情況下一個Pod隻建議部署一個容器。下列場景除外:
    • side car
    • 一個容器的運作以來與本地另外一個容器。如一個容器下應用負責下載下傳資料,另外一個容器下應用向外提供服務
Service

如果一些Pods 提供了一些功能供其它的Pod使用,在kubernete叢集中是如何實作讓這些前台能夠持續的追蹤到這些背景的?答案是:Service。

Kubernete Service 是一個定義了一組

Pod

的政策的抽象,這些被服務标記的Pod一般都是通過label Selector決定的。Service抽象了對Pod的通路。

預設的Service,通過一個叢集Ip擷取A Record。但是有時需要傳回所有滿足條件的Pod Ip清單,這時候可以直接使用 Headless Services。

參考:

Https://kubernetes.io/

推薦書籍:kubernetes in action

RPC介紹和分析

随着微服務的普及,應用之間的通信有了足夠多的成熟方案。Dubbo在2011年開源之後,被大量的中小型公司采用;在Spring Boot推出之後,Spring逐漸煥發出第二春,随即Spring Cloud面世,逐漸占領市場,在中國市場中,和Dubbo分庭抗争;gRPC是google推出的基于Http2的端到端的通信工具,逐漸地在K8s市場上占據統治地位,如etcd,istio等都采用gRPC作為通信工具;Service Mesh從開始概念上就火熱,現在逐漸走向成熟,Istio + Envoy(其他sidecar)逐漸開始走上舞台。

應用開發者視角

從功能層面來說,對開發者有感覺的功能有:服務實作,服務暴露(注解或配置),服務調用(注解或配置),服務治理等。

從選型角度會關注以下幾點:易用性(開發易用性和開箱即用),性能,功能,擴充性等。

架構開發者視角

關鍵流程:服務暴露,服務注冊,服務發現,服務調用,服務治理。

關鍵知識點:序列化,網絡通信,服務路由,負載均衡,服務限流,熔斷,降級等服務治理。

主流技術實作

DUBBO/HSF

Dubbo 在 K8s 下的思考K8S介紹RPC介紹和分析遇到的問題和挑戰問題梳理Dubbo 和 Spring CloudDubbo + K8S總結

Dubbo提供了面向接口的遠端方法調用。應用開發者定義接口,編寫服務并暴露;Client端通過接口進行調用。

Dubbo注冊服務的次元是接口次元,每個接口會在注冊中心寫入一條資料。

Dubbo支援條件路由,腳本路由,Tag路由等。這些路由規則都是強依賴于IP位址。

備注:Dubbo和HSF的大部分機制都是相似的,是以下面都以Dubbo作為方案進行讨論。

SpringCloud

Spring Cloud通過Rest形式進行網絡調用。應用開發者可以自己編寫暴露Rest服務,如springmvc。

Spring Cloud裡的服務注冊是應用次元(Eureka),Client端和Server端通過約定的方式進行通信。

Spring Cloud提供了一套标準API,而其中Netflix是其中的佼佼者,對這套API進行了實作,對大部分開發者來說,可以回直接依賴和使用Netflix,是以可以說是Netflix提供成了Spring Cloud的核心。但是作為商業公司對開源投入往往會多變,如Eureka已經體制維護。

gRPC

gRPC 是一個 基于 HTTP/2 協定設計的 RPC 架構,它采用了 Protobuf 作為 IDL。gRPC作為端到端的通信方案,可以解決現在的多語言問題。

gRPC本身不提供服務注冊,服務治理的功能。但現在可以看到gRPC有趨勢往這方面擴充的野心。

K8s

K8s體系裡暫時沒有公允的通信架構,一般推薦gRPC作為RPC架構。

K8s體系下,預設情況下,Pod的Ip是變化的,是以Pod和Pod之間需要通信的話,有幾種方式:

  • Service+DNS:建立一個Service,可以通過标簽選擇到一組Pod清單,這個service對應一個不變的叢集Ip;Client端通過DNS方式或者直接通路叢集Ip。這個叢集Ip,約等于實作了負載均衡 (Iptable方式)。
  • headless service:headless service和上面的service的差別是,它不提供叢集Ip,通過主機名的形式擷取一組Ip清單,Client端自己決定通路哪個Pod。

Istio + Envoy

Dubbo 在 K8s 下的思考K8S介紹RPC介紹和分析遇到的問題和挑戰問題梳理Dubbo 和 Spring CloudDubbo + K8S總結

Istio的控制層會向K8s的api server請求并監聽Pod資訊,service資訊等資訊。這樣Istio中就有了完整的K8s叢集中的Pod,service等的完整資訊。如果K8s叢集中有資訊變更,istio中也可以得到通知并更新對應的資訊。

Envoy作為Proxy一個最常見的實作,以Envoy作為例子簡單介紹。Envoy 通過查詢檔案或管理伺服器來動态發現資源。對應的發現服務及其相應的 API 被稱作 xDS。協定内容包括LDS,RDS,CDS等等。

參考資料:

servicemesh介紹 Istio路由規則

備注:上述知識是通過查閱資料(Istio官網),以及和集團service mesh同學溝通獲得。如有問題,歡迎指正。

總結

Dubbo 在 K8s 下的思考K8S介紹RPC介紹和分析遇到的問題和挑戰問題梳理Dubbo 和 Spring CloudDubbo + K8S總結

遇到的問題和挑戰

Spring Cloud和Dubbo的共生

基礎理論可以

參考

.

Dubbo預設是基于TCP通信,Spring Cloud大部分基于Rest請求。在阿裡雲實施商業化過程中,發現大量公司需要Spring Cloud應用和Dubbo進行通信,社群主要依靠Dubbo上增加一層網關來解決。

是否有方案進行統一服務注冊發現,以及服務調用呢?

Dubbo在K8s場景下的挑戰

K8s下Pod的IP是變化的 (預設),dubbo的服務治理高度依賴IP。

K8s的服務注冊通過Pod定義完成,服務發現其實是尋找Pod的過程。Pod和應用有一定的對應關系,和dubbo裡的接口次元的服務注冊發現模型不是很比對。

Dubbo在Service mesh場景下的生存空間

Dubbo需要進行支援裁剪,Dubbo的大部分功能都可以交由sidecar(proxy)來完成。

如果公司已經在部署了RPC架構,這時候如果需要實施Service Mesh,有什麼好的過渡方案嗎?

問題梳理

服務定義

服務怎麼定義呢?需要從應用開發者角度看待怎麼定義服務。

服務在功能次元對應某一功能,如查詢已買訂單詳情。在Dubbo中,對應某個接口下的方法;在Spring Cloud和gRPC對應一個Http請求。如果從面向函數程式設計角度,一個服務就是一個function。在Java語言中,class是一切程式設計的基礎,是以将某些服務按照一定的次元進行聚合,放到某個接口中,就成了一個接口包含了很多的服務。

從Dubbo角度來解釋下:Dubbo是面向接口程式設計的遠端通信,是以Dubbo是面向服務集的程式設計,你如果想調用某個服務,必須通過接口的方式引入,然後調用接口中的某個服務。Dubbo Ops中提供的服務查詢功能,其實不是查詢單個服務,而是通過查詢接口(服務集)之後獲得具體的方法(服務)。

而在Spring Cloud的世界裡,服務提供方會将自己的應用資訊(Ip+port)注冊成應用下的一個執行個體,服務消費方和服務提供方按照約定的形式進行Rest請求。每個請求對應的也是一個服務。

和K8s裡的service的差別

K8s裡的service其實是對應到一組Pod+port清單,和DNS聯系緊密;用通俗易懂的方式表達:維護了Pod集合的關系映射。和上面講的服務是屬于不同場景下的兩個概念。

按照這個方式定義服務,服務治理的粒度其實也是按照服務粒度,可以針對每個服務設定逾時時間,設定路由規則等等。但是服務注冊的粒度和服務有什麼關系呢?

服務注冊粒度

一個應用下包含了很多接口,一個接口下包含了很多服務(Dubbo);或者一個應用包含了很多的服務(Spring Cloud)。分析下應用次元注冊和接口次元注冊的優缺點。會有一篇獨立的文章來闡述應用次元注冊的方案。

接口次元注冊

優點:

  • 服務查詢按照接口次元查詢非常友善,實作難度低
  • 應用拆分或者合并的時候,Client端(消費者)無需關心,做到了讓使用者無感

缺點:

  • 和K8s等主流平台的模型對應關系不比對
  • 注冊的資料量非常大,有一定的性能風險
應用次元
  • 和K8s,Spring Cloud等模型對應關系一緻
  • 性能上可以得到很大緩解
  • 應用拆分或者合并的時候,Client端需要感覺 (如果想做到不感覺,需要架構開發者維護一份接口和應用映射關系的存儲)
  • 如果想對使用者保持Dubbo原有的接口次元的查詢,需要較多的工作量來保證。
  • 對使用者透明度有所減少,需要在OPS上提供其他一些工具。如供應用開發者可以檢視具體某個Ip是否提供了某個服務等等。

Dubbo 和 Spring Cloud

目标:Dubbo和Spring Cloud的服務發現進行統一;Dubbo和Spring Cloud可以互相調用。

服務發現統一

Dubbo改造成應用次元的服務注冊。(具體不展開,後面文章說明)

打通調用

Dubbo實作中,支援将以Rest協定進行暴露,并且讓Spring Cloud識别。@桃谷

Dubbo + K8S

在K8s已經闡述過,下面的内容也是假設一個應用部署在一個容器裡,一個容器部署在一個Pod裡。

接下來方案的讨論,互相之間其實是有關聯的,如服務治理可能會影響到服務注冊發現,服務查詢也不能依賴于服務注冊的内容。整個設計的過程是不斷優化的過程。下面所說的内容,以Dubbo來舉例說明。

服務治理

Dubbo原有體系裡的服務治理是強依賴于IP,當配置了一套服務治理規則的時候,最後都是基于一個或多個Ip位址。

到K8s體系下之後,要考慮的是Pod的Ip不是固定的。是以目前的路由規則不能滿足條件,而且會産生很多規則垃圾資料。K8s體系下,通過service查找Pod,是基于label selector; 通過deployment管理Pod,其實也是基于Pod label selector。是以Pod label selector是在K8s習題中比較通用的解決方案。

以路由規則為例,需要支援一種新的路由規則:label路由。通過一定條件比對之後,将結果定位到以label selector查詢到的Pod清單裡,而非原來的Ip清單。

要支援label路由,Client端需要擷取到Client端自己的Pod label資訊,還需要擷取到server Pod清單中每個Pod的label資訊。

應用擷取目前Pod的資訊方式
  1. Pod定義環境變量,應用擷取

Dubbo提供對環境變量讀取的支援,Pod中需要按照Dubbo定義的環境變量設定具體的Pod資訊。

  1. 通過Downward Api傳遞Pod資訊

Dubbo需要提供對Downward的目錄讀取,Pod中需要定制downward的對應配置。

  1. 通過Api server擷取資料

最強大的方式,但是應用需要強依賴于Api server。

應用擷取其他Pod的資訊方式
  1. 通過調用其他Pod的服務擷取

依賴于應用能擷取自身的Pod資訊,同時将自身的Pod資訊暴露成服務(rest或dubbo協定)

Client端通過調用對用的Pod擷取到對應Pod的完整資訊。

  1. 通過api server擷取資料

很強大,但增加了對api server的依賴。

服務注冊和發現

K8s體系下,RPC服務發現有幾種方式:

  • 注冊機制:将Ip寫入注冊中心,用心跳保持連接配接;當心跳停止,從注冊中心删除。
  • 利用Service+DNS:建立一個Service,可以通過标簽選擇到一組Pod清單,這個service對應一個不變的叢集Ip;Client端通過DNS方式或者直接通路叢集Ip。這個叢集Ip,約等于實作了負載均衡 (Iptable方式)。
  • 利用headless service(DNS):headless service和上面的service的差別是,它不提供叢集Ip,通過主機名的形式擷取一組Ip清單,Client端自己決定通路哪個Pod。
  • api server: Client端直接請求Api server,擷取到Pod的清單,Client自己決定通路Pod的邏輯。同時擷取的時候增加watch,api server會将Pod的變化資訊同步Client。

通過拿到Server端的Ip或者host,Client端就可以發起Http或者其他協定的請求。

下面介紹符合Dubbo的可行方案:

1. Dubbo + Zookeeper Pod cluster (HSF+CS cluster)

這是最簡單的方式,Dubbo本身不需要做任何改造。

帶來的問題是增加了ZooKeeper的維護,同時這個方案很不雲原生,和K8s的體系沒有任何關系。

腦暴

上面方案是将ZooKeeper作為注冊中心,那麼是否可以将K8s裡service作為注冊中心呢?dubbo裡每個接口去建立一個service,每個應用執行個體啟動過程中去更新Endpoint資訊,建立Service-> Endpoint-> Ip清單的關系。

這種方案中K8s service的定義被改造了,而且定義了過多的service,service的維護管理是個難題。

基于K8s的場景

在傳統的RPC領域,服務分成服務注冊和服務發現。在K8s領域Pod和應用是一對一的關系,K8s本身就提供了Pod查找的能力,是以一定程度上服務注冊其實可以不存在,而隻需要服務發現。但是這個其實需要一個前提:

dubbo需要将服務注冊發現的粒度改造成應用次元。

在運維層面,将app=xxx (應用名)寫入到Pod的label中。

2. Dubbo + K8s DNS

如果K8s service提供了cluster Ip,那麼Dubbo隻負責調用該叢集Ip,路由和負載均衡的邏輯則交給了K8s的proxy來完成。此方案削減了Dubbo的核心能力。

接下來讨論headless service提供的能力。

通過請求

<service>.<ns>.svc.<zone>. IN A

的方式發起請求擷取Ip清單,但是需要輪詢方式不斷擷取更新的Ip清單。

服務治理相關的功能,需要在上述服務治理部分中獨立支援。

3. Dubbo + Api Server

Dubbo 在 K8s 下的思考K8S介紹RPC介紹和分析遇到的問題和挑戰問題梳理Dubbo 和 Spring CloudDubbo + K8S總結

Pod的容器中部署的dubbo應用,服務注冊流程可以直接删除,服務發現功能通過和Api Server進行互動,擷取Pod和service資訊,同時watch Pod和service的變更。通過這種方式之後,服務治理相關的資訊也可以通過Api Server直接擷取。

4. Dubbo + Istio + Envoy

Dubbo可以直接使用指定Ip+端口的方式調用同一個Pod下Envoy (也可能是同一個node的Envoy)。Dubbo将路由規則,負載均衡,熔斷等功能交給Istio和Envoy。Envoy需要支援Dubbo協定的轉發。

是以Dubbo需要完成兩個事情:本地IP直連(現有功能), 多餘功能裁剪(暫未實作)。

5. Dubbo + Istio

Dubbo 在 K8s 下的思考K8S介紹RPC介紹和分析遇到的問題和挑戰問題梳理Dubbo 和 Spring CloudDubbo + K8S總結

Dubbo 應用不再依賴 Envoy 作為 sidecar ,而是直接和 Istio 進行互動,把 Istio 作為注冊中心,作為服務治理的配置中心。

Dubbo 需要提供類似的 xDS 協定,在pilot将service的instance轉換成dubbo的協定格式。

Dubbo 還需要去适配 istio 的一些功能,如健康檢查,安全相關的邏輯。具體實作可以參考 Envoy 的實作。

6. Dubbo和 Istio 在 K8s 體系下共存

這個可選擇的方案較多,我提供兩種思路,供大家思考:

所有的服務注冊通過K8s的機制完成,所有的服務發現通過 Headless service 完成。sidecar 在建立過程中,需要對原有的 K8s service 進行 update 。

Nacos 作為 Dubbo 的注冊中心,并且需要将 K8s 中的資料進行部分中轉。Dubbo 應用,将服務注冊以應用次元注冊到 Nacos ,Istio Pilot 需要識别 Nacos 資料;Istio 的運作機制基本不變,需要将 K8s service instance 的資料寫入到 nacos ,供 Dubbo 調用。

7. 雲上和雲下環境共存 & 雲上多叢集環境

Istio 提供了跨叢集和雲上雲下的解決方案, kubeFed 作為 K8s 的跨叢集解決方案也能起到一定作用。

這個課題的複雜度更加高,心中有了一些答案,期望大家通過上文也有一定的思考。

服務查詢

抛出三種方式,供大家思考。

Dubbo原有方式

Dubbo原有的服務查詢

是針對接口的查詢,每個接口會有版本号群組别。接口名+版本号+組别确定唯一的服務集合,這個服務集下有對應的服務提供者和服務消費者(接口級依賴),服務提供者是一組Ip+port清單,服務消費者也是一組Ip+port清單。

Dubbo 在 K8s 下的思考K8S介紹RPC介紹和分析遇到的問題和挑戰問題梳理Dubbo 和 Spring CloudDubbo + K8S總結

當做了改造成應用級别的服務注冊或者直接使用K8s自帶的Pod發現機制的話,需要做一些改造,這部分改造,和前面提到的一樣,放到其他文章裡單獨說明。

隻支援應用查詢

和Spring Cloud類似,支援應用次元的查詢。查詢到具體應用之後,應用詳情下包含了Ip+port清單,每個Ip+port其實就是一個應用的執行個體。點選開每個應用執行個體,可以檢視每個應用的詳細資訊,詳細資訊包含了該執行個體提供了哪些服務。

接口+應用查詢均衡

在原來隻支援應用查詢的基礎上,增加一步:支援查詢某個接口對應的應用清單,而大部分接口隻屬于一個應用。

再點選應用清單下具體的應用之後,會跳到應用詳情。

上述讨論的是開源的方案,是以相對曆史包袱比較少。對一些大公司想從原有的RPC方案切換到雲原生的支援,需要考慮更多相容性和性能,需要付出更大的代價。

雲原生的趨勢已經勢不可擋,在RPC領域究竟哪種方案最終能夠勝出,現在還言之過早。我相信Service Mesh 和傳統的RPC (Dubbo/ gRPC) 都會有自己的一席之地,一切讓時間給我們答案吧。

作者簡介:曹勝利,Apache Dubbo PMC,關注RPC領域。在阿裡内部負責Dubbo開源和ClassLoader隔離器Pandora Boot。