gRPC 及其在微服務通訊中的角色

gRPC(gRPC遠程過程調用)是由Google開發的一個現代、開源、高性能的RPC(遠程過程調用)框架。它旨在促進分布式系統之間的高效通信,特別適用於微服務架構。以下是關於gRPC及其在微服務通信中的作用的解釋:

什麼是gRPC?

gRPC是一種協議,可以使客戶端和服務器應用程序透明通信,更容易構建分布式系統。它使用HTTP/2作為傳輸協議,Protocol Buffers(Protobuf)作為接口定義語言(IDL),並提供身份驗證、負載平衡等功能。

以下是gRPC的一些特點:

  1. 與語言無關。gRPC支持多種編程語言,包括Java、Python、Go、C++等。
  2. 高效通信。它使用Protobuf進行二進制序列化,比基於文本的格式如JSON更快更節省空間。
  3. 基於HTTP/2。gRPC利用HTTP/2,實現多路徑傳輸、流式傳輸、降低延遲等功能。
  4. 強類型。服務和消息使用Protobuf定義,確保類型安全性並減少錯誤。
  5. 流式支持。 gRPC支持四種類型的流式傳輸:一元、伺服器流、客戶端流和雙向流。

gRPC的運作方式

1. 定義服務和消息

使用Protobuf,您可以定義服務接口(方法)和要交換的消息結構。

ProtoBuf

 

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloResponse);
}

message HelloRequest {
  string name = 1;
}

message HelloResponse {
  string message = 1;
}

2. 生成程式碼

Protobuf編譯器(protoc)會根據您選擇的編程語言生成客戶端和伺服器端的程式碼。

ProtoBuf

 

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloResponse);
}

message HelloRequest {
  string name = 1;
}

message HelloResponse {
  string message = 1;
}

3. 實現伺服器

為定義的服務實現伺服器端邏輯。

4. 建立客戶端

使用生成的客戶端程式碼調用伺服器方法。

gRPC在微服務通信中的作用

微服務架構涉及將應用程序拆分為更小、獨立的服務,這些服務通過網絡通信。由於其效率和靈活性,gRPC在此背景下發揮著至關重要的作用。

1. 高性能

  • gRPC使用Protobuf的二進制序列化,比基於文本的格式如JSON或XML更快速更緊湊。
  • HTTP/2通過啟用多路複用和標頭壓縮減少延遲時間並提高吞吐量。

2. 嚴格的契約定義

  • Protobuf強制執行服務之間的嚴格契約,降低通信錯誤的可能性。
  • 通過版本控制管理服務定義的更改,確保向後兼容性。

3. 流媒體功能

  • gRPC支持雙向流式傳輸,非常適合實時通信,如聊天應用或實時數據傳輸。
  • 服務端和客戶端流式傳輸可有效處理大型數據集或連續數據流。

4. 互通性

  • gRPC是與語言無關的,允許不同語言編寫的微服務無縫通信。
  • 這在混合微服務環境中特別有用。

5. 內建功能

  • gRPC提供內建支持身份驗證、加密(通過TLS)和負載平衡等功能,減少對其他庫或工具的需求。

6. 可擴展性

  • gRPC的輕量級特性和高效通信使其適用於大型規模的微服務部署。
  • 它與容器編排平台(如Kubernetes)很好地集成。

gRPC在微服務中的應用案例

  1. 服務間通信。gRPC非常適合在性能關鍵場景下的微服務間通信。
  2. 實時系統。其流媒體功能使其適用於遊戲、物聯網或實時分析等實時應用程式。
  3. 混合語言環境。當微服務使用不同語言編寫時,gRPC確保無縫通信。
  4. 雲原生應用程式。gRPC與Kubernetes和服務網格(例如Istio)等雲原生技術很好地集成。

gRPC 的優點

  • 效率。二進制序列化和HTTP/2使gRPC更快且更節省資源。
  • 類型安全。Protobuf確保強類型,減少運行時錯誤。
  • 跨語言支持。支援多種程式語言。
  • 流式處理。支援進階的流式處理模式,用於即時通訊。

gRPC 的挑戰

  • 複雜性。設置gRPC可能比REST更複雜,因為需要Protobuf定義和代碼生成。
  • 工具支援。相較於REST,調試和測試gRPC服務可能更困難,因為諸如Postman之類的工具並非為gRPC原生設計。
  • 瀏覽器支援。瀏覽器不原生支援gRPC,需要像gRPC-Web這樣的工具用於基於Web的客戶端。

為何使用 Spring Boot 搭配 gRPC?

Spring Boot 是一個用於構建Java應用程式的流行框架,將其與gRPC結合可讓開發人員創建高效、可擴展和互操作的服務。借助Spring Boot的自動配置和依賴注入,整合gRPC變得簡單明了。

構建應用程式的步驟

我們將構建一個名為Greeter的簡單gRPC服務,允許客戶端向服務器發送名稱並收到“Hello, {name}!”的回應。以下是我們的做法:

  1. 使用 Protocol Buffers 定義 gRPC 服務。
  2. .proto 檔案生成 Java 類別。
  3. 在 Spring Boot 中實現 gRPC 伺服器。
  4. 在 Spring Boot 中實現 gRPC 客戶端。
  5. 添加一個 REST 控制器以調用 gRPC 客戶端進行測試。
  6. 運行應用程式並測試通訊。

1. 定義 gRPC 服務(.proto 檔案)

第一步是使用 Protocol Buffers 定義 gRPC 服務。在 src/main/proto 目錄中創建一個名為 greeter.proto 的檔案:

ProtoBuf

 

syntax = "proto3";

option java_multiple_files = true;
option java_package = "com.example.grpc";
option java_outer_classname = "GreeterProto";
service Greeter {
  rpc SayHello (HelloRequest) returns (HelloResponse);
}
message HelloRequest {
  string name = 1;
}
message HelloResponse {
  string message = 1;
}

此檔案定義:

  • 具有 SayHello RPC 方法的 Greeter 服務。
  • 包含一個 name 欄位的 HelloRequest 訊息。
  • 包含一個 message 欄位的 HelloResponse 訊息。

2. 添加相依性

要在 Spring Boot 中使用 gRPC,請將以下相依性添加到您的 pom.xml 中:

XML

 

<dependencies>
    <!-- Spring Boot Starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
<!-- Spring Boot Web for REST Controller -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- gRPC dependencies -->
    <dependency>
        <groupId>net.devh</groupId>
        <artifactId>grpc-spring-boot-starter</artifactId>
        <version>2.14.0.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>io.grpc</groupId>
        <artifactId>grpc-netty-shaded</artifactId>
        <version>1.54.0</version>
    </dependency>
    <dependency>
        <groupId>io.grpc</groupId>
        <artifactId>grpc-protobuf</artifactId>
        <version>1.54.0</version>
    </dependency>
    <dependency>
        <groupId>io.grpc</groupId>
        <artifactId>grpc-stub</artifactId>
        <version>1.54.0</version>
    </dependency>
    <!-- Protobuf Java Format -->
    <dependency>
        <groupId>com.google.protobuf</groupId>
        <artifactId>protobuf-java</artifactId>
        <version>3.22.2</version>
    </dependency>
</dependencies>
<build>
    <plugins>
        <!-- Protobuf Compiler Plugin -->
        <plugin>
            <groupId>org.xolstice.maven.plugins</groupId>
            <artifactId>protobuf-maven-plugin</artifactId>
            <version>0.6.1</version>
            <configuration>
                <protocArtifact>com.google.protobuf:protoc:3.22.2:exe:${os.detected.classifier}</protocArtifact>
                <pluginId>grpc-java</pluginId>
                <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.54.0:exe:${os.detected.classifier}</pluginArtifact>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                        <goal>compile-custom</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

這些相依性包括:

  • Spring Boot Starter 用於基本應用程式設置。
  • Spring Boot Web 用於 REST 控制器支援。
  • 用於伺服器和客戶端實現的 gRPC 函式庫。
  • 用於序列化和反序列化的 Protobuf。

3. 生成 Java 類別

運行以下 Maven 命令從 .proto 檔案生成 Java 類別:

Plain Text

 

mvn clean compile

這將在 target/generated-sources 目錄中生成 GreeterGrpc 和相關類。

4. 實現 gRPC 伺服器

接下來,在 Spring Boot 中實現 gRPC 伺服器。創建一個名為 GreeterService 的類:

Java

 

package com.example.grpc.server;

import com.example.grpc.GreeterGrpc;
import com.example.grpc.GreeterProto.HelloRequest;
import com.example.grpc.GreeterProto.HelloResponse;
import io.grpc.stub.StreamObserver;
import net.devh.boot.grpc.server.service.GrpcService;
@GrpcService
public class GreeterService extends GreeterGrpc.GreeterImplBase {
    @Override
    public void sayHello(HelloRequest request, StreamObserver responseObserver) {
        String name = request.getName();
        String message = "Hello, " + name + "!";
        HelloResponse response = HelloResponse.newBuilder().setMessage(message).build();
        // 發送回應
        responseObserver.onNext(response);
        responseObserver.onCompleted();
    }
}

此類擴展生成的 GreeterGrpc.GreeterImplBase 並實現 sayHello 方法以處理傳入請求。

5. 實現 gRPC 客戶端

現在,在 Spring Boot 中實現 gRPC 客戶端。創建一個名為 GreeterClient 的類:

Java

 

package com.example.grpc.client;
import com.example.grpc.GreeterGrpc;
import com.example.grpc.GreeterProto.HelloRequest;
import com.example.grpc.GreeterProto.HelloResponse;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import org.springframework.stereotype.Service;
@Service
public class GreeterClient {
    private final GreeterGrpc.GreeterBlockingStub blockingStub;
    public GreeterClient() {
        ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 9090)
                .usePlaintext()
                .build();
        this.blockingStub = GreeterGrpc.newBlockingStub(channel);
    }
    public String sayHello(String name) {
        HelloRequest request = HelloRequest.newBuilder().setName(name).build();
        HelloResponse response = blockingStub.sayHello(request);
        return response.getMessage();
    }
}

此客戶端連接到 gRPC 伺服器並向 SayHello 方法發送請求。

6. 添加用於測試的 REST 控制器

為了更容易測試 gRPC 客戶端,我們將添加一個 REST 控制器來公開一個端點以調用 GreeterClient。創建一個名為 GreeterController 的類:

Java

 

package com.example.grpc.controller;
import com.example.grpc.client.GreeterClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GreeterController {

    private final GreeterClient greeterClient;

    @Autowired
    public GreeterController(GreeterClient greeterClient) {
        this.greeterClient = greeterClient;
    }

    @GetMapping("/greet")
    public String greet(@RequestParam String name) {
        return greeterClient.sayHello(name);
    }
}

此控制器公開一個 /greet 端點,接受一個 name 參數並返回來自 gRPC 伺服器的回應。

7. 創建 Spring Boot 應用程式

最後,創建一個 Spring Boot 應用程式來運行伺服器和客戶端:

Java

 

package com.example.grpc;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class GrpcApplication {
    public static void main(String[] args) {
        SpringApplication.run(GrpcApplication.class, args);
    }
}

8. 配置伺服器端口

將以下配置添加到 application.properties 中:

Plain Text

 

# gRPC 伺服器端口
grpc.server.port=9090

# Spring Boot 伺服器端口
server.port=8080

9. 運行應用程式

  1. 啟動 Spring Boot 應用程式。
  2. gRPC 伺服器將在端口 9090 上啟動。
  3. REST 控制器將在端口 8080 上提供。

您可以通過向 /greet 端點發送 GET 請求來測試應用程序:

Plain Text

 

curl http://localhost:8080/greet?name=World

響應將是:

Plain Text

 

"Hello, World!"

為 Spring Boot 選擇正確的 gRPC 库

在構建需要 gRPC 整合的 Spring Boot 應用程序時,開發人員通常需要在幾個庫之間進行選擇。最常討論的選項是 net.devh.grpcorg.lognet.grpcorg.springframework.grpc

這些庫各自具有自己的優勢、劣勢和使用案例。讓我們探索這些庫之間的區別、它們的功能以及您應該為您的項目使用哪一個。

1. net.devh.grpc(grpc-spring-boot-starter)

net.devh.grpc,也被稱為 grpc-spring-boot-starter,是一個廣泛使用的庫,用於將 gRPC 與 Spring Boot 集成。它受到積極維護,並為在 Spring Boot 應用程序中構建 gRPC 伺服器和客戶端提供了一套強大的功能。

主要功能

  • 自動配置。簡化了 gRPC 伺服器和客戶端的設置。
  • Spring 整合。支持依賴注入和其他 Spring 功能。
  • Spring 安全。輕鬆與 Spring Security 集成以進行安全通信。
  • 健康檢查。通過 Spring Boot Actuator 提供健康檢查。
  • 同步和異步通信。支持這兩種通信方式。

為什麼使用它?

  • 積極維護。該庫正在積極維護和更新。
  • 全面文檔。有大型社區支持的詳細文檔。
  • 適用於生產環境。在生產環境中被廣泛使用。

什麼時候使用它?

  • 如果您正在構建一個新的Spring Boot應用程序,並且需要可靠的、功能豐富的gRPC集成。
  • 如果您想要與Spring Boot的功能(如依賴注入、安全性和健康檢查)無縫集成。

2. org.lognet.grpc(grpc-spring-boot-starter)

org.lognet.grpc是另一個用於將gRPC與Spring Boot集成的庫。然而,與后者相比,它的維護活動較少,並且缺少一些高級功能。

主要功能

  • 基本gRPC設置。為gRPC服務器和客戶端提供基本支持。
  • Spring Boot集成。與Spring Boot合作,但功能較少。

為什麼使用它?

  • 歷史使用。它是早期用於gRPC和Spring Boot集成的庫之一。
  • 簡單易用。適用於簡單的用例。

什麼時候使用它?

  • 如果您正在為已經使用此庫的舊項目工作。
  • 由於維護有限且功能較少,不建議用於新項目。

3. org.springframework.grpc(Spring gRPC)

org.springframework.grpc 是一個實驗性或由社區驅動的努力,旨在將 gRPC 整合到 Spring 中。這不是官方的 Spring 項目,可能不像 net.devh.grpc 那樣成熟或功能豐富。

主要功能

  • 基本的 gRPC 整合。為 gRPC 服務器和客戶端提供基本支持。
  • 與 Spring 生態系統的對齊。設計與 Spring 生態系統密切對齊。

為什麼使用它?

  • 實驗性用途。適合進行實驗或為該項目做出貢獻。
  • Spring 對齊。如果您更喜歡使用與 Spring 緊密對齊的東西。

何時使用它?

  • 僅當您在探索或為該項目做出貢獻時。
  • 由於其實驗性質,不建議用於生產環境。

應該使用哪個?

對於新項目

使用 net.devh.grpc(grpc-spring-boot-starter)。這是與 Spring Boot 整合 gRPC 的最成熟、積極維護和功能豐富的選項。其與 Spring Boot 功能的無縫整合使其成為新項目的最佳選擇。

對於現有項目

如果您已經在使用org.lognet.grpc,請考慮遷移到net.devh.grpc以獲得更好的支持和功能。雖然org.lognet.grpc可能適用於舊項目,但缺乏net.devh.grpc的積極維護和高級功能。

用於實驗用途

如果您正在探索或參與Spring gRPC集成,可以考慮使用org.springframework.grpc。但由於其實驗性質,不建議用於生產環境。

關鍵考慮因素

  • 社區支持net.devh.grpc擁有更大的社區和更好的文檔,使之更容易尋找幫助和資源。
  • 生產就緒性net.devh.grpc在生產環境中被廣泛使用,被認為是穩定可靠的。
  • 使用便捷性net.devh.grpc提供自動配置和與Spring Boot的無縫集成,降低了設置的複雜性。

結論

gRPC是一個強大的微服務通信工具,提供高性能、強類型和諸如流式處理等高級功能。儘管與REST相比,它需要更多的初始設置,但其效率和可擴展性使其成為現代分佈式系統的優秀選擇。

隨著微服務架構變得越來越複雜,gRPC 在促進服務之間無縫通信方面扮演著越來越重要的角色。在本文中,我們使用 Spring Boot 3 構建了一個簡單的 gRPC 客戶端和服務器應用程序,使用 Protocol Buffers 定義了一個 gRPC 服務,生成了 Java 類,實現了服務器和客戶端,並添加了一個 REST 控制器,以便進行輕鬆測試。這個示例展示了使用 gRPC 構建高性能、可擴展和互操作的服務的功能和簡單性。您可以通過更複雜的服務、流式傳輸或錯誤處理進一步擴展它。祝您編碼愉快!

GitHub 存儲庫: grpc-client-and-server-with-spring-boot

Source:
https://dzone.com/articles/understanding-grpc-and-its-role-in-microservices-c