如何基于gRPC溝通微服務框架
本文我們來講解一下如何使用 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