gRPC란 (REST, message queue와 비교)

dasd412·2024년 11월 24일
0

gRPC

목록 보기
1/1

RPC

  • RPC(Remote Procedure Call)는 분산 시스템 내에 존재하는 다른 컴퓨터 프로세스의 메서드를 원격으로 호출하는 것이다. 마치 로컬 메서드를 호출하는 것처럼 말이다.

  • IDL(Interfacte Definition Langauge)를 활용해 호출 규약을 정의하고 stub 코드를 생성한다.

  • RPCstub이란 프록시 객체를 통해 서로 통신할 수 있게 도와준다. 프로그래머가 네트워크 지식이 없더라도 이 stub을 활용해 원격 함수 호출을 할 수 있다. (RPC 호출을 돕는 인터페이스라고 보면 된다.)


gRPC

gRPC는 구글이 개발한 RPC이다.
gRPCIDLprotobuf를 사용한다. 프로그램 상에서 사용하려면 .proto stub이 생성되어 있어야 한다.

여러 가지 통신 방식을 제공하는데, 다음과 같다.
1. 서버 측에서 스트리밍하는 방식
2. 클라이언트 측에서 스트리밍하는 방식
3. 서버와 클라이언트 양방향으로 스트리밍하는 방식

그리고 동기 방식 뿐만 아니라 비동기 방식도 제공한다.

사용 방법


1 .proto 파일 작성: 개발자가 서비스와 메시지 구조를 정의하는 .proto 파일을 작성한다.
2. protoc 실행: protoc 컴파일러를 실행하여 .proto 파일을 컴파일한다.
3. 언어별 코드 생성:protoc.proto 파일을 분석하고, 지정된 프로그래밍 언어에 맞는 코드를 자동으로 생성한다.
4. 코드 사용:생성된 코드를 프로젝트에 포함시켜 gRPC 클라이언트와 서버를 구현한다.

protoc으로 자동 생성된 파일들 (go 기준)

  1. .pb.go 파일
  • Protocol Buffer 메시지 타입에 대한 Go 구조체를 정의한다.
  • 메시지의 직렬화(serialization)와 역직렬화(deserialization) 메서드를 제공한다.
  • .proto 파일에서 정의한 모든 메시지 타입에 대한 Go 클래스를 포함한다.
  1. _grpc.pb.go 파일:
  • gRPC 서비스 인터페이스를 정의한다.
  • 서버 측 구현을 위한 Servicer 클래스를 포함한다.
  • 클라이언트 측 호출을 위한 Stub 클래스를 포함한다.

REST API와 비교

REST APIclient to server 뿐만 아니라 server to server 통신도 가능하다. 근데 왜 MSA 내에서 서버 간 통신에는 REST 보다 gRPC를 사용할까?

바로 데이터 포맷 때문이다.
REST APIJSON 기반으로 데이터를 교환한다. JSON은 사람이 보기에는 아주 편하다. 하지만, 컴퓨터 입장에서는 데이터 크기가 큰 편이고 파싱 비용도 발생한다. 반면 gRPCprotobuf라는 데이터 포맷으로 직렬화해서 json보다 더 데이터 크기도 작으면서 처리속도도 빠르다. 서버 간 통신에서는 네트워크 사용량을 줄이고, 응답 시간이 빠른 gRPC가 더 낫다. (서버 간에는 대규모 데이터 전송도 빈번하게 일어난다.)

이제 서버 간 통신 외의 것들도 살펴보자.

gRPChttp 2.0 기반으로 만들어졌기 때문에 멀티플렉싱을 제공한다. 그래서 하나의 TCP 연결로도 여러 요청과 응답 메시지를 주고 받을 수 있어 효율적이다. 만약, REST APIhttp 1.1 이하에서 사용한다면 하나의 TCP 연결로 하나의 요청/응답만 처리하기 때문에 비효율적이다. 물론, REST APIhttp 2.0에서 사용한다면 REST API 역시 멀티플렉싱을 사용할 수 있다.

그리고 REST API는 요청 / 응답 방식이다. 따라서 실시간 데이터 스트리밍에는 적합하지 않다. 하지만 gRPC는 양방향 스트리밍을 지원하여 클라이언트와 서버가 실시간으로 데이터를 주고 받을 수 있다.

그러나 REST API의 경우 브라우저에서 기본적으로 지원되지만, gRPC는 브라우저에서 직접 사용할 수 없다. 사용하려면 gRPC-web과 같은 솔루션이 필요하다.

message queue와 비교

메시지 큐gRPC는 서버 간 통신에서 많이 쓰인다. 물론 여러 가지 차이가 있겠지만, 가장 큰 것은 브로커의 유무인 것 같다.

gRPC의 경우, 클라이언트가 서버를 알아야 하지만 서버는 클라이언트를 알 필요가 없다.

메시지 큐의 경우, 브로커로 인해 클라이언트와 서버 모두 서로를 알 필요가 없다.

이 차이로 인해 설계에 있어서 메시지 큐가 좀 더 확장성이 높다.

실무에서 삽질 경험

1. .proto 파일의 namespace가 충돌하면 안된다.

https://velog.io/@dasd412/protobuf-namspace-collision-in-MSA-golang-ent

2. .proto의 field number를 함부로 수정하지 마라.

.proto라는 것은 클라이언트와 서버 간의 규약이라고 볼 수 있다. 규약은 버전이 호환되야 한다. field number 정리하겠답시고 .proto를 수정하면 다음과 같은 일이 일어난다.

  1. name의 field number를 3에서 2으로 수정한다. 기존 field number 2는 age였다. (name은 string, age는 int라고 가정)
  2. 서버는 이에 맞게 수정했다.
  3. 그대로 서버를 배포한다.
  4. 해당 .proto를 사용하던 클라이언트는 field number 2에서 int age가 올줄 알았지만 string name이 와서 터진다.

참고자료

https://grpc.io/docs/what-is-grpc/core-concepts/
https://protobuf.dev/overview/
https://mclub4.tistory.com/47
https://wisysta.tistory.com/entry/RPC-gRPC


profile
시스템 아키텍쳐 설계에 관심이 많은 백엔드 개발자입니다. (Go/Python/MSA/graphql/Spring)

0개의 댓글