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 new 創建一個 main 服務,一個微服務
-
都要安裝 @nestjs/microservices 包,因爲用到其中的 api
-
微服務裏用 createMicroservice 啓動服務,選擇傳輸方式爲 TCP,指定端口
-
微服務裏在 Controller 使用 MessagePattern 或者 EventPattern 註冊處理消息的 handler
-
main 服務使用 ClientsModule.register 來註冊微服務
-
main 服務裏注入 ClientProxy 對象,調用它的 send 方法給微服務發消息
這就是 Nest 跑微服務的方式。
當然,現在都是本機部署的,你完全可以把微服務放到不同的服務器,甚至可以不同微服務用不同的集羣部署。
Nest 裏跑微服務以及 http 服務裏註冊微服務的方式,還是挺簡單的,這塊封裝的確實好。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/k7RXn2tObNUOmmI1ss-qKw