【Nest】初探Nest+微服务+gRPC

文章主要介绍Nest微服务是什么?如何运行?以及搭配gRPC使用栗子。

微服务简介

微服务是一种开发软件的架构和组织方法,其中软件由通过明确定义的 API 进行通信的小型独立服务组成。

特性

  • 自主性

可以对微服务架构中的每个组件服务进行开发、部署、运营和扩展,而不影响其他服务的功能。这些服务不需要与其他服务共享任何代码或实施。各个组件之间的任何通信都是通过明确定义的 API 进行的。

  • 专用性

每项服务都是针对一组功能而设计的,并专注于解决特定的问题。如果开发人员逐渐将更多代码增加到一项服务中并且这项服务变得复杂,那么可以将其拆分成多项更小的服务。

优势

  • 敏捷
  • 灵活拓展
  • 轻松部署
  • 技术自由
  • 可重复使用代码
  • 弹性

Nest微服务介绍

Nest 支持几种内置的传输层实现,称为传输器,负责在不同的微服务实例之间传输消息。大多数传输器本机都支持请求 - 响应和基于事件的消息样式。Nest 在规范接口的后面抽象了每个传输器的实现细节,用于请求 - 响应和基于事件的消息传递。这样可以轻松地从一个传输层切换到另一层,例如,利用特定传输层的特定可靠性或性能功能,而不会影响您的应用程序代码。

项目结构

新建Nest项目

shell 复制代码
nest new micro-main // 新建grpc客户端
nest new micro-user // 新建用户模块项目

安装依赖

shell 复制代码
npm i --save @nestjs/microservices 
npm i --save @grpc/grpc-js @grpc/proto-loader

项目搭建

新建user.proto文件使用protoc生成proto.pb.ts文件

proto文件编写

ini 复制代码
syntax = "proto3";

package user;

service UserService {
  rpc FindOne (FindOneReq) returns (FindOneRes) {}
}

message User {
  int64 id = 1;
  string name = 2;
  string password = 3;
  string avatar = 4;
}

message FindOneReq {
  int64 id = 1;
}
message FindOneRes {
  User user = 1;
}

使用protoc生成.pb文件

typescript 复制代码
/* eslint-disable */
import { GrpcMethod, GrpcStreamMethod } from "@nestjs/microservices";
import { Observable } from "rxjs";

export const protobufPackage = "user";

export interface User {
  id: number;
  name: string;
  password: string;
  avatar: string;
}

export interface FindOneReq {
  id: number;
}

export interface FindOneRes {
  user: User | undefined;
}

export const USER_PACKAGE_NAME = "user";

export interface UserServiceClient {
  findOne(request: FindOneReq): Observable<FindOneRes>;
}

export interface UserServiceController {
  findOne(request: FindOneReq): Promise<FindOneRes> | Observable<FindOneRes> | FindOneRes;

}

export function UserServiceControllerMethods() {
  return function (constructor: Function) {
    const grpcMethods: string[] = ["findOne"];
    for (const method of grpcMethods) {
      const descriptor: any = Reflect.getOwnPropertyDescriptor(constructor.prototype, method);
      GrpcMethod("UserService", method)(constructor.prototype[method], method, descriptor);
    }
    const grpcStreamMethods: string[] = [];
    for (const method of grpcStreamMethods) {
      const descriptor: any = Reflect.getOwnPropertyDescriptor(constructor.prototype, method);
      GrpcStreamMethod("UserService", method)(constructor.prototype[method], method, descriptor);
    }
  };
}

export const USER_SERVICE_NAME = "UserService";

user模块搭建

改造main

ts 复制代码
import { NestFactory } from '@nestjs/core';
import { AppModule } from './user.module';
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
import { USER_PACKAGE_NAME } from '@pb/user.pb';
async function bootstrap() {
  const app = await NestFactory.createMicroservice<MicroserviceOptions>(
    AppModule,
    {
      transport: Transport.GRPC,
      options: {
        url: '0.0.0.0:50051',
        protoPath: './../micro-proto/user.proto',
        package: USER_PACKAGE_NAME,
      },
    },
  );
  await app.listen();
}
bootstrap();

编写user.controller

ts 复制代码
import { Controller } from '@nestjs/common';
import { UserService } from './user.service';
import { GrpcMethod } from '@nestjs/microservices';
import { FindOneReq, USER_SERVICE_NAME} from '@pb/user.pb';
import { Metadata, ServerUnaryCall } from '@grpc/grpc-js';

@Controller('user')
export class UserController {
  constructor() {}

  @GrpcMethod(USER_SERVICE_NAME, 'FindOne')
  FindOne(
    data: FindOneReq,
    metadata: Metadata,
    call: ServerUnaryCall<any, any>,
  ) {
    return {
        id: 1,
        name: 'test',
        password: 'string',
        avatar: 'string',
      };
  }
}

微服务客户端搭建

新增user文件夹并创建user.controller以及user.module

user.controller

ts 复制代码
import { Controller, Get, Inject, OnModuleInit, Post } from '@nestjs/common';
import { ClientGrpc, ClientProxy } from '@nestjs/microservices';
import { Observable } from 'rxjs';
import { Metadata } from '@grpc/grpc-js';
import {
  FindOneReq,
  FindOneRes,
  USER_PACKAGE_NAME,
  USER_SERVICE_NAME,
  UserServiceClient,
  UserServiceController,
} from '@pb/user.pb';
@Controller(USER_PACKAGE_NAME)
export class UserController implements OnModuleInit {
  private userService: UserServiceController;
  constructor(
    @Inject(USER_SERVICE_NAME) private readonly client: ClientGrpc) {}
  onModuleInit() {
      this.userService = this.client.getService<UserServiceClient>(USER_SERVICE_NAME);
  }

  @Post('findOne')
  findOne() {
    return this.userService.findOne(1); // 内容为演示demo
  }
}

user.module

ts 复制代码
import { Module } from '@nestjs/common';
import { ClientsModule, Transport } from '@nestjs/microservices';
import { UserController } from './user.controller';
import { resolve } from 'path';
import { USER_PACKAGE_NAME, USER_SERVICE_NAME } from '@pb/user.pb';
@Module({
  imports: [
    ClientsModule.register([
      {
        name: USER_SERVICE_NAME,
        transport: Transport.GRPC,
        options: {
          url: '0.0.0.0:50051',
          protoPath: resolve(
            __dirname,
            '../micro-proto/user.proto',
          ),
          package: USER_PACKAGE_NAME,
        },
      },
    ]),
  ],
  providers: [],
  controllers: [UserController],
})
export class UserModule {}

测试

分别运行主客户端服务以及用户模块在postman中测试POST请http://localhost:3000/user/findOne

得到结果

json 复制代码
{ id: 1, name: 'test', password: 'string', avatar: 'string', }

结尾

初探微服务+grpc跑通服务

感兴趣的同学关注我后续详细补充项目细节以及搭配Redis、kafka以及ELK日志服务

相关推荐
Spirited_Away4 天前
Nest世界中的AOP
前端·node.js·nestjs
Eric_见嘉11 天前
NestJS 🧑‍🍳 厨子必修课(六):Prisma 集成(下)
前端·后端·nestjs
kongxx1 个月前
NestJS中使用Guard实现路由保护
nestjs
白雾茫茫丶1 个月前
Nest.js 实战 (十二):优雅地使用事件发布/订阅模块 Event Emitter
nestjs·nest.js·发布订阅·event emitter
lph65822 个月前
比起上传资源更应该懂得如何资源回收
node.js·nestjs
gsls2008082 个月前
将nestjs项目迁移到阿里云函数
阿里云·云计算·nestjs·云函数
d3126975102 个月前
在Nestjs使用mysql和typeorm
mysql·express·nestjs·typeorm
剪刀石头布啊2 个月前
nestjs-版本控制
nestjs
潇洒哥gg3 个月前
重生之我在NestJS中使用jwt鉴权
前端·javascript·nestjs
huangkaihao3 个月前
【NestJS学习笔记】 之 自定义装饰器
前端·node.js·nestjs