banner
SlhwSR

SlhwSR

热爱技术的一名全栈开发者
github
bilibili

Nest基於Fastify實現微服務架構

我司最近很多 javaer 的各種微服務需要前端來一個一個調用,這樣做豈不是很繁瑣?

先說說為什麼要做微服務:
結合微服務架構,不僅能夠提升系統的可擴展性和可靠性,同時也能促進團隊的高效協作與快速迭代,從而更好地應對複雜業務場景。

這樣做可以結合他們的服務結合自己的業務緊密配合~

直接 po 代碼:

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import {
  FastifyAdapter,
  NestFastifyApplication,
} from '@nestjs/platform-fastify';
import { HkAuthMiddleware } from './hk-auth/hk-auth.middleware';
import { HttpService } from '@nestjs/axios';
import fastifyMultipart from '@fastify/multipart';
import cluster from 'cluster';
import * as os from 'os';
import { Transport, MicroserviceOptions } from '@nestjs/microservices';

async function bootstrap() {
  // 創建 Fastify HTTP 應用
  const app = await NestFactory.create<NestFastifyApplication>(
    AppModule,
    new FastifyAdapter(),
  );

  // 註冊微服務連接
  app.connectMicroservice<MicroserviceOptions>({
    transport: Transport.TCP,
    options: {
      host: process.env.SCREENSHOT_SERVICE_HOST || 'localhost',
      port: parseInt(process.env.SCREENSHOT_SERVICE_PORT || '4000'),
      retryAttempts: 5, // 重試次數
      retryDelay: 3000, // 重試延遲(毫秒)
    },
  });

  // 啟動微服務連接
  await app.startAllMicroservices();

  // 保持現有的配置
  const httpService = new HttpService();
  const authMiddleware = new HkAuthMiddleware(httpService);
  app.setGlobalPrefix(`/api`);
  await app.register(fastifyMultipart, {
    limits: {
      fileSize: 200 * 1024 * 1024,
    },
  });
  app.use((req, res, next) => authMiddleware.use(req, res, next));
  await app.enableCors();
  
  // 啟動 HTTP 服務
  await app.listen(3000, '0.0.0.0');
}

// 保持現有的集群模式
if (cluster.isPrimary) {
  const cpuCount = os.cpus().length;
  console.log(`主進程啟動,準備 fork ${cpuCount} 個工作進程`);
  for (let i = 0; i < cpuCount; i++) {
    cluster.fork();
  }
  cluster.on('exit', (worker) => {
    console.log(`工作進程 ${worker.process.pid} 退出,重啟中...`);
    cluster.fork();
  });
} else {
  bootstrap();
}

這裡解釋一下註冊微服務,你可以簡單的理解為,你自己開了一家店鋪,別人可以來你店裡採購你的各種service

那麼 host 就代表你伺服器的 Ip、port 及你開啟微服務的端口。

這樣即可將應用轉化為微服務應用~每個工作進程都會同時支持 HTTP 和微服務通信

在服務層建立 tcp 通訊#

這樣,我們就可以在服務層去連接其他 javer 的微服務,比如,我們需要把某一個截圖功能處理的 base64 存入 redis 或者調用 java 服務。

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

@Injectable()
export class ScreenshotClient {
  private client: ClientProxy;

  constructor() {
    this.client = new ClientProxy({
      transport: Transport.TCP,
      options: {
        host: process.env.SCREENSHOT_SERVICE_HOST || 'localhost',
        port: parseInt(process.env.SCREENSHOT_SERVICE_PORT || '4000'),
      },
    });
  }

  async generateScreenshot(groups: any) {
    try {
      const result = await firstValueFrom(
        this.client.send({ cmd: 'generate_screenshot' }, groups)
      );
      
      if (!result.success) {
        throw new Error(result.error);
      }
      
      return result.data;
    } catch (error) {
      throw new Error(`截圖生成失敗: ${error.message}`);
    }
  }
}

client 代表你連接 ip+port 的服務,

send 則表示你發送給對方微服務的消息命令。

如:send ({cmd: 'some_command'}, data)。即可。

當然了,你可以同時在一個服務裡調用不同的微服務。

@Injectable()
export class SomeService {
  private redisClient: ClientProxy;
  private rabbitClient: ClientProxy;

  constructor() {
    // Redis 微服務客戶端
    this.redisClient = new ClientProxy({
      transport: Transport.REDIS,
      options: {
        host: '192.168.1.111',
        port: 6379,
      },
    });

    // RabbitMQ 微服務客戶端
    this.rabbitClient = new ClientProxy({
      transport: Transport.RMQ,
      options: {
        urls: ['amqp://192.168.1.222:5672'],
        queue: 'my_queue',
      },
    });
  }
}

開放自己的微服務#

比如 javer 對於一個業務需要多次 dto-oto, 那麼可以經過我們的服務再做處理:

import { Controller } from '@nestjs/common';
import { MessagePattern } from '@nestjs/microservices';
import { ScreenshotService } from './screen-shot.service';

@Controller()
export class ScreenshotController {
  constructor(private readonly screenshotService: ScreenshotService) {}

  // 這是一個微服務端點
  @MessagePattern({ cmd: 'generate_screenshot' })
  async generateScreenshot(data: any) {
    try {
      const result = await this.screenshotService.compositeAllGroups(data);
      return {
        success: true,
        data: result
      };
    } catch (error) {
      return {
        success: false,
        error: error.message
      };
    }
  }

  // 這是原來的 HTTP 端點,保持不變
  @Post()
  async httpGenerateScreenshot(@Body() data: any) {
    // ... 原有的 HTTP 處理邏輯
  }
}

end----

下期出普羅米修斯 + granafa 集成可視化性能監控。

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。