Protocol Buffer(1)

現(xiàn)如今微服務(wù)很流行撇寞,而微服務(wù)很有可能是使用不同語言進(jìn)行構(gòu)建的应结。而微服務(wù)之間通常需要相互通信,所以微服務(wù)之間必須在以下幾個(gè)方面達(dá)成共識(shí):

需要使用某種API

數(shù)據(jù)格式

錯(cuò)誤的模式

負(fù)載均衡

奕枢。信轿。。

現(xiàn)在最流行的一種API風(fēng)格可能是REST曹铃,它主要是通過HTTP協(xié)議來傳輸JSON數(shù)據(jù)缰趋。

但是現(xiàn)在我們可以看看gRPC(https://grpc.io/),它來自Google陕见,并且支持眾多主流的語言包括Go秘血,Dart,C#评甜,C/C++直撤,Nodejs,Python等等蜕着。

下面就學(xué)習(xí)一下gRPC。


gRPC能解決哪些問題红柱?

構(gòu)建(Web)API是挺麻煩的承匣,因?yàn)闃?gòu)建API時(shí)我們得考慮:

數(shù)據(jù)的格式是JSON、XML還是二進(jìn)制的锤悄;

端點(diǎn)地址以及GET還是POST等韧骗;

如何調(diào)用API以及對(duì)異常的處理規(guī)則;

API的效率:一次調(diào)用讀取多少數(shù)據(jù)零聚?是否太多了或太少了袍暴?太少的話可能會(huì)導(dǎo)致多次API的調(diào)用;

延遲隶症;

擴(kuò)展性政模,是否能支持成上千個(gè)客戶端

負(fù)載均衡

與其他語言的互操作性

如何處理身份認(rèn)證、監(jiān)控蚂会、日志等等

以上這些問題據(jù)說gRPC都能解決淋样。。??


再次介紹一下gRPC

之前說了gRPC來自Google胁住,它是一個(gè)開源的框架趁猴;它同時(shí)也是Cloud Native Computation基金會(huì)(CNCF)的一部分,就像Docker和Kubernetes一樣彪见。

gRPC允許你為RPC(Remote Procedure Call)定義請(qǐng)求和響應(yīng)儡司,然后gRPC會(huì)幫你處理一切剩余問題

它速度快余指,執(zhí)行效率高捕犬,基于HTTP/2構(gòu)建,低延遲,支持流或听,與開發(fā)語言無關(guān)探孝,并且可以很簡(jiǎn)單的插入身份認(rèn)證、負(fù)載均衡誉裆、日志和監(jiān)控等功能顿颅。


RPC是啥

RPC是(Remote Procedure Call)遠(yuǎn)程過程調(diào)用。

在客戶端代碼使用RPC調(diào)用的時(shí)候足丢,就像直接調(diào)用了服務(wù)端的一個(gè)函數(shù)一樣粱腻。

例如在服務(wù)器端代碼是這樣的:


而在“遙遠(yuǎn)”的客戶端它是這樣調(diào)用服務(wù)器端的邏輯的,就像調(diào)用本地方法一樣:

而實(shí)際上客戶端在調(diào)用這個(gè)方法的時(shí)候斩跌,是要走網(wǎng)絡(luò)通信的绍些。


RPC它不是一個(gè)新的概念,很早它就出現(xiàn)了耀鸦。但是它存在很多的問題柬批。而gRPC它是對(duì)RPC一種非常簡(jiǎn)潔的實(shí)現(xiàn)并且解決了很多RPC的問題。



如何學(xué)習(xí)gRPC袖订?

首先氮帐,你得學(xué)習(xí)Protocol Buffers(https://developers.google.com/protocol-buffers/),簡(jiǎn)單的說洛姑,它可以用來定義消息和服務(wù)上沐。

然后,你只需要實(shí)現(xiàn)服務(wù)即可楞艾,剩余的gRPC代碼將會(huì)自動(dòng)為你生成参咙。

.proto這個(gè)文件可以適用于十幾種開發(fā)語言(包括服務(wù)端和客戶端),并且它允許你使用同一個(gè)框架來支持每秒百萬級(jí)以上的RPC調(diào)用硫眯。


gPRC使用的是合約優(yōu)先的API開發(fā)模式蕴侧,它默認(rèn)使用Protocol buffers (protobuf) 作為接口設(shè)計(jì)語言(IDL),這個(gè).proto文件包括兩部分:

gRPC服務(wù)的定義

服務(wù)端和客戶端之間傳遞的消息

看一個(gè)官網(wǎng)的例子(protobuf):

在這里定義了一個(gè)Greeter服務(wù)两入,它里面定義了一個(gè)SayHello的rpc調(diào)用戈盈。SayHello會(huì)發(fā)送HelloRequest這個(gè)消息,接收HelloReply這個(gè)消息谆刨。


為什么使用Protocol Buffers塘娶?

因?yàn)椋?/p>

它和開發(fā)語言無關(guān)

可以生成所有主流開發(fā)語言的代碼

數(shù)據(jù)是二進(jìn)制格式的,串行化的效率高痊夭,Payload比較小

也很適合傳遞大量的數(shù)據(jù)

通過設(shè)定某些規(guī)則刁岸,是的API的進(jìn)化也很簡(jiǎn)單


Protocol Buffer

開發(fā)環(huán)境:

IDE: VSCode

VSCode的擴(kuò)展插件:vscode-proto3和Clang-Format這兩個(gè)擴(kuò)展

Windows還需要安裝Clang,Windows 64位系統(tǒng)的地址如下:Clang for Windows (64-bit)她我;Mac:brew install clang-format虹曙。


第一個(gè)例子

選個(gè)文件夾迫横,建立一個(gè)名叫first.proto的文件:

1. 這行代碼表示我們使用的是語法是proto3,之前還有一個(gè)proto2酝碳;如果你不寫這一行矾踱,那么protocol buffer編譯器會(huì)認(rèn)為你采用的是proto2。這個(gè)必須是文件的第一個(gè)非空非注釋行疏哗。

2. 這里是定義了一個(gè)消息名稱為FirstMessage呛讲,類型是message。它里面定義了三個(gè)字段返奉,它們都是標(biāo)量類型(Scalar Type)贝搁,你也可以定義復(fù)合類型,這個(gè)以后再說芽偏。

3. 是指字段(Field)的類型

4. 字段的名稱

5. 字段的數(shù)值(也叫Tag)雷逆,這個(gè)數(shù)字是唯一的。它們是用來在信息格式里識(shí)別你的字段的污尉,一旦該類型被使用了膀哲,那么這個(gè)數(shù)字就不要再改變了。


標(biāo)量類型

數(shù)值型

數(shù)值型有很多種形式:double, float, int32, int64, uint32, uint64, sint32, sint64, fixed32, fixed64, sfixed32, sfixed64被碗。

根據(jù)需要選擇對(duì)應(yīng)的數(shù)值類型某宪。


布爾型

bool型可以有True和False兩個(gè)值。


字符串

string表示任意長(zhǎng)度的文本蛮放,但是它必須包含的是UTF-8編碼或7位ASCII的文本,長(zhǎng)度不可超過232奠宜。


字節(jié)型

bytes可表示任意的byte數(shù)組序列包颁,但是長(zhǎng)度也不可以超過232?,最后是由你來決定如何解釋這些bytes压真。例如你可以使用這個(gè)類型來表示一個(gè)圖片娩嚼。


做個(gè)例子

可以自己做一個(gè)例子,需求是這樣的:這個(gè)信息表示的是一個(gè)人Person滴肿,使用proto3語法岳悟,字段如下:ID,姓名泼差,身高贵少,體重,頭像堆缘,電子郵件滔灶,郵件是否已驗(yàn)證。

這個(gè)應(yīng)該沒有什么難度吼肥,不過要注意一下別忘記標(biāo)點(diǎn)符號(hào)录平。


字段的數(shù)值(Tag)

在Protocol Buffers里面麻车,字段的名其實(shí)沒那么重要,但是寫C#代碼的時(shí)候斗这,字段名還是很重要的动猬。

對(duì)于protobuf來說,這個(gè)tag是更為重要的表箭。

可以使用的最小的tag數(shù)值是1赁咙,最大值是229- 1, 或者 536,870,911。但是你不可以使用19000到19999之間的數(shù)燃逻,這部分?jǐn)?shù)是保留的序目。

還有一點(diǎn)值得注意的是:

從1到15的Tag數(shù)只占用1個(gè)字節(jié)的空間,所以它們應(yīng)該被用在頻繁使用的字段上伯襟。而從16到2047猿涨,則占用兩個(gè)字節(jié),它們可以用在不頻繁使用的字段上姆怪。


字段規(guī)則

protobuf的字段必須滿足以下兩個(gè)規(guī)則之一:

單數(shù)字段(Singular)

大概意思就是指這個(gè)字段只能出現(xiàn)0或1次(不能超過一次)叛赚,這也是proto3的默認(rèn)字段規(guī)則。


重復(fù)字段(Repeated)

與singular相對(duì)的就是repeated稽揭。如果你想做一個(gè)list或數(shù)組的話俺附,你可以使用重復(fù)字段這個(gè)概念。這個(gè)list可以有任何數(shù)量(包括0)的元素溪掀。它里面的值的順序?qū)?huì)得到保留事镣。


Repeated Fields 例子

還是使用前面的Person這個(gè)例子,我們?cè)诶锩嫣砑右粋€(gè)repeated字段(電話號(hào)碼):

就是在前面加上repeated這個(gè)關(guān)鍵字即可揪胃。

在proto3里面璃哟,標(biāo)量類型的repeated字段采用的是packed編碼。


注釋

proto文件里可以添加注釋喊递。它們通常被當(dāng)作你定義的這些消息的文檔随闪。

注釋很簡(jiǎn)單,還是兩種形式骚勘,直接看代碼就明白了:


保留的字段

如果你對(duì)你定義的消息類型進(jìn)行了更新铐伴,例如刪除某個(gè)字段或者注釋掉某個(gè)字段,那么其它開發(fā)者在以后更新這個(gè)消息類型的時(shí)候可能會(huì)重新使用被你刪除/注釋掉的字段的數(shù)值(tag)俏讹。如果以后還需要使用這個(gè)消息類型的老版本的proto文件当宴,那么這將會(huì)引起嚴(yán)重的問題,例如數(shù)據(jù)損壞泽疆、隱私漏洞等等即供。

那么一種避免此類事情發(fā)生的解決辦法就是將你刪除/注釋掉的這些字段的數(shù)值(或/并且包括字段名,因?yàn)樽侄蚊梢餔SON序列化的問題)標(biāo)記為reserved于微,如果其他人再使用這個(gè)數(shù)值作為字段標(biāo)識(shí)符逗嫡,那么編譯器就會(huì)有錯(cuò)誤提示:

注意青自,不可以把reserved數(shù)值和字段名放在同一個(gè)reserved語句里。


字段的默認(rèn)值

當(dāng)消息被解析的時(shí)候驱证,如果編碼的消息里不含有特定的一個(gè)singular元素延窜,那么在被解析對(duì)象里相應(yīng)的字段就會(huì)被設(shè)為默認(rèn)值。

常用類型的默認(rèn)值如下:

string:空字符串

bytes:空的byte數(shù)組

bool:false

數(shù)值型:0

枚舉enum:枚舉里定義的第一個(gè)枚舉值抹锄,值必須是0

repeated:通常是相應(yīng)開發(fā)語言里的空list

還有個(gè)消息類型的字段逆瑞,它的默認(rèn)值和開發(fā)語言有關(guān),這個(gè)以后再說伙单。


枚舉

之前說了获高,枚舉里面定義的第一個(gè)值就是這個(gè)枚舉的默認(rèn)值。

Enum的tag必須從0開始吻育,所以0就是枚舉的數(shù)值默認(rèn)值念秧。


繼續(xù)上個(gè)例子

我們對(duì)Person添加一個(gè)枚舉類型的字段:性別 Gender:

首先需要定義枚舉類型,這里定義了一個(gè)枚舉布疼,名稱是Gender摊趾,里面有3個(gè)值,默認(rèn)值是NOT_SPECIFIED游两,數(shù)值默認(rèn)值就是0砾层。

然后使用這個(gè)枚舉類型定義了一個(gè)字段,名稱為gender贱案,tag數(shù)為10肛炮。


為枚舉值起別名

枚舉值是可以起別名的,起別名的作用就是允許兩個(gè)枚舉值擁有同一個(gè)數(shù)值宝踪。

要想起別名侨糟,首先需要設(shè)置allow_alias這個(gè)option為true:

然后我們?yōu)镕EMALE這個(gè)枚舉值起了一個(gè)別名叫做WOMAN,它們的數(shù)值是一樣的肴沫。同樣的MAN是MALE的數(shù)值也是一樣的粟害。


枚舉里面的常量的值必須不能超過32位整型的數(shù)值蕴忆,不建議使用負(fù)數(shù)颤芬。

枚舉可以定義在message里面,也可以在外邊單獨(dú)定義以便復(fù)用套鹅。如果另一個(gè)消息想使用Person里面這個(gè)Gender枚舉站蝠,那么可以使用Person.Gender這種形式。


針對(duì)枚舉值被刪除/注釋掉這種情況卓鹿,它也可以使用reserved:

數(shù)值和常量名也必須分開使用兩個(gè)reserved語句菱魔。

其中max表示可能的最大的值。


使用其它的信息類型

可以使用其它的信息類型作為字段的類型吟孙。

我們可以在同一個(gè)proto文件里定義多個(gè)信息類型(為了截圖方便澜倦,我去掉了Person的一些字段):

在這個(gè)文件里聚蝶,除了Person信息類型外,我還定義了Date信息類型藻治。

所以碘勉,我可以在Person里面使用Date作為它的字段類型:


引入定義

如果想要使用的信息類型已經(jīng)在其它的proto文件定義好了呢?這個(gè)時(shí)候就需要引入信息類型的定義桩卵。

現(xiàn)在我把Date定義移動(dòng)到了date.proto這個(gè)文件里面:

然后在person.proto里面我們可以引用date.proto:


嵌套類型

Protocol Buffer允許在信息類型里面定義其它的信息類型验靡。

直接看例子:

如果想在Person外邊使用Address這個(gè)類型,那么就需要這樣用:Person.Address雏节。


打包

你可以向proto文件添加可選的打包(package)說明符胜嗓,以避免消息類型間的名稱沖突。

所以說打包是很必要的钩乍。

打包之后生成的C#代碼就會(huì)使用命名空間來對(duì)應(yīng)proto里面的package辞州,但是命名方式會(huì)改為Pascal Case(每個(gè)單詞首字母大寫)。

上面的代碼在C#里面的情況就是:Person類在My.Project這個(gè)命名空間下件蚕。

但是如果你在proto文件里設(shè)置了option csharp_namespace這個(gè)選項(xiàng)孙技,那么在C#里的命名空間就是該選項(xiàng)指定的命名空間了:

這時(shí)候,C#里面Perosn類的命名空間就是My.WebApis了排作,但是在proto文件里它的包還是my.project牵啦。


設(shè)置Protocol Buffers編譯器

protoc編譯器主要就是用來生成代碼的,它的下載地址目前是:https://github.com/protocolbuffers/protobuf/releases/

在里面選擇你使用的操作系統(tǒng)的版本:

下載后解壓縮到某個(gè)路徑妄痪,然后把解壓目錄下的bin目錄添加到系統(tǒng)的環(huán)境變量里哈雏。

然后打開命令行,輸入protoc衫生,如果有類似下面的東西出現(xiàn)裳瘪,說明安裝成功了:

這里面的--proto_path=PATH這個(gè)參數(shù)比較常用,它用來指定到哪個(gè)文件見來查找引入罪针。

再有就這個(gè)參數(shù)很常用:

--csharp_out=OUT_DIR用來指定存放生成的C#代碼的目錄彭羹。


我們先試驗(yàn)一下,生成Person的C#代碼:

執(zhí)行成功后就沒有任何提示泪酱,打開csharp目錄派殷,可以看到Person.cs這個(gè)文件:

而Person.cs文件里面的代碼就比較多了:

千萬不要去修改這個(gè)文件!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市墓阀,隨后出現(xiàn)的幾起案子毡惜,更是在濱河造成了極大的恐慌,老刑警劉巖斯撮,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件经伙,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡勿锅,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來网缝,“玉大人,你說我怎么就攤上這事作瞄。” “怎么了危纫?”我有些...
    開封第一講書人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵宗挥,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我种蝶,道長(zhǎng)契耿,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任螃征,我火速辦了婚禮搪桂,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘盯滚。我一直安慰自己踢械,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開白布魄藕。 她就那樣靜靜地躺著内列,像睡著了一般。 火紅的嫁衣襯著肌膚如雪背率。 梳的紋絲不亂的頭發(fā)上话瞧,一...
    開封第一講書人閱讀 51,165評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音寝姿,去河邊找鬼交排。 笑死,一個(gè)胖子當(dāng)著我的面吹牛饵筑,可吹牛的內(nèi)容都是我干的埃篓。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼根资,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼架专!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起嫂冻,我...
    開封第一講書人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤胶征,失蹤者是張志新(化名)和其女友劉穎塞椎,沒想到半個(gè)月后桨仿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡案狠,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年服傍,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了钱雷。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡吹零,死狀恐怖罩抗,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情灿椅,我是刑警寧澤套蒂,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站茫蛹,受9級(jí)特大地震影響操刀,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜婴洼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一骨坑、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧柬采,春花似錦欢唾、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至肩刃,卻和暖如春亡脸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背树酪。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工浅碾, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人续语。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓垂谢,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親疮茄。 傳聞我的和親對(duì)象是個(gè)殘疾皇子滥朱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容