本文我們來講解一下如何使用 gRPC構建微服務,gRPC是一個開源框架,可用於構建可擴充套件且高效能的微服務並建立服務之間的通訊。
背景
隨著企業越來越多地轉向微服務,對構建這些微服務的低延遲和可擴充套件框架的需求也在增加。為了滿足這一需求,各種工具和框架提供商正加快滿足微服務需求。同時從構建大型微服務應用程式的經驗中學習,技術專業人士分享他們對可重用元件的知識,以便其他人可以構建具有相同規模和效能的架構。
什麼是 gRPC
gRPC 是一個開源框架(由 Google 建立),是一個通用的 RPC 框架,用於大規模構建具有高效能的網路應用程式。實現有多種語言版本,並且支援跨平臺通訊。
使用場景
gRPC 非常適合服務與服務之間的 RPC 通訊。在這裡,我們將使用 Java 來實現微服務和相關框架,讓它的功能更齊全。為了讓其他服務可以訪問它,我們將建立一個包裝 REST 服務,這個服務將使用 gRPC 客戶端與 gRPC 服務進行通訊。
準備工作
我們需要設定一個基礎環境來構建和執行示例。基本要求是安裝 Java 和 Maven。gRPC 工具和伺服器執行時庫等其他依賴項,將在構建過程中自動下載。有關構建應用程式所需的核心依賴項,請參閱下面的程式碼。
<dependency>
<groupId>io.github.lognet</groupId>
<artifactId>grpc-spring-boot-starter</artifactId>
<version>4.5.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</dependency>
核心功能
gRPC 基本上是一種與平臺和編碼無關的協議。這意味著,您可以使用任何型別的編碼,如二進位制、JSON、XML 等,但推薦的方法是使用“protobuf”,它使用專門的序列化/反序列化機制支援二進位制編碼。可插拔設計允許使用者對其進行擴充套件以支援所需的平臺和堆疊。
protobuf 的核心構造是 proto IDL(介面定義語言),定義了訊息型別和服務定義。它還提供了為所需平臺生成模型類和服務介面的工具。
訊息型別
我們可以從在.proto檔案中定義訊息型別的 proto 定義開始。看下面的例子。
message AccountProto {
int32 accId = 1;
string accName = 2;
string accBalance = 3;
bool status = 4;
...
}
有關資料型別和關鍵字的完整參考,請參閱proto3文件。
Protobuf 提供了一種工具,可以根據適用於您的平臺/程式語言的訊息定義為模型類生成程式碼。以下命令將根據給定的訊息定義在 Java 中生成account類。
$ > protoc -I=proto-demo --java_out=proto-demo account.proto
服務定義
gRPC 服務定義是一組需要對定義的訊息型別執行的操作。這些操作可以採用以下四種通訊形式之一:
-
單通道 RPC — 它是最簡單的通訊形式。它本質上是同步的,允許使用者以阻塞模式傳送請求並等待響應,直到伺服器完成處理。
-
流式 RPC — 在這種形式中,客戶端一次性傳送資料,但伺服器以流的形式返回響應。
-
客戶端流式 RPC — 與伺服器流式傳輸不同,在這種形式中,客戶端以流的形式傳送請求的資料,伺服器將資料作為一個整體返回。
-
雙向流式 RPC — 在這種形式中,伺服器和客戶端都支援根據請求和響應流式傳輸資料。
具有標準 CRUD 操作的訊息型別的示例服務定義將採用以下輸入:
service AccountService {
rpc GetAccount (google.protobuf.Int32Value) returns (AccountProto);
rpc GetAllAccounts (google.protobuf.Empty) returns (stream AccountProto);
rpc CreateAccount (AccountProto) returns (AccountProto);
rpc UpdateAccount (AccountProto) returns (AccountProto);
rpc DeleteAccount (google.protobuf.Int32Value) returns (google.protobuf.Empty);
}
gRPC-Java 實現提供的擴充套件工具有助於根據域邏輯和伺服器存根生成使用者需要實現的服務介面,客戶端將使用這些存根呼叫已部署的服務。
$ > protoc -I=grpc-demo\src\main\proto --java_out=grpc-demo\src\main\proto account.proto
標準伺服器和客戶端
gRPC-Java 庫提供了一個響應式伺服器實現(基於 Netty)來部署您的服務和一個阻塞/非阻塞客戶端實現來連線您的服務和其他服務。
您需要註冊您的服務實現並以程式設計方式啟動伺服器。
server = ServerBuilder.forPort(port), .addService(new GreeterImpl()).build().start();
在此處找到 GitHub 參考。
要連線到部署在基於 Netty 的 gRPC 伺服器上的服務,您需要建立一個訊息通道並將其與生成的伺服器存根連線以進行呼叫。
ManagedChannel channel = ManagedChannelBuilder.forTarget(target).usePlaintext().build();
blockingStub = GreeterGrpc.newBlockingStub(channel);
HelloRequest request = HelloRequest.newBuilder().setName(name).build();
HelloReply response = blockingStub.sayHello(request);
在此處找到 GitHub 參考。
網路客戶端
還有一個 gRPC Web 模組,允許 Web 客戶端無縫訪問您的 gRPC 服務。他們的早期版本支援通過反向代理連線 Web 客戶端,但現在可以在沒有中間代理的情況下進行。
另一種方法是使用 REST/GraphQL 協議將包裝服務層暴露給面向外部的世界,並通過 gRPC 客戶端連線。
資料對映和永續性
我們可能需要在其之上新增另一層,以使用 Hibernate 等資料訪問庫建立功能齊全的域服務。與 Hibernate 或任何資料庫一樣,需要以某種方式修飾所需的實體,而這對於 protobuf 模型生成的模型可能不可行。因此,我們可能需要一些對映邏輯來將模型類轉換為實體類。一個這樣好的庫是 MapStruct,它基於 bean 約定進行自動對映。我們只需要提供對映介面:
@Mapper
public interface AccountProtoMapper {
Account map(AccountProto accountProto);
AccountProto map(Account account);
}
第三方支援
為了進一步簡化整個構建和執行環境,有一些流行的第三方 Maven 外掛和庫也有幫助。
1. 執行與 Build 整合的 Proto Tool
協議緩衝區 Maven 外掛(由 Xolstice 提供)執行 proto 工具及其擴充套件,以及從.proto檔案構建和生成原始碼。它還附加了 .proto檔案作為專案的資源。請參閱示例配置以生成 Java 程式碼。
<configuration>
<protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
</configuration>
參考可以在這裡找到。
2. 生成對映器類
MapStruct 庫支援生成訊息型別的對映器類,這些對映器類可以將訊息從/到類的實體。它提供了一個註解處理器,通過在構建時分析指定的註解來生成一個對映器類。Maven編譯外掛參考下面的配置。
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
3.自動啟動gRPC伺服器並註冊服務實現
預設情況下,gRPC 伺服器不會與 web 伺服器(在本例中為 Netty)一起啟動。此外,它需要在伺服器啟動之前註冊所有 gRPC 服務。LogNet 的 gRPC Spring Boot 會自動掃描所有帶有@GRpcService註解的類,並向伺服器構建器註冊服務定義。構建伺服器後,它會在 Spring 應用程式屬性中配置的埠上自動啟動 gRPC 伺服器。
除了註冊服務和啟動伺服器外,它還支援自動配置的安全、健康檢查和服務發現。有關詳細資訊,請參閱此處。
GitHub 上提供了上述方法的完整示例實現。
差異化
-
谷歌構建 gRPC 是出於從零開始構建大規模微服務的學習需求。大多數流行的微服務框架仍然缺乏對效能和跨平臺支援的要求,因為沒有大型系統可以在單個堆疊和單個編碼中構建。
-
最受歡迎的是對 HTTP/2 的支援,它仍然是許多提供商的路線圖。它為在單個 TCP 連線上使用多路複用非阻塞資料流的二進位制線路傳輸提供了優勢。進一步支援標頭壓縮,它提供了額外的效能優勢。
-
除了支援 protobuf 作為主要編碼機制外,它還增加了對基於 JSON 的服務的支援,這些服務可以很容易地被低端客戶端使用。雖然 protobuf 是實施 gRPC 的推薦方式,但 Google 增加了對 FlatBuffers 的支援,並增加了內部和整個行業的採用率。
-
初始版本支援通過反向代理(如基於 Envoy 和 Ngnix 的系統)公開 gRPC 服務。gRPC Web 的最新發展彌補了這一差距,並通過跨 JavaScript 庫採用 HTTP/2 增加了對向 Web 客戶端公開 gRCP 服務的支援。進一步的開發正在進行中,以增加對 Angular 和 React 等流行 Web 框架的支援。
-
藉助功能齊全的開發堆疊,它還為單元測試助手(如InProcessServer和InProcessChannelBuilder.
採用
- Google 在其內部工具和平臺上使用它,例如 Bigtable、Pub/Sub、Speech 和 TensorFlow。
- CoreOS 是 gRPC 的早期採用者,並在其服務發現工具和容器引擎中增加了支援。
- Microsoft 是 gRPC 的高階採用者,並增加了對其 Web API 和構建工具的支援,以簡化開發人員無縫構建服務的工作。
- 現在,越來越多的專案在整個行業中使用它,例如 Docker、Square、Netflix 和 Cisco 等開源開發人員。
替代方法
除了構建 gRPC 之外,Google 的應用程式還提供了文章中提到的工具/庫和 Spring Boot 啟動框架。一些專門的微服務框架為 gRPC 服務實現提供了開箱即用的支援。
- Quarkus gRPC
- Asp.NET gRPC
- Akka gRPC
- Salesforce gRPC