5分钟搭建基于 NestJS v9 的异构多主机分布式系统

545 阅读3分钟

NestJS 简介

🚀 NestJS 是一款基于 TypeScript 的后端框架,它使用面向对象和函数式编程的风格,结合了 Express 和 Angular 的特性,通过使用依赖注入、模块化和可测试性等实践,提供了一种优雅而强大的方式来构建可扩展的应用程序。

🌟它支持各种常用的 Web 应用程序开发模型,并且具有自己的模块化体系结构,使得开发过程更加简单高效。这里不得不提一下微服务架构💻,NestJS 提供的微服务模块可以说是开箱即用,简单易上手,极大地降低了入门微服务的门槛。

系统主要功能

基于 NestJS,我们用两台不同架构的设备搭建起一个分布式系统,其中树莓派作为网关,接受 HTTP 请求,并将计算请求通过 TCP 协议转发给电脑,电脑接受 TCP 请求,提供计算服务。

这样我们的用户就能通过性能较差的网关调用到分布式系统中性能卓越的计算服务。

设备清单

一台 arm64 架构的树莓派(网关),IP地址为192.168.0.6

一台高性能 amd64 或者 arm64 架构的电脑(计算),IP地址为192.168.0.3

网关

一、安装Nestjs框架和一些必要的依赖项

这里我们首先安装脚手架 nestjs/cli ,然后新建一个 gateway 项目,并安装微服务的依赖。

npm i --g @nestjs/cli
nest new gateway
cd gateway
npm i --save @nestjs/microservices

二、修改代码

在 main.ts 我们让 app 监听 8888 端口。

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(8888);
}
bootstrap();

在 app.service.ts 中,其通过 @nestjs/microservices 模块提供的 TCP 客户端将消息发送到电脑的计算服务器。在 @Client 装饰器中指定服务器的主机和端口配置连接,然后调用 this.client.send(...).pipe(...) 方法发送格式化的消息并等待回复结果。

这里的 pipe用起来非常舒服,有一种流水线处理的感觉,其实 nestjs 官方使用了 rxjs 来处理这种请求,吊打 fetch API 和 ajax 回调地狱。

import { Injectable } from '@nestjs/common';
import { Client, ClientProxy, Transport } from '@nestjs/microservices';
import { Observable, map } from 'rxjs';

@Injectable()
export class AppService {
  @Client({
    transport: Transport.TCP,
    options: {
      host: '192.168.0.3',
      port: 3000,
    }
  })
  private client: ClientProxy;

  getHello(): Observable<number> {
    const pattern = { cmd: 'sum' };
    const payload = [1, 2, 3];
    return this.client.send(pattern, payload).pipe(
      map((data) => {
        return data;
      })
    );
  }

}

三、运行

日志没有报错,表明启动成功。

计算服务

一、安装Nestjs框架和一些必要的依赖项

npm i --g @nestjs/cli
nest new math
cd math
npm i --save @nestjs/microservices

二、修改代码

首先修改 main.ts 中的代码,把我们的数学计算服务改为微服务,也就是 NestFactory.createMicroservice。

其中 options 里面我们把主机设成了 localhost,端口为3000。

import { NestFactory } from '@nestjs/core';
import { Transport, MicroserviceOptions } from '@nestjs/microservices';
import { AppModule } from './app.module';

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

然后我们修改 controller 里的方法,返回计算结果。

import { Controller, Get } from '@nestjs/common';
// import { AppService } from './app.service';
import { MessagePattern } from '@nestjs/microservices';

@Controller()
export class AppController {

  @MessagePattern({ cmd: 'sum' })
  accumulate(data: number[]): number {
    return (data || []).reduce((a, b) => a + b);
  }
}

三、运行

也可以直接运行 nest start 命令启动微服务。

测试

我们用 wget 测试接口,如果 Content 输出6说明正确调用了电脑的计算服务。

总结

总的来说,整个分布式系统实现起来非常简单,可见 NestJS 做了很多的封装方便我们开发。