gRPC

gRPC

gRPC는 고성능 오픈 소스 범용 RPC 프레임 워크입니다.

Installation

시작하기 전에 필요한 패키지를 설치해야합니다.

$ npm i --save grpc @grpc/proto-loader

Transporter

gRPC 전송기로 전환하려면 createMicroservice()메소드에 전달된 옵션 객체를 수정해야 합니다.

@@filename(main)
const app = await NestFactory.createMicroservice(ApplicationModule, {
  transport: Transport.GRPC,
  options: {
    package: 'hero',
    protoPath: join(__dirname, 'hero/hero.proto'),
  },
});

info 힌트 join()함수는 path 패키지에서 가져오고 Transport 열거는 @nestjs/microservices에서 온 것입니다.

Options

전송기 동작을 결정하는 사용 가능한 옵션이 많이 있습니다.

url

Connection url

protoLoader

NPM 패키지 이름 (다른 프로토 로더를 사용하려는 경우)

protoPath

.proto 파일의 절대 (또는 루트 디렉토리에 대한) 경로

loader

@grpc/proto-loader옵션. 여기.에 잘 설명되어 있습니다

package

Protobuf package name

credentials

Server credentials (read more)

Overview

일반적으로 package 속성은 protobuf 패키지 이름을 설정하고 protoPath.proto 정의 파일의 경로입니다. hero.proto 파일은 프로토콜 버퍼 언어를 사용하여 구성됩니다.

syntax = "proto3";

package hero;

service HeroService {
  rpc FindOne (HeroById) returns (Hero) {}
}

message HeroById {
  int32 id = 1;
}

message Hero {
  int32 id = 1;
  string name = 2;
}

위의 예에서, 우리는 HeroById를 입력으로 예상하고 Hero 메시지를 리턴하는 FindOne() gRPC 핸들러를 노출하는 HeroService를 정의했습니다. 이 프로토 타입 정의를 충족시키는 핸들러를 정의하려면 @GrpcMethod() 데코레이터를 사용해야합니다. 이전에 알려진 @MessagePattern()은 더 이상 유용하지 않습니다.

@@filename(hero.controller)
@GrpcMethod('HeroService', 'FindOne')
findOne(data: HeroById, metadata: any): Hero {
  const items = [
    { id: 1, name: 'John' },
    { id: 2, name: 'Doe' },
  ];
  return items.find(({ id }) => id === data.id);
}

info 힌트 @GrpcMethod()데코레이터는 @nestjs/microservices 패키지에서 가져옵니다.

HeroService는 서비스 이름인 반면, FindOneFindOne() gRPC 핸들러를 가리킵니다. 해당하는 findOne() 메소드는 두가지 인수, 즉 호출자로부터 전달된 data와 gRPC 요청의 메타 데이터를 저장하는 metadata를 취합니다.

또한, FindOne은 실제로 여기서 중복됩니다. @GrpcMethod()에 두 번째 인수를 전달하지 않으면 Nest는 자동으로 첫 번째 문자 (예 :findOne->FindOne)와 함께 메소드 이름을 사용합니다.

@@filename(hero.controller)
@Controller()
export class HeroService {
  @GrpcMethod()
  findOne(data: HeroById, metadata: any): Hero {
    const items = [
      { id: 1, name: 'John' },
      { id: 2, name: 'Doe' },
    ];
    return items.find(({ id }) => id === data.id);
  }
}

마찬가지로 인수를 전달하지 못할 수도 있습니다. 이 경우 Nest는 클래스 이름을 사용합니다.

@@filename(hero.controller)
@Controller()
export class HeroService {
  @GrpcMethod()
  findOne(data: HeroById, metadata: any): Hero {
    const items = [
      { id: 1, name: 'John' },
      { id: 2, name: 'Doe' },
    ];
    return items.find(({ id }) => id === data.id);
  }
}

Client

클라이언트 인스턴스를 만들려면 @Client()데코레이터를 사용해야 합니다.

@Client({
  transport: Transport.GRPC,
  options: {
    package: 'hero',
    protoPath: join(__dirname, 'hero/hero.proto'),
  },
})
client: ClientGrpc;

이전 예와 비교하여 약간의 차이가 있습니다. ClientProxy 클래스 대신, getService() 메소드를 제공하는 ClientGrpc를 사용합니다. getService()제네릭 메서드는 서비스 이름을 인수로 사용하고 가능한 경우 해당 인스턴스를 반환합니다.

@@filename(hero.controller)
onModuleInit() {
  this.heroService = this.client.getService<HeroService>('HeroService');
}

heroService 객체는 .proto 파일 내에 정의된 것과 동일한 메소드 세트를 노출합니다. 모든 규칙은 소문자 (자연 규칙을 따르기 위해)입니다. 기본적으로 gRPC HeroService 정의에는 FindOne()함수가 포함되어 있습니다. heroService 인스턴스는 findOne()메소드를 제공한다는 의미입니다.

interface HeroService {
  findOne(data: { id: number }): Observable<any>;
}

모든 서비스 메소드는 Observable을 리턴합니다. Nest는 RxJS 스트림을 지원하고 잘 작동하므로 HTTP 처리기 내에서도 반환할 수 있습니다.

@@filename(hero.controller)
@Get()
call(): Observable<any> {
  return this.heroService.findOne({ id: 1 });
}

전체 작업 예는 여기에서 확인할 수 있습니다.

gRPC Streaming

GRPC 자체는 스트림으로 알려진 롱텀 라이브 연결을 지원합니다. 스트림은 채팅, 관찰 또는 청크 데이터 전송과 같은 서비스 사례에 매우 유용한 도구가 될 수 있습니다. 공식 문서 (여기)에서 자세한 내용을 확인할 수 있습니다.

Nest는 두 가지 방법으로 GRPC 스트림 핸들러를 지원합니다.

  • RxJS Subject + Observable 핸들러: Controller 메소드 내에서 바로 응답을 쓰거나 Subject/Observable 소비자에게 전달하는 데 유용 할 수 있습니다

  • 순수 GRPC 호출 스트림 핸들러: 노드 표준 Duplex 스트림 핸들러에 대한 나머지 디스패치를 처리하는 일부 실행기에 전달하는 데 유용 할 수 있습니다.

Subject strategy

@GrpcStreamMethod()데코레이터는 함수 매개 변수를 RxJS Observable로 제공합니다.

// Set decorator with selecting a Service definition from protobuf package
// the string is matching to: package proto_example.orders.OrdersService
@GrpcStreamMethod('orders.OrderService')
handleStream(messages: Observable<any>): Observable<any> {
  const subject = new Subject();
  messages.subscribe(message => {
    console.log(message);
    subject.next({
      shipmentType: {
        carrier: 'test-carrier',
      },
    });
  });
  return subject.asObservable();
}

@GrpcStreamMethod()데코레이터와의 전이중 상호 작용을 지원하려면 컨트롤러 메소드에서 RxJS 'Observable'을 반환해야 합니다.

Pure GRPC call stream handler

@GrpcStreamCall()데코레이터는 grpc.ServerDuplexStream과 같은 함수 매개 변수를 제공하며 .on('data',callback), .write(message)또는 .cancel()과 같은 표준 메소드를 지원합니다. 사용 가능한 방법에 대한 전체 설명서는 여기에서 찾을 수 있습니다.

// Set decorator with selecting a Service definition from protobuf package
// the string is matching to: package proto_example.orders.OrdersService
@GrpcStreamCall('orders.OrderService')
handleStream(stream: any) {
  stream.on('data', (msg: any) => {
    console.log(msg);
    // Answer here or anywhere else using stream reference
    stream.write({
      shipmentType: {
        carrier: 'test-carrier',
      },
    });
  });
}

이 데코레이터에는 특정 리턴 매개 변수를 제공할 필요가 없습니다. 스트림은 다른 표준 스트림 유형과 같은 방식으로 처리될 것으로 예상됩니다.

Last updated