Nest-js 的微服務,寫起來也太簡單了吧!

想必大家都寫過 http 服務,接受 http 請求、做一些處理、返回 http 響應。

這樣完成 web 服務器的功能沒問題,但隨着功能的越來越多,比如現在有一百多個模塊了,總不能都放在一個服務裏吧,這樣管理不方便。

於是就有了拆分的需求,也就有了微服務的概念。

拆分微服務是很自然的事情,但有個問題,微服務和 http 服務之間怎麼通信呢?

用 HTTP?

這個是可以,但是 HTTP 是文本協議,傳輸效率太低了。

所以一般都直接用 TCP 通信。

微服務架構是主流了,各種服務端開發框架都提供了微服務的支持,Nest 自然也不例外。

而且,Nest 對微服務封裝的很好,寫個微服務是特別簡單的事情。

不信我們一起來寫一個吧!

首先全局安裝 nest 的 cli 工具:

npm i -g @nestjs/cli

然後用 nest 的 cli 快速創建一個 nest 項目:

nest new xxx

選一個依賴管理工具,我這裏用的 yarn。

執行 yarn start 就可以看到跑起來的 http 服務了:

瀏覽器訪問下 http://localhost:3000

到這一步,http 服務就啓動成功了。

然後我們創建個微服務,同樣的方式,用 nest new 創建個項目:

nest new micro-service-calc

這裏要創建微服務,需要安裝一個包:

yarn add @nestjs/microservices

然後改下 main.ts:

之前創建 http 服務是這樣的:

現在要改成這樣:

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: {
        port: 8888,
      },
    },
  );
  app.listen();
}
bootstrap();

很容易理解,之前是啓 http 服務,現在是起微服務了嘛,所以啓動方式不一樣。

啓動的時候指定用 TCP 來傳輸消息,然後指定 TCP 啓動的端口爲 8888。

之後在 AppController 裏註冊下怎麼處理 TCP 的消息:

這裏用 MessagePattern 的方式來聲明處理啥消息:

import { Controller, Get } from '@nestjs/common';
import { MessagePattern } from '@nestjs/microservices';

@Controller()
export class AppController {
  constructor() {}

  @MessagePattern('sum')
  sum(numArr: Array<number>): number {
    return numArr.reduce((total, item) => total + item, 0);
  }
}

這個 sum 方法就是接受 sum 消息,返回求和的結果的 handler。

然後同樣是 yarn start 把這個微服務跑起來:

現在我們有兩個服務了:

一個 http 服務,一個 TCP 協議的微服務,然後把兩者連起來就可以了。

怎麼連起來呢?

我們來改造下 http 服務。

先安裝 @nestjs/microservices  依賴:

yarn add @nestjs/microservices

然後在 app.module.ts 裏註冊 calc 那個微服務:

調用 ClientModule.register 指定名字、傳輸方式爲 TCP、端口爲 8888。

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { ClientsModule, Transport } from '@nestjs/microservices';

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

這樣就註冊完了。

然後就可以用了,在 Controller 裏注入這個微服務的 clientProxy,也就是客戶端代理。

import { Controller, Get, Inject, Query } from '@nestjs/common';
import { ClientProxy } from '@nestjs/microservices';
import { Observable } from 'rxjs';

@Controller()
export class AppController {
  constructor(@Inject('CALC_SERVICE') private calcClient: ClientProxy) {}

  @Get()
  calc(@Query('num') str): Observable<number> {
    const numArr = str.split(',').map((item) => parseInt(item));

    return this.calcClient.send('sum', numArr);
  }
}

這樣就可以接收到 http 請求的時候調用微服務來處理了。

比如上面我們在收到請求的時候,調用代理對象的 send 方法發了一個 TCP 消息給微服務。

這也是爲啥叫做 ClientProxy 了,不用你自己發 TCP 消息,你只要調用 send 方法即可。

然後把它重新跑起來:

yarn start

然後,看:

我們 num 傳了 1,2,3,這裏返回了 6 ,這明顯就是 calc 微服務處理的。

這樣,我們第一個 Nest 微服務就跑成功了!

是不是挺簡單的?

其實微服務還有一種消息傳輸的類型,這裏我們需要響應,所以是 message 的方式,如果不需要響應,那就可以直接聲明 event 的方式。

我們再來創建個微服務,用來打印日誌。

用 nest new mirco-app-log 創建項目,然後安裝 @nestjs/microservices 包,之後像上一個微服務一樣改用 createMicroservice 的 api 啓動服務。

這個微服務起在 9999 端口。

然後 Controller 改一下:

這裏不需要響應,只是處理事件,所以不用 MessagePattern 註冊消息了,用 EventPattern。

然後在 main 項目裏註冊下:

名字叫做 LOG_SERVICE,端口 9999。

然後在 Controller 裏注入這個微服務的 clientProxy:

這樣我們在這個 http 請求的 handler 裏同時用到了兩個微服務:

用 calc 微服務來做計算,用 log 微服務來記錄日誌。

yarn start 重跑一下。

瀏覽器刷新下:

同樣返回了 6,說明 calc 微服務正常。

再去 log 微服務的控制檯看看:

log 的微服務打印了日誌,說明 log 微服務正常。

至此,Nest 微服務跑成功了!

完整 demo 代碼上傳了 github:https://github.com/QuarkGluonPlasma/nest-microservice-demo

總結

http 服務大了難免要拆分,現在都是拆成微服務的方式,http 服務負責處理 http 請求,微服務完成不同模塊的業務邏輯處理。

微服務和 http 服務之間用 TCP 通信。

用 nest 跑個微服務的步驟如下:

這就是 Nest 跑微服務的方式。

當然,現在都是本機部署的,你完全可以把微服務放到不同的服務器,甚至可以不同微服務用不同的集羣部署。

Nest 裏跑微服務以及 http 服務裏註冊微服務的方式,還是挺簡單的,這塊封裝的確實好。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/k7RXn2tObNUOmmI1ss-qKw