gRPC是由Google公司開源的高性能RPC框架。python
gRPC支持多語言web
gRPC原生使用C、Java、Go進行了三種實現,而C語言實現的版本進行封裝後又支持C++、C#、Node、ObjC、 Python、Ruby、PHP等開發語言服務器
gRPC支持多平臺架構
支持的平臺包括:Linux、Android、iOS、MacOS、Windows框架
gRPC的消息協議使用Google自家開源的Protocol Buffers協議機制(proto3) 序列化ide
gRPC的傳輸使用HTTP/2標準,支持雙向流和鏈接多路複用性能
C語言實現的gRPC支持多語言,其架構以下ui
安裝編碼
pip install grpc
install grpcio-tools pip
使用url
.proto
爲後綴名)中。
Protocol Buffers 是一種與語言無關,平臺無關的可擴展機制,用於序列化結構化數據。使用Protocol Buffers 能夠一次定義結構化的數據,而後可使用特殊生成的源代碼輕鬆地在各類數據流中使用各類語言編寫和讀取結構化數據。
如今有許多框架等在使用Protocol Buffers。gRPC也是基於Protocol Buffers。 Protocol Buffers 目前有2和3兩個版本號。
在gRPC中推薦使用proto3版本。
Protocol Buffers文檔的第一行非註釋行,爲版本申明,不填寫的話默認爲版本2。
syntax = "proto3"; 或者 syntax = "proto2";
Protocol Buffers 能夠聲明package,來防止命名衝突。 Packages是可選的。
package foo.bar; message Open { ... }
使用的時候,也要加上命名空間,
message Foo { ... foo.bar.Open open = 1; ... }
注意:對於Python而言,package
會被忽略處理,由於Python中的包是以文件目錄來定義的。
Protocol Buffers 中能夠導入其它文件消息等,與Python的import相似。
import 「myproject/other_protos.proto」;
消息messge是用來定義數據的,服務service是用來gRPC的方法的。
Protocol Buffers 提供如下兩種註釋方式。
// 單行註釋 /* 多行註釋 多行註釋 */
.proto | 說明 | Python |
---|---|---|
double | float | |
float | float | |
int32 | 使用變長編碼,對負數編碼效率低, 若是你的變量多是負數,可使用sint32 | int |
int64 | 使用變長編碼,對負數編碼效率低,若是你的變量多是負數,可使用sint64 | int/long |
uint32 | 使用變長編碼 | int/long |
uint64 | 使用變長編碼 | int/long |
sint32 | 使用變長編碼,帶符號的int類型,對負數編碼比int32高效 | int |
sint64 | 使用變長編碼,帶符號的int類型,對負數編碼比int64高效 | int/long |
fixed32 | 4字節編碼, 若是變量常常大於2^{28} 的話,會比uint32高效 | int |
fixed64 | 8字節編碼, 若是變量常常大於2^{56} 的話,會比uint64高效 | int/long |
sfixed32 | 4字節編碼 | int |
sfixed64 | 8字節編碼 | int/long |
bool | bool | |
string | 必須包含utf-8編碼或者7-bit ASCII text | str |
bytes | 任意的字節序列 | str |
在 Proto Buffers 中,咱們能夠定義枚舉和枚舉類型,
enum Corpus { UNIVERSAL = 0; WEB = 1; IMAGES = 2; LOCAL = 3; NEWS = 4; PRODUCTS = 5; VIDEO = 6; } Corpus corpus = 4;
枚舉定義在一個消息內部或消息外部都是能夠的,若是枚舉是 定義在 message 內部,而其餘 message 又想使用,那麼能夠經過 MessageType.EnumType 的方式引用。
定義枚舉的時候,咱們要保證第一個枚舉值必須是0,枚舉值不能重複,除非使用 option allow_alias = true 選項來開啓別名。
enum EnumAllowingAlias { option allow_alias = true; UNKNOWN = 0; STARTED = 1; RUNNING = 1; }
枚舉值的範圍是32-bit integer,但由於枚舉值使用變長編碼,因此不推薦使用負數做爲枚舉值,由於這會帶來效率問題。
Protocol Buffers使用message定義消息數據。在Protocol Buffers中使用的數據都是經過message消息數據封裝基本類型數據或其餘消息數據,對應Python中的類。
message SearchRequest { string query = 1; int32 page_number = 2; int32 result_per_page = 3; }
消息定義中的每一個字段都有惟一的編號。這些字段編號用於以消息二進制格式標識字段,而且在使用消息類型後不該更改。 請注意,1到15範圍內的字段編號須要一個字節進行編碼,包括字段編號和字段類型。16到2047範圍內的字段編號佔用兩個字節。所以,您應該爲很是頻繁出現的消息元素保留數字1到15。請記住爲未來可能添加的經常使用元素留出一些空間。
最小的標識號能夠從1開始,最大到2^29 - 1,或 536,870,911。不可使用其中的[19000-19999]的標識號, Protobuf協議實現中對這些進行了預留。若是非要在.proto文件中使用這些預留標識號,編譯時就會報警。一樣你也不能使用早期保留的標識號。
消息字段能夠是如下之一:
singular:格式良好的消息能夠包含該字段中的零個或一個(但不超過一個)。
repeated:此字段能夠在格式良好的消息中重複任意次數(包括零)。將保留重複值的順序。對應Python的列表。
message Result { string url = 1; string title = 2; repeated string snippets = 3; }
能夠在單個.proto文件中定義多個消息類型。
message SearchRequest { string query = 1; int32 page_number = 2; int32 result_per_page = 3; } message SearchResponse { ... }
保留變量不被使用
若是經過徹底刪除字段或將其註釋來更新消息類型,則將來用戶能夠在對類型進行本身的更新時重用字段編號。若是之後加載相同的舊版本,這可能會致使嚴重問題,包括數據損壞,隱私錯誤等。確保不會發生這種狀況的一種方法是指定已刪除字段的字段編號(或名稱)reserved。若是未來的任何用戶嘗試使用這些字段標識符,protobuf編譯器將會報錯。
message Foo { reserved 2, 15, 9 to 11; reserved "foo", "bar"; }
解析消息時,若是編碼消息不包含特定的單數元素,則解析對象中的相應字段將設置爲該字段的默認值。這些默認值是特定於類型的:
你能夠在其餘消息類型中定義、使用消息類型,在下面的例子中,Result消息就定義在SearchResponse消息內,如:
message SearchResponse { message Result { string url = 1; string title = 2; repeated string snippets = 3; } repeated Result results = 1; }
若是要在其父消息類型以外重用此消息類型,使用
SearchResponse.Result
若是要在數據定義中建立關聯映射,Protocol Buffers提供了一種方便的語法:
map< key_type, value_type> map_field = N ;
其中key_type能夠是任何整數或字符串類型。請注意,枚舉不是有效的key_type。value_type能夠是除map映射類型外的任何類型。
例如,若是要建立項目映射,其中每條Project消息都與字符串鍵相關聯,則能夠像下面這樣定義它:
map<string, Project> projects = 3 ;
若是你的消息中有不少可選字段, 而且同時至多一個字段會被設置, 你能夠增強這個行爲,使用oneof特性節省內存。
爲了在.proto定義oneof字段, 你須要在名字前面加上oneof關鍵字, 好比下面例子的test_oneof:
message SampleMessage { oneof test_oneof { string name = 4; SubMessage sub_message = 9; } }
而後你能夠增長oneof字段到 oneof 定義中. 你能夠增長任意類型的字段, 可是不能使用repeated 關鍵字。
Protocol Buffers使用service定義RPC服務。
示例:
message HelloRequest { string greeting = 1; } message HelloResponse { string reply = 1; } service HelloService { rpc SayHello (HelloRequest) returns (HelloResponse) {} } syntax = "proto3"; message UserRequest { string user_id=1; int32 channel_id=2; int32 article_num=3; int64 time_stamp=4; } message Track { string click=1; string collect=2; string share=3; string read=4; } message Article { int64 article_id=1; Track track=2; } message ArticleResponse { string exposure=1; int64 time_stamp=2; repeated Article recommends=3; } service UserRecommend { rpc user_recommend(UserRequest) returns(ArticleResponse) {} }
編譯生成代碼
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. reco.proto
-I
表示搜索proto文件中被導入文件的目錄--python_out
表示保存生成Python文件的目錄,生成的文件中包含接口定義中的數據類型--grpc_python_out
表示保存生成Python文件的目錄,生成的文件中包含接口定義中的服務類型在toutiao-backend/common/rpc目錄下執行上述命令,會自動生成以下兩個rpc調用輔助代碼模塊: