本文咱们来解说一下如何应用 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