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服务,允许客户端向服务器发送姓名并接收“你好,{姓名}!”的响应。以下是我们的做法:

  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,是一个广泛使用的库,用于在 Spring Boot 应用程序中集成 gRPC。它得到积极维护,并提供了一套强大的功能,用于在 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)。这是最成熟、积极维护和功能丰富的用于将gRPC与Spring Boot集成的选择。其与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