「这是我参与2022首次更文挑战的第13天,活动详情查看:2022首次更文挑战」
介绍
微服务架构是Nest.js支持的功能之一,通过将功能分解到各个离散的服务中以实现对解决方案的解耦。这篇文章通过一个例子来为大家展示创建微服务架构的步骤。
开始
首先我们创建一个nestjs-microservices文件夹,在文件夹里创建三个应用
$ mkdir nestjs-microservices && cd nestjs-microservices
$ npm install -g @nestjs/cli
$ nest new users
$ nest new profiles
$ nest new bff
然后分别为这三个应用安装微服务模块 npm i @nestjs/microservices --save
我们现在需要开发一个获取用户的接口,获取到的数据包含用户id、用户名和用户其他属性,而用户id和用户名会放在项目users中,而用户属性会存放在项目profiles中,bff项目用来存放主接口,当我们请求接口的时候会在bff中获取用户列表和用户属性列表,然后根据用户id进行合并,返回给用户。
微服务
Nest 内置了几种不同的微服务传输层实现,默认是 TCP 协议,我们今天选择REDIS作为消息中转
项目users和profiles 是我们的两个微服务,我们打开这两个项目的main.ts
// users/src/main.ts 和 profiles/src/main.ts
import { NestFactory } from '@nestjs/core';
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.createMicroservice<MicroserviceOptions>(
AppModule,
{
transport: Transport.REDIS,
options: {
url: 'redis://localhost:6379',
},
},
);
app.listen(() => console.log('Services started'));
}
bootstrap();
接下来我们分别为users和profiles 添加逻辑代码。先修改users的app.controller.ts
// users/src/app.controller.ts
import { Controller } from '@nestjs/common';
import { MessagePattern } from '@nestjs/microservices';
import { Profile } from './app.interface';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@MessagePattern({ cmd: 'get_profiles' })
getProfiles(): Profile[] {
return this.appService.getProfiles();
}
}
/users/src/app.service.ts
// users/src/app.service.ts
import { Injectable } from '@nestjs/common';
import { User } from './app.interface';
@Injectable()
export class AppService {
users = [
{ id: '1', name: '张三' },
{ id: '2', name: '李四' },
];
getUsers(): User[] {
return this.users;
}
}
然后打开profiles的app.controller.ts
// profiles/src/app.controller.ts
import { Controller } from '@nestjs/common';
import { MessagePattern } from '@nestjs/microservices';
import { Profile } from './app.interface';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@MessagePattern({ cmd: 'get_profiles' })
getProfiles(): Profile[] {
return this.appService.getProfiles();
}
}
/profiles/src/app.service.ts
// profiles/src/app.service.ts
import { Injectable } from '@nestjs/common';
import { Profile } from './app.interface';
@Injectable()
export class AppService {
profiles = [
{ id: '1', hobby: '打游戏', age: 21 },
{ id: '2', hobby: '听音乐', age: 18 },
];
getProfiles(): Profile[] {
return this.profiles;
}
}
这样我们就完成了微服务的修改,接下来我们修改bbf的项目 /bff/src/app.controller.ts
import { Controller, Get, Inject } from '@nestjs/common';
import { ClientProxy } from '@nestjs/microservices';
import { Account, Profile, User } from './app.interface';
@Controller()
export class AppController {
constructor(
@Inject('PUBSUB')
private readonly client: ClientProxy,
) {}
@Get('accounts')
async getAccounts(): Promise<Account[]> {
const users = await this.client
.send<User[]>({ cmd: 'get_users' }, { page: 1, items: 10 })
.toPromise();
const profiles = await this.client
.send<Profile[]>({ cmd: 'get_profiles' }, { ids: users.map((u) => u.id) })
.toPromise();
return users.map<Account>((u) => ({
...u,
...profiles.find((p) => p.id === u.id),
}));
}
}
我们在这里面的操作是,利用ClientProxy的send的方法与其他两个微服务通信,获取到各自的数据,然后把它们根据 id 进行合并,返回我们完整的用户数据。
接下来最后一步我们需要在 /bff/src/app.module.ts 里面进行注册和注入token PUBSUB 这个需要和其他两个应用一致。
import { Module } from '@nestjs/common';
import { ClientsModule, Transport } from '@nestjs/microservices';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [
ClientsModule.register([
{
name: 'PUBSUB',
transport: Transport.REDIS,
options: {
url: 'redis://localhost:6379',
},
},
]),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
这样就完成了一个最简单的微服务架构
测试
全部的应用都启动后,我们通过 postMan 调用接口 http://localhost:3000/accounts
可以看到,我们已经获取到了合并后的完整数据。