Nest 微服务

原帖

项目大了以后会难以维护和扩展时,这时候可以通过微服务的方式把业务逻辑拆分到不同的微服务里。微服务之间通过<font style="color:rgb(37, 41, 51);"> tcp </font>方式通信,在 nest 里需要用到 <font style="color:rgb(37, 41, 51);">@nestjs/microservices</font> 这个包。

Start

微服务启动的时候不再调用 NestFactory.create 而是调用 <font style="color:rgb(37, 41, 51);">NestFactory.createMicroservice</font> 方法,指定 tcp 的端口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { NestFactory } from "@nestjs/core";
import { AppModule } from "./app.module";
import { Transport, MicroserviceOptions } from "@nestjs/microservices";

async function bootstrap() {
const app = await NestFactory.createMicroservice<MicroserviceOptions>(
AppModule,
{
transport: Transport.TCP,
options: { port: 8888 },
}
);
app.listen();
}
bootstrap();

然后另一个服务(可以为 http 服务也可以是另一个微服务)里通过 <font style="color:rgb(37, 41, 51);">ClientsModule</font> 来注入连接这个微服务的代理对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { Module } from "@nestjs/common";
import { AppController } from "./app.controller";
import { AppService } from "./app.service";
import { ClientsModule, Transport } from "@nestjs/microservices";

@Module({
imports: [
ClientsModule.register([
{
name: "USER_SERVICE",
transport: Transport.TCP,
options: {
port: 8888,
},
},
]),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}

之后分别用 <font style="color:rgb(37, 41, 51);">send</font> 调用微服务的 <font style="color:rgb(37, 41, 51);">@MessagePattern</font> 用于声明要处理的消息的方法。而<font style="color:rgb(37, 41, 51);">emit</font> 方法来调用微服务的 <font style="color:rgb(37, 41, 51);">@EventPattern</font> 声明的不需要返回消息的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//-------- 微服务 --------
@MessagePattern('sum')
sum(numArr: Array<number>): number {
return numArr.reduce((total, item) => total + item, 0);
}

@EventPattern('log')
log(str: string) {
console.log(str);
}

//-------- 调用微服务 --------
@Get('sum')
calc(@Query('num') str) {
const numArr = str.split(',').map((item) => parseInt(item));
return this.userClient.send('sum', numArr);
}

@Get('log/:str')
log(@Param('str') str) {
console.log('[str]===>', str);
this.userClient.emit('log', str);
}

可通过 wireshark 抓包分析了 tcp 通信的内容,发现微服务之间的通信是基于 json 的。

Monorepo 与 Library

nest cli 支持 monorepo,只要执行 <font style="color:rgb(37, 41, 51);">nest g app xxx</font> 就会把项目变为 monorepo 的,在 apps 下保存多个 nest 应用。

nest-cli.json 里配置了多个 projects 的信息,以及默认的 project

npm run start:dev 或者 npm run build 可以加上应用名来编译对应的 app。

此外,多个项目可能有公共代码,这时候可以用 <font style="color:rgb(37, 41, 51);">nest g lib xxx</font> 创建 library

library 保存在 libs 目录下,和 apps 一样可以有多个。

nest 会为 libs 创建别名,可以在其他 app 或者 lib 里用别名引入。

Etcd 实现微服务配置中心和注册中心

微服务架构的系统中少不了<font style="color:rgb(37, 41, 51);">配置中心</font><font style="color:rgb(37, 41, 51);">注册中心</font>

不同服务的配置需要统一管理,并且在更新后通知所有的服务,所以需要配置中心。

微服务的节点可能动态的增加或者删除,依赖他的服务在调用之前需要知道有哪些实例可用,所以需要注册中心。

redis 没法监听不存在的 key 的变化,而 etcd 可以,而配置信息很多都是动态添加的。

服务启动的时候注册到注册中心,并定时续租期,调用别的服务的时候,可以查一下有哪些服务实例可用,也就是服务注册、服务发现功能

注册中心和配置中心可以用 etcd 来做,它就是一个专业做这件事的中间件,k8s 就是用的它来做的配置和服务注册中心。

我们用 docker 跑了 etcd server,它内置了命令行工具 <font style="color:rgb(37, 41, 51);">etcdctl</font> 可以用来和 server 交互。

常用的命令有 <font style="color:rgb(37, 41, 51);">put、get、del、watch</font> 等。

在 node 里可以通过 etcd3 这个包来操作 etcd server。

稍微封装一下就可以实现配置管理和服务注册、发现的功能。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!