dubbogo 3.0:牵手 gRPC 走向云原生时代
作者 | 李志信? 于雨
來(lái)源|阿里巴巴云原生公眾號(hào)
自從 2011 年 Dubbo 開源之后,被大量中小公司采用,一直是國(guó)內(nèi)最受歡迎的 RPC 框架。2014 年,由于阿里內(nèi)部組織架構(gòu)調(diào)整,Dubbo 暫停維護(hù)了一段時(shí)間,之后隨著 Spring Cloud 的面世,兩個(gè)體系在融合中一起助推了微服務(wù)的火熱。
不過(guò)這世界變化快,自從以 docker 為代表的的容器技術(shù)和以 K8s 為代表的容器編排技術(shù)登上舞臺(tái)之后,云原生時(shí)代到來(lái)了。在云原生時(shí)代,不可變的基礎(chǔ)設(shè)施給原有的中間件帶來(lái)了不可變的中間件基礎(chǔ)設(shè)施:gRPC 統(tǒng)一了底層通信層;protobuf 統(tǒng)一了序列化協(xié)議;以 envoy + istio 為代表的 service mesh 逐漸統(tǒng)一了服務(wù)的控制面與數(shù)據(jù)面。
dubbogo 的天然使命是:Bridging the gap between Java and Go。保持 Go 應(yīng)用與 Java 應(yīng)用互聯(lián)互通的同時(shí),借助 Go 語(yǔ)言(事實(shí)上的第一云原生語(yǔ)言)的優(yōu)勢(shì)擁抱云原生時(shí)代。dubbogo 社區(qū) 2020 年勠力打造三支箭:
-
已經(jīng)發(fā)布的對(duì)齊 dubbo 2.7 的 dubbogo v1.5 版本;
-
近期將要發(fā)布的 sidecar 形態(tài)的 dubbo-go-proxy 項(xiàng)目;
-
以及處于進(jìn)行時(shí)的 dubbogo 3.0。
用一句話概括 dubbogo 3.0 即是:新通信協(xié)議、新序列化協(xié)議、新應(yīng)用注冊(cè)模型以及新的服務(wù)治理能力!本文主要著重討論 dubbogo 3.0 的新通信協(xié)議和應(yīng)用級(jí)服務(wù)注冊(cè)發(fā)現(xiàn)模型。
dubbogo 3.0 vs gRPC
知己知彼,方能進(jìn)步。dubbogo 3.0 的通信層改進(jìn)主要借鑒了 gRPC。
gRPC 協(xié)議,簡(jiǎn)單來(lái)說(shuō)就是 http2 協(xié)議的基礎(chǔ)之上,增加了特定的協(xié)議 header:“grpc-” 開頭的 header 字段,采用特定的打解包工具(protobuf)對(duì)數(shù)據(jù)進(jìn)行序列化,從而實(shí)現(xiàn) RPC 調(diào)用。
眾所周知,gRPC 幾乎沒(méi)有服務(wù)治理能力,而阿里云現(xiàn)有 dubbo 框架兼具 RPC 和服務(wù)治理能力,整體實(shí)力不遜于 gRPC。但在“大家都用 gRPC” 這樣的背景之下,dubbogo 3.0 的新通信協(xié)議就必須完美兼容 gRPC,對(duì)開發(fā)者已部署的服務(wù)完全兼容,并在此基礎(chǔ)之上延續(xù)已有 dubbo 協(xié)議和服務(wù)治理能力,進(jìn)而推出一系列新策略:比如 mesh 支持、應(yīng)用級(jí)服務(wù)注冊(cè)等。
dubbogo 3.0 vs dubbogo 1.5
目前已有的 dubbo 2.7 協(xié)議已經(jīng)盡可能實(shí)現(xiàn)了 gRPC 的支持。開發(fā)者可以通過(guò) protoc-gen-dubbo 工具將 pb IDL 協(xié)議轉(zhuǎn)換為框架支持的 stub,再借助底層 gRPC conn 的 RPC 過(guò)程,將已有的服務(wù)治理能力自上而下傳遞給 gRPC,因此實(shí)現(xiàn)了 gRPC 服務(wù)的支持。
dubbo-go v1.5.x 也支持 gRPC 的 Stream 調(diào)用。和 unary RPC 類似,通過(guò)產(chǎn)生框架支持的 stub,在底層 gRPC stream 調(diào)用的基礎(chǔ)之上,將流式 RPC 的能力和并入框架。但由于 dubbo v2.7.x / dubbo-go v1.5.x 本身并不支持流式調(diào)用,所以沒(méi)有對(duì) gRPC stream 調(diào)用的進(jìn)行上層服務(wù)治理支持。
開發(fā)者所面臨的問(wèn)題就是:我們?cè)谑褂?dubbo-go2.7 進(jìn)行 grpc 協(xié)議傳輸?shù)臅r(shí)候,或多或少不是那么放心。
而即將推出的 dubbo-go 3.0 協(xié)議將從根源解決這個(gè)問(wèn)題。
協(xié)議兼容的三種層次
筆者認(rèn)為,一款服務(wù)框架對(duì)于第三方協(xié)議的支持可分為三個(gè)程度:應(yīng)用層次、協(xié)議層次、傳輸層次。
一款框架如果在一個(gè)協(xié)議的 sdk 之上封裝接口,可以認(rèn)為它處于應(yīng)用層次支持,這樣的框架需要遵循下層 sdk 的接口,可擴(kuò)展性較差。
處于協(xié)議層次的框架,從配置層到服務(wù)治理層均由本框架提供,而在此之下的協(xié)議層到網(wǎng)絡(luò)傳輸層均使用某個(gè)固定的通信協(xié)議,這樣的框架可以解決服務(wù)治理的問(wèn)題,但框架本身無(wú)法與第三方協(xié)議完全適配,如果不適配就會(huì)出現(xiàn)對(duì)第三方協(xié)議支持的削弱,比如上面說(shuō)到的 dubbo-go 1.5 對(duì) stream rpc 支持的缺陷。
如果想進(jìn)一步支持更多的第三方協(xié)議,需要從傳輸層下手,真正了解第三方協(xié)議的具體字段、所依賴的底層協(xié)議(比如 HTTP2)的幀模型和數(shù)據(jù)流,再開發(fā)出與第三方協(xié)議完全一致的數(shù)據(jù)交互模塊,作為本框架的底層。這樣做的好處是最大程度賦予了協(xié)議的可擴(kuò)展性,可以在兼容已有協(xié)議的基礎(chǔ)之上,可選地增加開發(fā)者需要的字段,從而實(shí)現(xiàn)已有協(xié)議無(wú)法實(shí)現(xiàn)的功能,就比如 dubbogo 3.0 將支持的反壓策略。
基于 HTTP2 的通信流程
gRPC 一次基于 HTTP2 的 unary rpc 調(diào)用傳輸主要流程如下:
-
client 發(fā)送 Magic 信息:
PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n; -
server 收到并檢查是否正確;
-
client 和 server 互相發(fā)送 setting 幀,收到后發(fā)送 ACK 確認(rèn);
-
client 發(fā)送 Header 幀,包含 gRPC 協(xié)議字段,以 End Headers 作為 Header 結(jié)束標(biāo)志;
-
client 緊接著發(fā)送 Data 幀,包含 RPC 調(diào)用的 request 信息,以 End Stream 作為 Data 結(jié)束標(biāo)志;
-
server 調(diào)用函數(shù)獲得結(jié)果;
-
server 發(fā)送 Header 幀,包含 gRPC 協(xié)議字段,以 End Headers 作為 Header 結(jié)束標(biāo)志;
-
server 緊接著發(fā)送 Data 幀,包含 RPC 調(diào)用回傳的 response 信息;
-
server 緊接著再次發(fā)送 Header 幀,包含 RPC 狀態(tài)和 message 信息,以 End Stream 作為本次 RPC 調(diào)用結(jié)束標(biāo)志。
其中包含 gRPC 調(diào)用信息的 HTTP2 Header 幀如下圖:
另外,在 gRPC 的 stream 調(diào)用中,可在 server 端回傳的過(guò)程中發(fā)送多次 Data,調(diào)用結(jié)束后再發(fā)送 Header 終止 RPC 過(guò)程,并匯報(bào)狀態(tài)信息。
dubbogo 3.0 的通信層將在 HTTP2 通信協(xié)議之上采用同樣的通信流程,以保證與 gRPC 的底層通信溝通能力。
dubbogo 3.0 預(yù)期通信架構(gòu)
除了通信協(xié)議采用 HTTP2 外,dubbogo 3.0 將采用基于 google protobuf 的 triple 協(xié)議【下面稱為 dubbo3 協(xié)議】作為 dubbogo 3.0 的序列化協(xié)議,為 dubbo 將來(lái)支持更多的編程語(yǔ)言打下通信協(xié)議層面的基礎(chǔ)。
目前設(shè)計(jì)的 dubbogo 3.0 傳輸模型如下:
-
為保證同時(shí)支持 unary RPC 和 stream RPC,在 server 端和 client 端增加數(shù)據(jù)流結(jié)構(gòu),以異步調(diào)用的形式完成數(shù)據(jù)傳遞;
-
繼續(xù)支持原有的 TCP 通信能力;
-
在 HTTP2 的通信協(xié)議之上支持 dubbo3 協(xié)議,decode 過(guò)程兼容 gRPC 使用的 protobuf,保證與 gRPC 服務(wù)打通。
應(yīng)用級(jí)服務(wù)注冊(cè)發(fā)現(xiàn)
1. 應(yīng)用級(jí)服務(wù)注冊(cè)發(fā)現(xiàn)介紹
dubbogo 3.0 使用的新一代服務(wù)注冊(cè)發(fā)現(xiàn)體系,將摒棄舊版的“接口級(jí)注冊(cè)發(fā)現(xiàn)”,使用“應(yīng)用級(jí)別注冊(cè)發(fā)現(xiàn)”。
簡(jiǎn)單地說(shuō),接口級(jí)別注冊(cè)發(fā)現(xiàn),在注冊(cè)中心中以 RPC 服務(wù)為 key,以實(shí)例列表作為 value 來(lái)組織數(shù)據(jù)的,而我們新引入的“應(yīng)用粒度的服務(wù)發(fā)現(xiàn)”,它以應(yīng)用名(Application)作為 key,以這個(gè)應(yīng)用部署的一組實(shí)例(Instance)列表作為 value。這帶來(lái)兩點(diǎn)不同:
-
數(shù)據(jù)映射關(guān)系變了,從 RPC Service -> Instance 變?yōu)?Application -> Instance;
-
數(shù)據(jù)變少了,注冊(cè)中心沒(méi)有了 RPC Service 及其相關(guān)配置信息。
可以認(rèn)為,基于應(yīng)用粒度的模型所存儲(chǔ)和推送的數(shù)據(jù)量是和應(yīng)用、實(shí)例數(shù)成正比的,只有當(dāng)我們的應(yīng)用數(shù)增多或應(yīng)用的實(shí)例數(shù)增長(zhǎng)時(shí),地址推送壓力才會(huì)上漲。
而對(duì)于基于接口粒度的模型,數(shù)據(jù)量是和接口數(shù)量正相關(guān)的,鑒于一個(gè)應(yīng)用通常發(fā)布多個(gè)接口的現(xiàn)狀,其數(shù)量級(jí)一般是比應(yīng)用粒度的數(shù)十倍。另外一個(gè)關(guān)鍵點(diǎn)在于,接口的定義更多的是業(yè)務(wù)側(cè)的內(nèi)部行為,接口粒度導(dǎo)致的集群規(guī)模評(píng)估的不透明,而實(shí)例、應(yīng)用增長(zhǎng)都通常是在運(yùn)維側(cè)的規(guī)劃之中,可控性較好。
工商銀行曾經(jīng)對(duì)這兩個(gè)模型進(jìn)行生產(chǎn)測(cè)算:應(yīng)用級(jí)服務(wù)注冊(cè)模型可以讓注冊(cè)中心上的數(shù)據(jù)量變成原來(lái)的 1.68%,新模型可以讓 zookeeper 輕松至成 10 萬(wàn)級(jí)別的服務(wù)量和 10 萬(wàn)級(jí)別的節(jié)點(diǎn)量。
2. 元數(shù)據(jù)中心同步機(jī)制的引入
數(shù)據(jù)中心的數(shù)據(jù)量變少所造成的結(jié)果,是 RPC 服務(wù)相關(guān)的數(shù)據(jù)在注冊(cè)中心消失了,只有 application - instance ?這兩個(gè)層級(jí)的數(shù)據(jù)。為了保證這部分缺少的 RPC 服務(wù)數(shù)據(jù)仍然能被 Consumer 端正確的感知,我們?cè)?Consumer 和 Provider ?間建立了一條單獨(dú)的通信通道,目前針對(duì)元數(shù)據(jù)同步有兩種具體的可選方案,分別是:
-
內(nèi)建 MetadataService;
-
獨(dú)立的元數(shù)據(jù)中心,通過(guò)中細(xì)化的元數(shù)據(jù)集群協(xié)調(diào)數(shù)據(jù)。
3. 兼容舊版本 dubbo-go
為了使整個(gè)開發(fā)流程對(duì)老的 dubbo-go 用戶更透明,同時(shí)避免指定 provider 對(duì)可擴(kuò)展性帶來(lái)的影響),我們?cè)O(shè)計(jì)了一套 RPC服務(wù)到應(yīng)用名的映射關(guān)系,以嘗試在 consumer 自動(dòng)完成 RPC 服務(wù)到 provider 應(yīng)用名的轉(zhuǎn)換。
這套設(shè)計(jì)可以讓 dubbogo 3.0 中同時(shí)保持對(duì) dubbo v2.6.x、dubbo v2.7.x 和 dubbo v3.0.x 三個(gè)大版的互聯(lián)互通。
統(tǒng)一路由的支持
路由在概念上可以理解為從已有的所有 IP 地址列表中,根據(jù)特定的路由規(guī)則,挑選出需要的 ip 地址子集。路由的過(guò)程需要根據(jù)配置好的路由規(guī)則進(jìn)行篩選,最終取所有路由規(guī)則的交集獲得結(jié)果。多個(gè)路由如同流水線一樣,形成一條路由鏈,從所有的地址表中篩選出最終目的地址集合,再通過(guò)負(fù)載均衡策略選擇訪問(wèn)的地址。
1. 路由鏈
可以把路由鏈的邏輯簡(jiǎn)單理解為 target = rn(…r3(r2(r1(src))))。對(duì)于每一個(gè) router 內(nèi)部的邏輯,可以抽象為輸入地址 addrs-in 與 router 中按全量地址 addrs-all 實(shí)現(xiàn)切分好的 n 個(gè)互不相交的地址池 addrs-pool-1 … addrs-pool-n 按實(shí)現(xiàn)定義好的規(guī)則取交集作為輸出地址。以此類推,完成整個(gè)路由鏈的計(jì)算。
2. failover
在路由規(guī)則配置文件中可以配置 failover 字段。在尋找地址失敗時(shí)可以 failover, 選擇其他 subset,并且順序執(zhí)行下來(lái),直到找到地址,否則最后報(bào)地址找不到異常。
3. 兜底路由
在的路由規(guī)則配置中,可以配置一個(gè)沒(méi)有任何條件的 match, 最終的結(jié)果是至少會(huì)有一個(gè) subset 被選到,以達(dá)到地址空保護(hù)的作用。
作為 2020 年 dubbogo 社區(qū)打造并將在 2021 年初亮出的的三支箭之一,dubbogo 3.0 將帶來(lái)不同平常且煥然一新的開發(fā)體驗(yàn),敬請(qǐng)廣大開發(fā)者期待!
如果你有任何疑問(wèn),歡迎釘釘搜索群號(hào)加入交流群:釘釘群號(hào) 31363295。
dubbogo 3.0 目前是社區(qū)和 dubbo 官方團(tuán)隊(duì)-- 阿里中間件團(tuán)隊(duì)共同合作開發(fā)。
阿里云-中間件團(tuán)隊(duì)招募對(duì) dubbo3 (java & go)、dapr、arthas 有興趣的開發(fā)者。可以釘釘聯(lián)系 northlatitude,或者發(fā)送郵件至 beiwei.ly@alibaba-inc.com。
作者簡(jiǎn)介
李志信?(GitHubID LaurenceLiZhixin),阿里云云原生中間件團(tuán)隊(duì)開發(fā)工程師,dubbogo 社區(qū)開發(fā)者,中山大學(xué)軟件工程專業(yè)在校學(xué)生,擅長(zhǎng)使用 Go 語(yǔ)言,專注于云原生和微服務(wù)等技術(shù)方向。
于雨(github @AlexStocks),dubbo-go 項(xiàng)目和社區(qū)負(fù)責(zé)人,一個(gè)有十多年服務(wù)端做著基礎(chǔ)架構(gòu)研發(fā)一線工作經(jīng)驗(yàn)的程序員,陸續(xù)參與改進(jìn)過(guò) Muduo/Pika/Dubbo/Sentinel-go 等知名項(xiàng)目,目前在螞蟻金服可信原生部從事容器編排和 service mesh 工作。
總結(jié)
以上是生活随笔為你收集整理的dubbogo 3.0:牵手 gRPC 走向云原生时代的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 一个改变世界的“箱子”
- 下一篇: 刚刚,阿里云知行动手实验室正式开放公测了