微服務架構攀登之路(三)之gRPC入門


一、gRPC入門

1. gRPC 簡介

⚫   gRPC 由 google 開發,是一款語言中立、平台中立、開源的遠程過程調用系統

⚫   gRPC 客戶端和服務端可以在多種環境中運行和交互,例如用 java 寫一個服務端,可以用 go 語言寫客戶端調用

2. gRPC 與 Protobuf 介紹

⚫  微服務架構中,由於每個服務對應的代碼庫是獨立運行的,無法直接調用,彼此間的通信就是個大問題

⚫  gRPC 可以實現微服務,將大的項目拆分為多個小且獨立的業務模塊,也就是服務,各服務間使用高效的 protobuf 協議進行RPC 調用,gRPC 默認使用 protocol buffers,這是 google  開源的一套成熟的結構數據序列化機制(當然也可以使用其他數據格式如JSON)

⚫  可以用 proto files 創建 gRPC 服務,用 message 類型來定義方法參數和返回類型

3. 安裝 gRPC 和 Protobuf

go get -u -v github.com/golang/protobuf/proto
go get google.golang.org/grpc(無法使用,用如下命令代替)
git clone https://github.com/grpc/grpc-go.git $GOPATH/src/google.golang.org/grpc
git clone https://github.com/golang/net.git $GOPATH/src/golang.org/x/net
git clone https://github.com/golang/text.git $GOPATH/src/golang.org/x/text
go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
git  clone https://github.com/google/go-genproto.git $GOPATH/src/google.golang.org/genproto
cd $GOPATH/src/
go install google.golang.org/grpc
go get github.com/golang/protobuf/protoc-gen-go
go build github.com/golang/protobuf/protoc-gen-go 
上面安裝好后,會在GOPATH/bin 下生成 protoc-gen-go.exe
但還需要一個 protoc.exe,windows 平台編譯受限,很難自己手動編譯,直接去網站下載一個,地址:https://github.com/protocolbuffers/protobuf/releases/tag/v3.9.0  ,同樣放到GOPATH/bin 下

  二、Protobuf語法

1. 基本規范

⚫ 文件以.proto 做為文件后綴,除結構定義外的語句以分號結尾

⚫ 結構定義可以包含:message、service、enum

⚫ rpc 方法定義結尾的分號可有可無

⚫ Message 命名采用駝峰命名方式,字段命名采用小寫字母加下划線分隔方式

message SongServerRequest { 
    required string song_name = 1;
}

⚫ Enums 類型名采用駝峰命名方式,字段命名采用大寫字母加下划線分隔方式

⚫ Service 與 rpc 方法名統一采用駝峰式命名

enum Foo {
    FIRST_VALUE = 1;
    SECOND_VALUE = 2;
}

2. 字段規則

⚫ 字段格式:限定修飾符 |  數據類型 |  字段名稱 | = |  字段編碼值 | [字段默認值]

⚫ 限定修飾符包含 required\optional\repeated

◼ Required:  表示是一個必須字段,必須相對於發送方,在發送消息之前必須設置該字段的值,對於接收方,必須能夠識別該字段的意思。發送之前沒有設置

required 字段或者無法識別 required 字段都會引發編解碼異常,導致消息被丟棄

◼ Optional:表示是一個可選字段,可選對於發送方,在發送消息時,可以有選擇性的設置或者不設置該字段的值。對於接收方,如果能夠識別可選字段就進行相應的處理,如果無法識別,則忽略該字段,消息中的其它字段正常處理。

---因為 optional 字段的特性,很多接口在升級版本中都把后來添加的字段都統一的設置為 optional 字段,這樣老的版本無需升級程序也可以正常的與新的軟件進行通信,只不過新的字段無法識別而已,因為並不是每個節點都需要新的功能,因此可以做到按需升級和平滑過渡

◼ Repeated:表示該字段可以包含 0~N 個元素。其特性和 optional 一樣,但是每一次可以包含多個值。可以看作是在傳遞一個數組的值

⚫ 數據類型

◼ Protobuf  定義了一套基本數據類型。幾乎都可以映射到 C++\Java 等語言的基礎數據類型


◼  N  表示打包的字節並不是固定。而是根據數據的大小或者長度

◼  關於 fixed32 和 int32 的區別。fixed32 的打包效率比 int32 的效率高,但是使用的空間一般比 int32 多。因此一個屬於時間效率高,一個屬於空間效率高

⚫ 字段名稱

◼ 字段名稱的命名與 C、C++、Java 等語言的變量命名方式幾乎是相同的

◼ protobuf 建議字段的命名采用以下划線分割的駝峰式。例如 first_name  而不是firstName

⚫ 字段編碼值

◼ 有了該值,通信雙方才能互相識別對方的字段,相同的編碼值,其限定修飾符和數據類型必須相同,編碼值的取值范圍為 1~2^32(4294967296)

◼ 其中 1~15 的編碼時間和空間效率都是最高的,編碼值越大,其編碼的時間和空間效率就越低,所以建議把經常要傳遞的值把其字段編碼設置為 1-15 之間的值

◼ 1900~2000 編碼值為 Google protobuf 系統內部保留值,建議不要在自己的項目中使用

⚫ 字段默認值

◼ 當在傳遞數據時,對於 required 數據類型,如果用戶沒有設置值,則使用默認值傳遞到對端

3. service 如何定義

⚫  如果想要將消息類型用在 RPC 系統中,可以在.proto 文件中定義一個 RPC 服務接口,protocol buffer 編譯器會根據所選擇的不同語言生成服務接口代碼

