gRPC란?

[DEV] Developer 회고 / / 2020. 11. 23. 17:25

# gRPC란?

A high-performance, open source universal RPC framework


# RPC란?

분산 네트워크 환경에서 조금 더 편하게 프로그래밍하기 위해 등장한 RPC

어떻게 하면 분산 네트워크 컴퓨터 환경 또는 MSA(Micro Service Architecture)에서 프로그래밍을 쉽게 할 수 있을까?


Q. 우리가 일반적으로 사용하는 커뮤니케이션 패턴은?

Client - Server 패턴

- Client는 요청하고 기다리고

- Server는 요청한 내용을 실행하고 결과값을 반환하고

- Client는 결과값을 받아 진행

MSA를 통해 정말 다양한 언어와 프레임워크가 존재

Polyglot한 구조를 지탱하기 위해선 프로토콜을 맞춰야 비용이 발생.


Q. RPC의 궁극적인 목표는 무엇일까?

- 클라이언트 - 서버간의 커뮤니케이션에 필요한 상세한 정보는 최대한 감추고

- 클라이언트는 일반 메소드를 호출하는 것처럼 호출하면 된다.

- 서버도 마찬가지로 일반 메소드를 다루는 것처럼!


Q. RPC의 대표적인 구현체는 뭐가 있을까?

- Google의 ProtocolBuffer > gRPC는 해당 구현체를 통해 구현되어 매우 빠르다는 장점이 있다.

- Facebook의 Thrift

- Twitter의 Finalge


Q. RPC의 간단한 Example를 확인해보자

이상적인 RPC를 사용하면 아래와 같이 표현할 수 있다.

# Client
z = function(x, y)
# Server
function(x, y) {
 compute x, y
 return z
}

# RPC의 동작 원리

- Caller / Callee

사용자(Client / Server)가 필요한 비즈니스 로직을 작성하는 Layer

IDL(interface definition language)로 작성

- Stub

Stub Compiler가 IDL 파일을 읽어 원하는 Language로 생성.

Parameter Object를 Message로 marshalling/unmarshalling하는 Layer

- RPC RunTime

Server와 Client를 Binding하는 Layer

커뮤니케이션 중 발생한 에러 처리도 진행


# RPC는 어떻게 서버와 클라이언트는 연결할까?

- Static Binding

서버 주소 Hard Coding

간단하고 효율적

서버 주소 변경에 약함.

- Dynamic Binding

주소 변경에 매우 유동적

여분의 서버를 둬야 하는 단점.

Name Server

Load Balancer


# RPC 장점

RPC의 장점은?

- 비즈니스 로직에 집중할 수 있음.

- 다양한 언어를 가진 환경에서 쉽게 확장할 수 있음.

- 쉽게 인터페이스 협업이 가능함.


# gRPC

gRPC를 사용하면 클라이언트 애플리케이션에서 마치 자신의 메서드를 호출하는 것처럼 원격서버(gRPC서버)의 메서드를 직접 호출 할 수 있으므로 MSA환경의 서비스를 보다 쉽게 만들 수 있다. 여타 다른 RPC와 마찬가지로 gRPC는 IDL(Interface Definition Language)를 이용하여 서비스를 정의하고 페이로드를 정의하며 gRPC서버는 이 인터페이스를 구현하고 클라이언트 호출을 처리하기 위해 gRPC서버를 실행한다. 클라이언트 측에서 클라이언트는 서버와 동일한 인터페이스를 가지는 스텁 객체를 가지고 있다.

internal 통신이 빈번한 마이크로 서비스 구조에서 gRPC 를 적용했을 때, latency 감소 및 더 많은 트래픽을 처리하는 성능의 이점을 기대할 수 있다.



ProtoBuf

gRPC는 기본적으로 구조화된 데이터를 직렬화하기 위해 Google의 ProtoBuf를 사용한다. 


ProtoBuf로 작업할 때는 첫번째로 .proto 파일에 직렬화하려는 데이터의 구조를 정의한다. 메시지라는 오브젝트(?)로 구성되며, 각 메시지는 데이터 타입과 key&value쌍을 이루는 필드를 하나이상 가지고 있다.


message Person {

  string name = 1;

  int32 id = 2;

  bool has_ponycopter = 3;

}


그 이후 protoc를 사용하여 원하는 언어로 컴파일이 가능하다. 컴파일된 소스는 각 필드에 대한 간단한 setter/getter를 제공한다. 또한 .proto 파일을 이용하여 위 proto message가 매개변수, 리턴 값으로 사용된 service를 정의할 수 있다.


// The greeter service definition.

service Greeter {

  // Sends a greeting

  rpc SayHello (HelloRequest) returns (HelloReply) {}

}


// The request message containing the user's name.

message HelloRequest {

  string name = 1;

}


// The response message containing the greetings

message HelloReply {

  string message = 1;

}


# .proto file

gRPC 개발에 대한 핵심 파일은 gRPC 서비스 및 메시지의 계약을 정의하는 .proto file이다. 이 파일에서 gRPC 프레임워크는 서비스 기본 클래스, 메시지 및 전체 클라이언트를 코드 생성한다.

서버와 클라이언트 간에 proto 파일을 공유하여 메시지와 클라이언트 코드를 종단 간에 생성할 수 있다. 클라이언트의 코드 생성은 클라이언트와 서버에서 메시지의 중복을 제거하고 강력한 형식의 클라이언트를 만든다. 클라이언트를 작성하지 않아도 되므로 많은 서비스를 갖춘 응용 프로그램의 개발 시간이 상당히 절감된다.( 기존 server-client 방식은 클라이언트를 작성해야만 했다.)


일반적으로 JSON을 주고 받는 HTTP는 엄격한 사양이 존재하지 않는다. 그래서 개발자끼리 URL, HTTP payload, 응답코드 등을 논의해야한다. 하지만 gRPC는 gRPC가 따라야하는 명확한 형식이 있기 때문에 HTTP와 같이 큰 논의가 필요없다. 단순히 생성된 코드를 사양에 맞게 사용하면 된다.


# gRPC는 어떠한 상황에서 사용하는 것이 좋을까?

마이크로 서비스 - gRPC는 대기 시간이 짧고 처리량이 높은 통신을 위해 설계되었습니다. gRPC는 효율성이 중요한 경량 마이크로 서비스에 적합합니다.


# nestjs에서 grpc를 사용하기

Nest 에서 gRPC 를 사용하고자 한다면 우선 아래 dependency 를 설치하길 바란다.


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

그리고 부트스트래핑 되는 main.ts 를 아래와 같이 수정한다. 마이크로 서비스 전송 계층 구현과 마찬가지로 transport, createMicroservice()메소드에 전달 된 옵션 객체 의 속성을 사용하여 gRPC 전송기 메커니즘을 선택한다.


기본적으로 5000 포트로 시작된다.


const app = await NestFactory.createMicroservice<MicroserviceOptions>(AppModule, {

  transport: Transport.GRPC,

  options: {

    package: 'person',

    protoPath: join(__dirname, 'person.proto'), // 아까 만든 person proto 경로

  },

});


await app.listenAsync();


# 출처

- https://nesoy.github.io/articles/2019-07/RPC

- https://coding-start.tistory.com/351 [코딩스타트]

- https://blog.hax0r.info/2020-06-23/grpc-with-nest/  [Hax0r blog]

  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기