W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
Triple 協(xié)議的格式和原理請(qǐng)參閱 RPC 通信協(xié)議
根據(jù) Triple 設(shè)計(jì)的目標(biāo),?Triple
?協(xié)議有以下優(yōu)勢(shì):
當(dāng)前使用其他協(xié)議的 Dubbo 用戶,框架提供了兼容現(xiàn)有序列化方式的遷移能力,在不影響線上已有業(yè)務(wù)的前提下,遷移協(xié)議的成本幾乎為零。
需要新增對(duì)接 Grpc 服務(wù)的 Dubbo 用戶,可以直接使用 Triple 協(xié)議來(lái)實(shí)現(xiàn)打通,不需要單獨(dú)引入 grpc client 來(lái)完成,不僅能保留已有的 Dubbo 易用性,也能降低程序的復(fù)雜度和開(kāi)發(fā)運(yùn)維成本,不需要額外進(jìn)行適配和開(kāi)發(fā)即可接入現(xiàn)有生態(tài)。
對(duì)于需要網(wǎng)關(guān)接入的 Dubbo 用戶,Triple 協(xié)議提供了更加原生的方式,讓網(wǎng)關(guān)開(kāi)發(fā)或者使用開(kāi)源的 grpc 網(wǎng)關(guān)組件更加簡(jiǎn)單。網(wǎng)關(guān)可以選擇不解析 payload ,在性能上也有很大提高。在使用 Dubbo 協(xié)議時(shí),語(yǔ)言相關(guān)的序列化方式是網(wǎng)關(guān)的一個(gè)很大痛點(diǎn),而傳統(tǒng)的 HTTP 轉(zhuǎn) Dubbo 的方式對(duì)于跨語(yǔ)言序列化幾乎是無(wú)能為力的。同時(shí),由于 Triple 的協(xié)議元數(shù)據(jù)都存儲(chǔ)在請(qǐng)求頭中,網(wǎng)關(guān)可以輕松的實(shí)現(xiàn)定制需求,如路由和限流等功能。
Dubbo2 的用戶使用 dubbo 協(xié)議 + 自定義序列化,如 hessian2 完成遠(yuǎn)程調(diào)用。
而 Grpc 的默認(rèn)僅支持 Protobuf 序列化,對(duì)于 Java 語(yǔ)言中的多參數(shù)以及方法重載也無(wú)法支持。
Dubbo3的之初就有一條目標(biāo)是完美兼容 Dubbo2,所以為了 Dubbo2 能夠平滑升級(jí), Dubbo 框架側(cè)做了很多工作來(lái)保證升級(jí)的無(wú)感,目前默認(rèn)的序列化和 Dubbo2 保持一致為?hessian2
?。
所以,如果決定要升級(jí)到 Dubbo3 的 Triple 協(xié)議,只需要修改配置中的協(xié)議名稱為 tri (注意: 不是triple)即可。
接下來(lái)我們我們以一個(gè)使用 Dubbo2 協(xié)議的工程 來(lái)舉例,如何一步一步安全的升級(jí)。
dubbo
?協(xié)議啟動(dòng) ?provider
?和 ?consumer
?,并完成調(diào)用。dubbo
?和 ?tri
?協(xié)議 啟動(dòng)?provider
?,以 ?dubbo
? 協(xié)議啟動(dòng) ?consumer
?,并完成調(diào)用。tri
?協(xié)議 啟動(dòng) ?provider
?和 ?consumer
?,并完成調(diào)用。public interface IWrapperGreeter { //... /** * 這是一個(gè)普通接口,沒(méi)有使用 pb 序列化 */ String sayHello(String request); }
public class IGreeter2Impl implements IWrapperGreeter { @Override public String sayHello(String request) { return "hello," + request; } }
為保證兼容性,我們先將部分 provider 升級(jí)到 ?dubbo3
?版本并使用 ?dubbo
?協(xié)議。
使用 dubbo
協(xié)議啟動(dòng)一個(gè) Provider
和 Consumer
,完成調(diào)用,輸出如下:
對(duì)于線上服務(wù)的升級(jí),不可能一蹴而就同時(shí)完成 provider 和 consumer 升級(jí), 需要按步操作,保證業(yè)務(wù)穩(wěn)定。 第二步, provider 提供雙協(xié)議的方式同時(shí)支持 dubbo + tri 兩種協(xié)議的客戶端。
結(jié)構(gòu)如圖所示:
按照推薦升級(jí)步驟,provider 已經(jīng)支持了tri協(xié)議,所以 dubbo3的 consumer 可以直接使用 tri 協(xié)議
使用dubbo
協(xié)議和triple
協(xié)議啟動(dòng)Provider
和Consumer
,完成調(diào)用,輸出如下:
當(dāng)所有的 consuemr 都升級(jí)至支持 ?Triple
?協(xié)議的版本后,?provider
?可切換至僅使用 ?Triple
?協(xié)議啟動(dòng)
結(jié)構(gòu)如圖所示:
Provider 和 Consumer 完成調(diào)用,輸出如下:
通過(guò)上面介紹的升級(jí)過(guò)程,我們可以很簡(jiǎn)單的通過(guò)修改協(xié)議類型來(lái)完成升級(jí)??蚣苁窃趺磶臀覀冏龅竭@些的呢?
通過(guò)對(duì) Triple 協(xié)議的介紹,我們知道Dubbo3的 Triple 的數(shù)據(jù)類型是 protobuf 對(duì)象,那為什么非 protobuf 的 java 對(duì)象也可以被正常傳輸呢。
這里 Dubbo3 使用了一個(gè)巧妙的設(shè)計(jì),首先判斷參數(shù)類型是否為 protobuf 對(duì)象,如果不是。用一個(gè) protobuf 對(duì)象將 request 和 response 進(jìn)行 wrapper,這樣就屏蔽了其他各種序列化帶來(lái)的復(fù)雜度。在 wrapper 對(duì)象內(nèi)部聲明序列化類型,來(lái)支持序列化的擴(kuò)展。
wrapper 的protobuf的 IDL如下:
syntax = "proto3"; package org.apache.dubbo.triple; message TripleRequestWrapper { // hessian4 // json string serializeType = 1; repeated bytes args = 2; repeated string argTypes = 3; } message TripleResponseWrapper { string serializeType = 1; bytes data = 2; string type = 3; }
對(duì)于請(qǐng)求,使用TripleRequestWrapper進(jìn)行包裝,對(duì)于響應(yīng)使用TripleResponseWrapper進(jìn)行包裝。
對(duì)于請(qǐng)求參數(shù),可以看到 args 被repeated修飾,這是因?yàn)樾枰С?java 方法的多個(gè)參數(shù)。當(dāng)然,序列化只能是一種。序列化的實(shí)現(xiàn)沿用 Dubbo2 實(shí)現(xiàn)的 spi
建議新服務(wù)均使用該方式
對(duì)于 Dubbo3 和 Triple 來(lái)說(shuō),主推的是使用 protobuf 序列化,并且使用 proto 定義的 IDL 來(lái)生成相關(guān)接口定義。以 IDL 做為多語(yǔ)言中的通用接口約定,加上 Triple 與 Grpc 的天然互通性,可以輕松地實(shí)現(xiàn)跨語(yǔ)言交互,例如 Go 語(yǔ)言等。
將編寫(xiě)好的 .proto 文件使用 dubbo-compiler 插件進(jìn)行編譯并編寫(xiě)實(shí)現(xiàn)類,完成方法調(diào)用:
從上面升級(jí)的例子我們可以知道,Triple 協(xié)議使用 protbuf 對(duì)象序列化后進(jìn)行傳輸,所以對(duì)于本身就是 protobuf 對(duì)象的方法來(lái)說(shuō),沒(méi)有任何其他邏輯。
使用 protobuf 插件編譯后接口如下:
public interface PbGreeter { static final String JAVA_SERVICE_NAME = "org.apache.dubbo.sample.tri.PbGreeter"; static final String SERVICE_NAME = "org.apache.dubbo.sample.tri.PbGreeter"; static final boolean inited = PbGreeterDubbo.init(); org.apache.dubbo.sample.tri.GreeterReply greet(org.apache.dubbo.sample.tri.GreeterRequest request); default CompletableFuture<org.apache.dubbo.sample.tri.GreeterReply> greetAsync(org.apache.dubbo.sample.tri.GreeterRequest request){ return CompletableFuture.supplyAsync(() -> greet(request)); } void greetServerStream(org.apache.dubbo.sample.tri.GreeterRequest request, org.apache.dubbo.common.stream.StreamObserver<org.apache.dubbo.sample.tri.GreeterReply> responseObserver); org.apache.dubbo.common.stream.StreamObserver<org.apache.dubbo.sample.tri.GreeterRequest> greetStream(org.apache.dubbo.common.stream.StreamObserver<org.apache.dubbo.sample.tri.GreeterReply> responseObserver); }
Stream 是 Dubbo3 新提供的一種調(diào)用類型,在以下場(chǎng)景時(shí)建議使用流的方式:
Stream 分為以下三種:
由于 java 語(yǔ)言的限制,BIDIRECTIONAL_STREAM 和 CLIENT_STREAM 的實(shí)現(xiàn)是一樣的。
在 Dubbo3 中,流式接口以 SteamObserver 聲明和使用,用戶可以通過(guò)使用和實(shí)現(xiàn)這個(gè)接口來(lái)發(fā)送和處理流的數(shù)據(jù)、異常和結(jié)束。
對(duì)于 Dubbo2 用戶來(lái)說(shuō),可能會(huì)對(duì)StreamObserver感到陌生,這是Dubbo3定義的一種流類型,Dubbo2 中并不存在 Stream 的類型,所以對(duì)于遷移場(chǎng)景沒(méi)有任何影響。
流的語(yǔ)義保證
public interface IWrapperGreeter { StreamObserver<String> sayHelloStream(StreamObserver<String> response); void sayHelloServerStream(String request, StreamObserver<String> response); }
Stream 方法的方法入?yún)⒑头祷刂凳菄?yán)格約定的,為防止寫(xiě)錯(cuò)而導(dǎo)致問(wèn)題,Dubbo3 框架側(cè)做了對(duì)參數(shù)的檢查, 如果出錯(cuò)則會(huì)拋出異常。 對(duì)于 雙向流(BIDIRECTIONAL_STREAM), 需要注意參數(shù)中的 StreamObserver 是響應(yīng)流,返回參數(shù)中的 StreamObserver 為請(qǐng)求流。
public class WrapGreeterImpl implements WrapGreeter { //... @Override public StreamObserver<String> sayHelloStream(StreamObserver<String> response) { return new StreamObserver<String>() { @Override public void onNext(String data) { System.out.println(data); response.onNext("hello,"+data); } @Override public void onError(Throwable throwable) { throwable.printStackTrace(); } @Override public void onCompleted() { System.out.println("onCompleted"); response.onCompleted(); } }; } @Override public void sayHelloServerStream(String request, StreamObserver<String> response) { for (int i = 0; i < 10; i++) { response.onNext("hello," + request); } response.onCompleted(); } }
delegate.sayHelloServerStream("server stream", new StreamObserver<String>() { @Override public void onNext(String data) { System.out.println(data); } @Override public void onError(Throwable throwable) { throwable.printStackTrace(); } @Override public void onCompleted() { System.out.println("onCompleted"); } }); StreamObserver<String> request = delegate.sayHelloStream(new StreamObserver<String>() { @Override public void onNext(String data) { System.out.println(data); } @Override public void onError(Throwable throwable) { throwable.printStackTrace(); } @Override public void onCompleted() { System.out.println("onCompleted"); } }); for (int i = 0; i < n; i++) { request.onNext("stream request" + i); } request.onCompleted();
對(duì)于 Protobuf 序列化方式,推薦編寫(xiě) IDL 使用 compiler 插件進(jìn)行編譯生成。生成的代碼大致如下:
public interface PbGreeter { static final String JAVA_SERVICE_NAME = "org.apache.dubbo.sample.tri.PbGreeter"; static final String SERVICE_NAME = "org.apache.dubbo.sample.tri.PbGreeter"; static final boolean inited = PbGreeterDubbo.init(); //... void greetServerStream(org.apache.dubbo.sample.tri.GreeterRequest request, org.apache.dubbo.common.stream.StreamObserver<org.apache.dubbo.sample.tri.GreeterReply> responseObserver); org.apache.dubbo.common.stream.StreamObserver<org.apache.dubbo.sample.tri.GreeterRequest> greetStream(org.apache.dubbo.common.stream.StreamObserver<org.apache.dubbo.sample.tri.GreeterReply> responseObserver); }
Triple協(xié)議的流模式是怎么支持的呢?
關(guān)于 Triple 協(xié)議的應(yīng)用級(jí)服務(wù)注冊(cè)和發(fā)現(xiàn)和其他語(yǔ)言是一致的,可以通過(guò)下列內(nèi)容了解更多。
通過(guò)對(duì)于協(xié)議的介紹,我們知道 Triple 協(xié)議是基于 HTTP2 并兼容 GRPC。為了保證和驗(yàn)證與GRPC互通能力,Dubbo3 也編寫(xiě)了各種從場(chǎng)景下的測(cè)試。詳細(xì)的可以通過(guò)這里 了解更多。
用過(guò) Grpc 的同學(xué)應(yīng)該對(duì) Stub 都不陌生。 Grpc 使用 compiler 將編寫(xiě)的 proto 文件編譯為相關(guān)的 protobuf 對(duì)象和相關(guān) rpc 接口。默認(rèn)的會(huì)同時(shí)生成幾種不同的 stub
stub 用一種統(tǒng)一的使用方式幫我們屏蔽了不同調(diào)用方式的細(xì)節(jié)。不過(guò)目前 Dubbo3 暫時(shí)只支持傳統(tǒng)定義接口并進(jìn)行調(diào)用的使用方式。
在不久的未來(lái),Triple 也將實(shí)現(xiàn)各種常用的 Stub,讓用戶寫(xiě)一份proto文件,通過(guò) comipler 可以在任意場(chǎng)景方便的使用,請(qǐng)拭目以待。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: