解密gRPC:Protocol Buffer
在之前的文章中,我們?nèi)娼榻B了gRPC,在這一部分中,我們將涵蓋Protocol Buffer,也稱為Protobuf。
Protobuf標(biāo)志
“Protocol Buffers”這個名字有著獨(dú)特的起源。
在早期,它指的是一個名為“ProtocolBuffer”的類,充當(dāng)了單個方法調(diào)用的緩沖區(qū)。用戶可以向此緩沖區(qū)添加標(biāo)簽/值對,原始字節(jié)會存儲在其中,直到構(gòu)建消息后被寫出。盡管名稱中的“buffers”部分失去了原始含義,但它一直存在。今天,我們通常使用“協(xié)議消息”來指代抽象意義上的消息,“協(xié)議緩沖區(qū)”來指代序列化消息,以及“協(xié)議消息對象”來指代解析后的內(nèi)存表示。
什么是Protocol Buffers?
Protocol Buffers是一種簡單的語言中立和平臺中立的接口定義語言(IDL),用于定義數(shù)據(jù)結(jié)構(gòu)模式和編程接口。它支持二進(jìn)制和文本線路格式,并可以與不同平臺上的許多不同線路協(xié)議一起工作。例如,看看這個簡單的proto文件(person.proto),定義了一個名為'Person'的消息。這個消息描述了一個人的屬性,包括名字,ID和可選的電子郵件地址。message Person { required string name = 1; required int32 id = 2; optional string email = 3; } 這個person.proto文件用作服務(wù)器和客戶端之間的契約。如果您想要更改這個“Person”實(shí)體的結(jié)構(gòu),或者更改請求和響應(yīng)的外觀,您需要修改proto文件。Protobuf編譯器protoc由Google維護(hù),盡管也有可選的實(shí)現(xiàn)。生成的代碼經(jīng)過優(yōu)化,以實(shí)現(xiàn)數(shù)據(jù)的快速序列化和反序列化。
為什么選擇Protocol Buffers(Protobuf)而不是JSON?
Proto vs JSON
你可能會想,既然已經(jīng)有廣泛使用的序列化格式JSON,為什么要選擇Protocol Buffers(Protobuf)呢?
讓我們深入探討Protobuf為什么是一個出色的選擇,以及它在解決常見數(shù)據(jù)序列化挑戰(zhàn)方面與JSON相比的情況:
在總結(jié)一下,Protobuf和JSON各有各自的獨(dú)特優(yōu)勢,Protobuf在需要效率、跨平臺兼容性和結(jié)構(gòu)化數(shù)據(jù)至關(guān)重要的情況下表現(xiàn)出色。
另一方面,當(dāng)您需要可讀性強(qiáng)的數(shù)據(jù)或輕量級格式的簡單性更合適時,JSON仍然是一個很好的選擇。
Protobuf語法
這個快速介紹為您提供了Protobuf的語法和核心概念的味道。如果您想進(jìn)一步探索,我鼓勵您查看官方Protocol Buffers文檔。
1.消息:數(shù)據(jù)藍(lán)圖
將Protobuf消息視為數(shù)據(jù)結(jié)構(gòu)的藍(lán)圖。它們告訴您數(shù)據(jù)應(yīng)該如何組織。
message Recipe {
string dish_name = 1;
repeated string ingredients = 2;
double preparation_time_minutes = 3;
}
在這個例子中,我們創(chuàng)建了一個名為Recipe的消息,其中包含三個字段:dish_name表示菜名,ingredients表示配料列表(可以有多個),preparation_time_minutes表示制作這道菜所需的時間。每個字段都有一個唯一的編號(例如,1,2,3),用于組織。
2.字段類型
Protobuf支持各種字段類型,如字符串、整數(shù)、浮點(diǎn)數(shù)、枚舉等等。您甚至可以嵌套消息以創(chuàng)建復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。這些字段類型確保數(shù)據(jù)結(jié)構(gòu)良好,類型正確。
3.字段標(biāo)簽
消息中的字段可以具有標(biāo)簽,確定它們是required、optional還是repeated(用于列表):
- Required字段:這些字段必須始終出現(xiàn)在此類型的消息中。如果在序列化消息時缺少一個必需字段,將導(dǎo)致錯誤。
- Optional字段:它們可以包含在消息中,但不是必需的。如果在序列化消息時省略了可選字段,它將被視為具有默認(rèn)值。
- Repeated字段:重復(fù)字段允許在單個字段中具有相同類型的多個值。它們用于數(shù)據(jù)的列表或數(shù)組。
4.枚舉
枚舉允許您定義一組命名的常量值。當(dāng)您有一個字段具有預(yù)定義選項集,例如一周的日期或產(chǎn)品類別時,它非常有用。
enum DayOfWeek {
MONDAY = 1;
TUESDAY = 2;
// ...
}
5.注釋
您可以在Protobuf定義中包含注釋,以更好地解釋您的消息和字段。注釋可以以//開始,也可以包裝在/* ... */中。
6.語法版本:規(guī)則和特性
Protobuf提供不同的語法版本,其中proto2和`proto3`是最常見的。這些版本定義了您可以在Protobuf定義中使用的規(guī)則和特性。
注意:建議gRPC API使用Protocol Buffers版本3(proto3)來定義API
7.導(dǎo)入其他文件:保持組織
對于更大的項目,您可以將Protobuf定義分成多個文件,并使用import語句將它們組合在一起。
序列化和反序列化
Protobuf的線路格式是二進(jìn)制編碼,因此處理起來更快。它使用一些巧妙的技巧來最小化用于表示消息的字節(jié)數(shù)。不需要了解二進(jìn)制編碼格式的知識來使用Protobuf。
為了真正理解Protocol Buffers(Protobuf)的威力,讓我們通過一個示例,演示數(shù)據(jù)是如何序列化和編碼,以及隨后如何解碼回來的。
考慮以下數(shù)據(jù):
(我們使用前面定義的person.proto)
{
"name": "Ankit",
"id": 21,
"email": "username@gmail.com"
}
1.序列化和編碼
Protobuf將此JSON數(shù)據(jù)轉(zhuǎn)換為一個既高效又節(jié)省空間的二進(jìn)制格式。在這種情況下,Protobuf編碼如下:
0a 05 41 6e 6b 69 74 10 15 1a 12 75 73 65 72 6e 61 6d 65 40 67 6d 61 69 6c 2e 63 6f 6d
2.解碼
現(xiàn)在,讓我們顛倒這個過程,將這個Protobuf數(shù)據(jù)解碼回其原始形式:
這個解碼過程使Protobuf如此高效和強(qiáng)大。它確保數(shù)據(jù)保持一致和結(jié)構(gòu)化,即使在編碼和解碼后,這使得它成為各種場景中數(shù)據(jù)傳輸?shù)氖走x選擇。
這只是一個簡單的示例,如果您有興趣,可以在Protocol Buffers網(wǎng)站上了解更多信息。
gRPC中的Protocol Buffers
Protocol Buffers(Protobuf)在gRPC中至關(guān)重要,為客戶端和服務(wù)器之間提供了高效和一致的通信。以下是它們至關(guān)重要的原因:
- API契約定義:Protobuf為gRPC定義了消息結(jié)構(gòu),確保了高效和無錯誤的數(shù)據(jù)傳輸。
- 高效的序列化:Protobuf的二進(jìn)制格式加速了數(shù)據(jù)序列化和反序列化,提高了gRPC的性能。
- 語言中立性:Protobuf的語言不可知性使其能夠無縫集成到各種編程語言中。
- 高效性:Protobuf的二進(jìn)制格式減少了網(wǎng)絡(luò)使用,使數(shù)據(jù)傳輸更快。
- 互操作性:Protobuf充當(dāng)通用翻譯器,使gRPC服務(wù)能夠在不同語言和平臺之間輕松通信。
- 向后兼容性:Protobuf的版本支持允許API演進(jìn)而不破壞現(xiàn)有客戶端。
- 代碼生成:Protobuf簡化了消息結(jié)構(gòu)代碼生成,簡化了開發(fā)流程。
- 性能:Protobuf的高效序列化和反序列化增強(qiáng)了gRPC服務(wù)的整體性能。
讓我們包括一個使用Protocol Buffers(Protobuf)定義的gRPC服務(wù)的示例。假設(shè)我們正在構(gòu)建一個帶有用戶身份驗證的聊天應(yīng)用程序。
這是我們服務(wù)的Protobuf定義:
syntax = "proto3";
message User {
string id = 1;
string username = 2;
}
message Message {
string id = 1;
string text = 2;
User sender = 3;
}
service ChatService {
rpc SendMessage(Message) returns (Message);
rpc GetMessages(User) returns (stream Message);
}
在這個示例中,我們定義了兩種消息類型,User和Message,以及一個允許發(fā)送和接收消息的ChatService。使用Protobuf,這個服務(wù)定義清晰、簡潔,并且可以輕松地生成成各種編程語言的代碼。
總之,Protocol Buffers(Protobuf)已經(jīng)徹底改變了數(shù)據(jù)序列化、傳輸和在不同系統(tǒng)中的理解方式。它們的效率、跨平臺兼容性和結(jié)構(gòu)化數(shù)據(jù)處理使它們成為現(xiàn)代應(yīng)用程序的強(qiáng)大選擇。
通過了解Protobuf的語法、核心概念以及它在gRPC中的作用,您可以充分利用它的功能。在探索Protobuf的世界時,請記住官方Protocol Buffers文檔是深入了解這項技術(shù)的綜合指南。