⚫  例如,想要定義一個 RPC 服務並具有一個方法,該方法接收 SearchRequest 並返回一個 SearchResponse,此時可以在.proto 文件中進行如下定義:

service SearchService {
    rpc Search (SearchRequest) returns (SearchResponse) {}
}

⚫    生成的接口代碼作為客戶端與服務端的約定,服務端必須實現定義的所有接口方法,客戶端直接調用同名方法向服務端發起請求,比較麻煩的是,即便業務上不需要參數也必須指定一個請求消息,一般會定義一個空message

4. Message 如何定義

⚫  一個 message 類型定義描述了一個請求或響應的消息格式,可以包含多種類型字段

⚫  例如定義一個搜索請求的消息格式,每個請求包含查詢字符串、頁碼、每頁數目

⚫ 字段名用小寫,轉為 go 文件后自動變為大寫,message 就相當於結構體       

syntax = "proto3";

message SearchRequest {
    string query = 1;	// 查詢字符串
    int32    page_number = 2;	//  頁碼
    int32    result_per_page = 3;	//  每頁條數
}

⚫ 首行聲明使用的 protobuf 版本為 proto3

⚫ SearchRequest  定義了三個字段,每個字段聲明以分號結尾,.proto 文件支持雙斜線 //  添加單行注釋

5. 添加更多 Message 類型

⚫  一個.proto 文件中可以定義多個消息類型,一般用於同時定義多個相關的消息,例如在同一個.proto 文件中同時定義搜索請求和響應消息

syntax = "proto3";

// SearchRequest  搜索請求
message SearchRequest {
    string query = 1;	// 查詢字符串
    int32    page_number = 2;	//  頁碼
    int32    result_per_page = 3;	//  每頁條數
} 
// SearchResponse  搜索響應
message SearchResponse {
...
}

6. 如何使用其他 Message

⚫   message 支持嵌套使用,作為另一 message 中的字段類型

message SearchResponse { 
    repeated Result results = 1;
}

message Result { 
    string url = 1; 
    string title = 2;
}

7. Message 嵌套的使用

⚫  支持嵌套消息,消息可以包含另一個消息作為其字段。也可以在消息內定義一個新的消息

⚫  內部聲明的 message 類型名稱只可在內部直接使用

message SearchResponse { 
    message Result {
    string url = 1; string title = 2;
    repeated string snippets = 3;
    }
    repeated Result results = 1;
}

⚫    另外,還可以多層嵌套

message Outer {
    message MiddleAA { 
        message Inner {
            int64 ival = 1; 
            bool  booly = 2;
    }
}
message MiddleBB { 
    message Inner {
        int32 ival = 1;
        bool	booly = 2;
        }
    }
}

8. proto3 的 Map 類型

⚫  proto3 支持 map 類型聲明

map<key_type, value_type> map_field = N;

message Project {...}

map<string, Project> projects = 1;

⚫ 鍵、值類型可以是內置的類型,也可以是自定義 message 類型

⚫ 字段不支持repeated 屬性

9. .proto 文件編譯

⚫ 通過定義好的.proto 文件生成Java, Python, C++, Go, Ruby, JavaNano, Objective-C, or C#  代碼,需要安裝編譯器 protoc

⚫ 當使用 protocol buffer 編譯器運行.proto 文件時,編譯器將生成所選語言的代碼,用於使用在.proto 文件中定義的消息類型、服務接口約定等。不同語言生成的代碼格式不同:

◼ C++: 每個.proto 文件生成一個.h 文件和一個.cc 文件,每個消息類型對應一個類

◼ Java:   生成一個.java  文件,同樣每個消息對應一個類,同時還有一個特殊的

Builder 類用於創建消息接口

◼ Python: 姿勢不太一樣,每個.proto 文件中的消息類型生成一個含有靜態描述符的模塊,該模塊與一個元類 metaclass 在運行時創建需要的 Python 數據訪問類

◼ Go:  生成一個.pb.go 文件,每個消息類型對應一個結構體

◼ Ruby:  生成一個.rb 文件的 Ruby 模塊,包含所有消息類型

◼ JavaNano: 類似 Java,但不包含 Builder 類

◼ Objective-C: 每個.proto 文件生成一個 pbobjc.h 和一個 pbobjc.m 文件

◼ C#:  生成.cs 文件包含,每個消息類型對應一個類

10. import 導入定義

⚫ 可以使用 import 語句導入使用其它描述文件中聲明的類型

⚫ protobuf  接口文件可以像 C 語言的 h 文件一個,分離為多個,在需要的時候通過import 導入需要對文件。其行為和 C 語言的#include 或者 java 的 import 的行為大致相同,例如 import "others.proto";

⚫  protocol buffer 編譯器會在 -I / --proto_path 參數指定的目錄中查找導入的文件,如果沒有指定該參數,默認在當前目錄中查找

11.包的使用

⚫ 在.proto 文件中使用 package 聲明包名,避免命名沖突        

syntax = "proto3"; 
package foo.bar;
message Open {...}

⚫ 在其他的消息格式定義中可以使用包名+消息名的方式來使用類型,如

message Foo {
...
foo.bar.Open open = 1;
...
}

⚫ 在不同的語言中,包名定義對編譯后生成的代碼的影響不同

◼ C++ 中:對應 C++命名空間,例如 Open 會在命名空間 foo::bar 中

◼ Java  中:package 會作為 Java 包名,除非指定了 option jave_package 選項

◼ Python  中:package 被忽略

◼ Go 中:默認使用 package 名作為包名,除非指定了 option go_package 選項

◼ JavaNano  中:同 Java

◼ C#  中:package  會轉換為駝峰式命名空間,如 Foo.Bar,除非指定了 option csharp_namespace 選項 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM