想象一下,你回家过节,你的家人决定聚会。而不是让一个人做所有的烹饪,每个人都同意带上他们擅长制作的特色菜。目标是通过组合所有这些菜肴来制作一顿完整的饭菜。你同意做鸡肉炒饭,你哥哥做甜点蛋糕,妹妹做沙拉。
每个菜代表一个具有特定功能或用途的微服务。例如,炒饭代表一道丰盛的主菜;沙拉代表新鲜健康的配菜,蛋糕代表甜蜜甜点。在微服务架构中,开发人员可以独立于其他微服务开发、部署和维护每个微服务,确保每个微服务保持独立和独立。
就像家庭聚会上的每道菜都代表具有不同功能或目的的微服务一样,软件系统中的每个微服务都必须与其他微服务进行有效的通信,以形成功能齐全的应用程序。类似于每道菜都需要与其他菜肴协调以创建美味佳肴一样,随着微服务数量的增加,微服务之间的通信变得越来越重要。我们可以确保微服务可以无缝运行,通过使用高效的通信框架(如 gRPC)来构建持久且可缩放的系统。
在本文中,我们将了解 gRPC(一种高性能的开源远程过程调用框架)如何允许 NestJS 应用程序中的微服务进行通信。我们将介绍使用 gRPC 的优势,如何在 NestJS 应用程序中执行此操作,并举例说明微服务如何使用它进行通信。
目录
- 先决条件
- 微服务及其通信方式
- 微服务通信的挑战
- 微服务中的通信模式
- gRPC 概述
- 微服务中的 gRPC vs REST vs SOAP
- 在 NestJS 中使用 gRPC
- 使用 gRPC 进行微服务通信的好处
- 结论
先决条件
让我们首先介绍一下我们需要的先决条件和工具:
- Node.js 与 NPM – 运行和处理我们应用程序的依赖项。
- NestJS CLI – 用于构建、管理和运行 NestJS 应用程序。
- 协议缓冲区 – 在 gRPC 中定义消息和服务。
- gRPC – 允许 NestJS 应用程序中的微服务相互通信。
- grpcurl – 允许您测试简单的微服务通信。
微服务及其通信方式
微服务以多种方式相互通信。由于微服务架构中的每个微服务都执行特定的功能或任务,因此需要通信以确保完整的应用程序正常运行。由于每个微服务的独立性,微服务架构使开发人员能够创建更灵活、可扩展和容错的应用程序。此外,微服务的模块化设计使其成为复杂应用程序的理想选择,因为不同的系统组件可能有不同的需求和要求。
微服务通信的挑战
微服务通常通过定义明确的 API 和协议相互通信,使每个微服务都能可靠、高效地进行通信。但是,微服务间通信可能有点挑战性和棘手性。当许多微服务相互通信时,开发人员可能会遇到几个问题,包括:
- 延迟:由于通信和数据传输效率低下而导致的网络拥塞。
- 安全性:潜在的漏洞和威胁可能是由于访问控制管理不善或没有必要的安全协议造成的。
- 服务发现:随着系统中服务数量的增加,管理和查找适当的服务变得困难。更糟糕的是,拥有硬编码的端点可能会导致系统变脆。
- 容错:由于多个服务相互交互,任何服务故障都可能对整个系统产生涟漪效应。
总体而言,微服务之间的通信可能具有挑战性且复杂。开发人员可以通过在设计系统时考虑以下因素来创建高度可扩展、容错和弹性的微服务体系结构:
- 沟通在心。
- 高效的通信协议。
- 适当的安全协议。
- 用于动态定位服务并与之通信的服务发现机制。
微服务中的通信模式
微服务使用各种通信模式相互通信。我们将研究其中的一些:发布-订阅、请求-响应、事件驱动体系结构和消息队列。
- 发布-订阅模式:涉及一对多通信,其中它将消息发布到多个订阅者。例如,一家公司向其各种时事通讯订阅者发送电子邮件。
- 请求-响应模式:一个服务向另一个服务发送请求,接收方服务发回响应。例如,当 API 收到请求并发回请求的数据或错误消息作为响应时。
- 消息队列模式:在此模式中,消息被发送到队列并存储,直到服务可用于处理它们。例如,送货公司可以使用此模式来接收和组织客户交货请求,并根据其位置分配可用的司机。
- 事件驱动架构:在此模式中,服务在事件发生时交换消息。例如,当用户从其移动银行应用汇款时,帐户更新服务会收到扣除金额的通知。
gRPC 概述
gRPC 是由 Google 开发的高性能开源远程过程调用 (RPC) 框架。它使客户端应用程序能够调用位于远程计算机上的服务器应用程序上的方法,其方式与在本地对象上调用方法一样容易。它通过在客户端和服务器应用程序之间提供高效且独立于语言的通信,简化了构建和扩展分布式应用程序的过程。
微服务中的 gRPC vs REST vs SOAP
微服务体系结构中使用的通信协议包括 gRPC、REST 和 SOAP。以下是它们之间的一些主要区别:
- 语言支持:REST 和 SOAP 通常用于基于 Web 的编程语言,而 gRPC 支持多种编程语言,包括 C++、Java、Python 等。
- 性能:由于 gRPC 使用二进制序列化、压缩数据格式和双向流式处理,因此它比 REST 和 SOAP 更快、更有效。因此,客户端和服务器应用程序可以实时通信。
- 数据格式:REST 和 SOAP 使用 XML 或 JSON,而 gRPC 使用 Protocol Buffers,这是一种二进制序列化标准。
- 强类型和服务协定:为了建立服务协定,gRPC 使用协议缓冲区,该缓冲区提供强类型并有助于服务版本控制和维护。REST 和 SOAP 在其服务契约中使用表达力较低且灵活的 WSDL 或 OpenAPI 定义。
- 可伸缩性:gRPC 是微服务体系结构的绝佳选择,因为它是为处理大规模分布式系统而构建的,并具有开箱即用的负载平衡和运行状况检查等功能。
在 NestJS 中使用 gRPC
在本节中,您将学习如何创建一个简单的 NestJS 微服务,该服务使用 gRPC 返回“Hello, World!”:
首先,你需要安装 NestJS CLI 和 gRPC 工具:
npm install -g @nestjs/cli
npm install @nestjs/microservices @grpc/grpc-js
你需要使用 CLI 创建一个新的 NestJS 项目:
nest new hello-world-demo
此示例中的项目名称为“hello-world-demo”。
现在,导航到项目文件夹:
cd hello-world-demo
接下来,您需要创建一个新的模块和服务。服务是为应用程序提供特定类型功能的类,而模块是相关服务、控制器和提供程序集合的容器。通过这样做,你基本上是在向你的NestJS应用程序添加一个新的可管理,可测试的功能层。这有助于将来添加其他功能,并有利于应用程序的常规体系结构和可维护性。
nest g module hello
nest g service hello
然后,您需要使用以下代码更新 hello-world-demo/src/hello/hello.service.ts
文件:
import { Injectable } from '@nestjs/common';
import { GrpcMethod } from '@nestjs/microservices';
@Injectable()
export class HelloService {
@GrpcMethod('HelloService', 'SayHello')
sayHello(data: any): { message: string } {
return { message: 'Hello, World!' };
}
}
此服务文件包含一个标记为可注入提供程序的 HelloService 类。 @GrpcMethod
修饰器用于将 sayHello
方法标记为 gRPC 方法,该方法返回“Hello, World!”消息。总的来说,此代码演示了如何使用 NestJS 创建基本的 gRPC 服务。
更新 hello-world-demo/src/app.module.ts
文件以包含 HelloService
和 使用 gRPC:
import { Module } from '@nestjs/common';
import { ClientsModule, Transport } from '@nestjs/microservices';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { HelloService } from './hello/hello.service';
@Module({
imports: [
ClientsModule.register([
{
name: 'HELLO_PACKAGE',
transport: Transport.GRPC,
options: {
url: 'localhost:5000',
package: 'hello',
protoPath: './hello.proto',
},
},
]),
],
controllers: [AppController],
providers: [AppService, HelloService],
})
export class AppModule {}
它具有用于 HelloService 提供程序类、HTTP 控制器和 AppService HelloService 提供程序类的 gRPC 客户端。用于 ClientsModule 使用提供的选项注册 gRPC 客户端,例如描述服务的原型文件的路径、gRPC 服务器的 URL 以及包的名称。在 providers 应用程序中管理业务逻辑的 AppService and HelloService 类包含在字段中。管理 AppController 传入 HTTP 请求的类是该 controllers 属性的成员。
创建一个新文件 hello-world-demo/hello.proto
并添加以下代码:
syntax = "proto3";
package hello;o
service HelloService {
rpc SayHello (HelloRequest) returns (HelloResponse);
}
message HelloRequest {
string name = 1;
}
message HelloResponse {
string message = 1;
}
原型文件用于定义 gRPC 服务的结构和接口。它是一个概述服务的过程以及参数的输入和输出数据格式的文件。gRPC 框架使用用协议缓冲区语言编写的原型文件在 NestJs 中生成客户端和服务器代码。
最后,更新 hello-world-demo/src/main.ts
文件以启动 gRPC 微服务:
import { NestFactory } from '@nestjs/core';
import { Transport } from '@nestjs/microservices';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.createMicroservice(AppModule, {
transport: Transport.GRPC,
options: {
url: 'localhost:5000',
package: 'hello',
protoPath: './hello.proto',
},
});
await app.listen();
}
bootstrap();
现在,启动 gRPC 微服务:
npm run start
服务器启动后,它将侦听指定 URL 和端口(在本例中为 5000)上的传入 gRPC 请求。然后,可以从 gRPC 客户端(例如 Web 前端、移动应用或其他微服务)向服务器发送请求。对于我们一直在处理的“Hello World”示例,您可以通过使用 grpcurl 命令行工具发送请求来测试服务器。若要测试微服务,可以使用 grpcurl,这是一个用于与 gRPC 服务交互的命令行工具:
grpcurl -plaintext -d '{"name": "John"}' localhost:5000 hello.HelloService/SayHello
这应返回以下响应:
{
"message": "Hello, World!"
}
就是这样!您已经创建了一个使用 gRPC 返回“Hello, World!”的 NestJS 微服务,并且您已经使用 grpcurl 对其进行了测试。当然,在实际应用程序中,微服务可能具有更复杂的功能,而不是简单地返回“Hello, World!”来响应单个请求。但是,启动服务器、侦听传入请求以及根据业务逻辑处理这些请求的基本过程将是相同的。
使用 gRPC 进行微服务通信的好处
使用 NestJS 和 gRPC 进行微服务通信可以产生更快、更可靠、更具可扩展性的系统。以下是一些好处:
- 强类型协定:gRPC 提供的 API 是强类型,它使用协议缓冲区来构造服务协定。换句话说,服务器和客户端都可以确保它们发送和接收的消息遵循特定的架构。
- 自动代码生成:NestJS提供的工具使得从gRPC服务定义文件(.proto)自动生成TypeScript代码变得简单,这使得将微服务与NestJS集成变得简单。
- 互操作性:通过允许 NestJS 和 gRPC 与其他使用不同通信协议的服务一起运行,使它们更容易与 HTTP/REST 等其他协议一起运行。
- 易用性:NestJS提供了一个易于理解的API来定义gRPC服务,使构建和管理微服务变得简单。
结论
微服务架构正在成为设计复杂且可扩展的应用程序的一种更流行的方式。它通过将应用程序分解为独立和专用的组件来提供灵活性和可扩展性。但是,此设计的有效性取决于微服务之间的有效通信。这就是高性能远程过程调用 (RPC) 框架 gRPC 发挥作用的地方。
在本文中,我们探讨了在 NestJS 中使用 gRPC 进行微服务通信的好处。我们讨论了微服务通信中涉及的挑战,包括延迟、安全性、服务发现和容错。我们还探讨了 gRPC 如何帮助开发人员克服这些挑战并构建可缩放的容错微服务体系结构。此外,我们还将 gRPC 与其他通信协议(如 REST 和 SOAP)进行了比较,重点介绍了其语言支持、性能、数据格式和服务协定优势。
此外,我们在 NestJS 中使用 gRPC 构建了一个简单的“hello world”服务,以演示 Nest 应用程序中的服务如何使用 gRPC 进行有效通信。
最后,我们讨论了在 NestJS 中使用 gRPC 进行微服务通信的好处,包括强类型协定、自动代码生成、互操作性和易用性。
总之,开发人员可以使用 gRPC 的性能和类型安全以及 NestJS 的简单性,构建具有有效通信通道的可扩展且可维护的微服务,从而产生更健壮、更可靠的系统。