gRPC와 Protocol Buffers 개요
RPC란 무엇인가
분산 시스템에서 서비스 A가 서비스 B의 기능을 호출할 방법은 크게 둘이다. 첫째, REST처럼 자원(Resource) 을 URL로 표현하고 HTTP 메서드로 조작한다. 둘째, 원격 프로시저 호출(Remote Procedure Call, RPC) 처럼 함수 호출 형태로 추상화해 네트워크를 감춘다.
gRPC는 Google이 내부에서 10년 이상 사용하던 RPC 프레임워크 "Stubby"를 2015년 오픈소스화한 것이다. HTTP/2를 전송 계층으로 쓰고, Protocol Buffers(Protobuf)를 기본 직렬화 형식으로 사용한다. CNCF(Cloud Native Computing Foundation) 프로젝트이며 Kubernetes, Istio, Envoy, etcd 등 주요 클라우드 네이티브 인프라에서 내부 통신에 채택하고 있다.
Protocol Buffers — 계약 우선 인터페이스 정의
gRPC의 출발점은 .proto 파일이다. 이 파일에 메시지 스키마와 서비스 인터페이스를 정의하면, protoc 컴파일러가 원하는 언어(Go, Java, Python, C++, Kotlin 등 10개 이상)의 클라이언트·서버 코드를 자동 생성한다.
syntax = "proto3";
package user.v1;
message GetUserRequest {
string user_id = 1;
}
message User {
string user_id = 1;
string name = 2;
int32 age = 3;
}
service UserService {
rpc GetUser(GetUserRequest) returns (User);
}각 필드에 붙은 = 1, = 2는 필드 번호다. Protobuf는 필드 이름 대신 이 번호로 인코딩하므로 JSON처럼 키 문자열을 반복 전송하지 않아도 된다. 동일한 페이로드를 JSON으로 직렬화하면 Protobuf보다 3~5배 크기가 커지는 것이 일반적이다.
Protobuf 바이너리 인코딩 원리
각 필드는 (field_number << 3) | wire_type 형태의 varint 태그로 시작한다. int32/bool 같은 정수형은 varint (가변 길이 인코딩), string/bytes/내포 메시지는 길이-접두사 방식으로 인코딩된다. 작은 정수는 1~2바이트로 표현되므로 숫자 데이터에서 압축 효율이 특히 높다.
gRPC 아키텍처
stub.GetUser(req) Stub (생성 코드)
직렬화 / 역직렬화 Channel
HTTP/2 연결 풀
HTTP/2 accept Server Stub
역직렬화 / 직렬화 서비스 구현체
GetUser 로직
인증·로깅·재시도 ⇄ Interceptor (서버)
인증·로깅·메트릭
Channel은 서버 주소와 포트로 열린 HTTP/2 연결을 추상화한다. 내부적으로 연결 풀과 재연결 로직을 관리한다.
Stub은 protoc가 생성하는 클라이언트 측 프록시다. 메서드를 호출하면 인수를 Protobuf로 직렬화하고 HTTP/2 요청을 보낸 뒤, 응답을 역직렬화해 반환한다.
Interceptor는 미들웨어다. 클라이언트·서버 양쪽에 붙일 수 있어 인증 토큰 삽입, 요청 로깅, 재시도 로직, 분산 추적 등을 공통 처리한다.
네 가지 RPC 유형
gRPC는 REST와 달리 네 가지 통신 패턴을 지원한다.
- Unary RPC: 가장 기본적인 단일 요청-단일 응답. REST GET/POST와 동일한 개념.
- Server Streaming: 클라이언트가 요청 한 번을 보내면 서버가 여러 메시지를 스트림으로 돌려준다. 실시간 피드, 대용량 결과 페이지네이션에 적합.
- Client Streaming: 클라이언트가 여러 메시지를 보내고 서버가 최종 집계 응답을 한 번 보낸다. 센서 데이터 업로드, 파일 청크 전송에 적합.
- Bidirectional Streaming: 양쪽이 완전히 독립적인 스트림으로 메시지를 주고받는다. 실시간 채팅, 게임 상태 동기화, 협업 편집에 적합.
HTTP/2가 주는 이점
gRPC가 HTTP/1.1이 아닌 HTTP/2를 선택한 이유는 세 가지다.
멀티플렉싱(Multiplexing): HTTP/1.1은 하나의 TCP 연결에서 응답이 올 때까지 기다려야 한다(Head-of-Line Blocking). HTTP/2는 하나의 연결 안에서 여러 스트림을 동시에 독립적으로 처리한다. gRPC의 스트리밍 RPC가 가능한 이유다.
헤더 압축(HPACK): HTTP/1.1에서는 Authorization 헤더처럼 긴 헤더를 매 요청마다 반복 전송한다. HTTP/2는 HPACK 압축으로 헤더 크기를 80~90% 줄인다.
바이너리 프레이밍: HTTP/1.1의 텍스트 프레임 대신 바이너리 프레임을 써서 파싱 비용을 줄인다.
gRPC vs REST 비교
| 항목 | gRPC | REST |
|---|---|---|
| 전송 프로토콜 | HTTP/2 | HTTP/1.1 (주로) |
| 직렬화 | Protobuf (바이너리) | JSON (텍스트) |
| 스트리밍 | 4가지 패턴 지원 | 단방향(SSE) 또는 별도 WebSocket |
| 인터페이스 정의 | .proto (강타입, 코드 생성) | OpenAPI/Swagger (선택) |
| 페이로드 크기 | JSON 대비 60~70% 절약 (일반적) | 상대적으로 크다 |
| 브라우저 지원 | grpc-web 필요 (제한적) | 직접 지원 |
| 인간 가독성 | 낮음 (바이너리) | 높음 (텍스트) |
| 적합한 사용처 | 내부 마이크로서비스, 고성능 통신 | 공개 API, 브라우저 호출 |
REST가 더 유리한 상황도 있다. 브라우저에서 직접 호출하는 공개 API, 다양한 언어 클라이언트를 미리 알 수 없는 외부 파트너 연동, curl로 빠르게 테스트해야 할 때 등이다.
메타데이터, 데드라인, 상태 코드
메타데이터(Metadata) 는 HTTP 헤더에 해당하는 키-값 쌍이다. 클라이언트는 요청 메타데이터로 인증 토큰·요청 ID를 보내고, 서버는 응답 메타데이터로 속도 제한 정보 등을 돌려줄 수 있다.
데드라인(Deadline) 은 RPC가 완료되어야 할 절대 시각이다. DEADLINE_EXCEEDED 상태가 되면 클라이언트는 물론 서버 측 처리도 취소된다. 마이크로서비스 체인에서 상위 호출의 데드라인을 하위 호출에 전파해야 요청 전체가 제한 시간 내에 완료됨을 보장할 수 있다.
상태 코드(Status Code) 는 HTTP 상태 코드와 별개로 gRPC가 정의한 16개 코드다.
| 코드 | 의미 |
|---|---|
OK (0) | 성공 |
CANCELLED (1) | 클라이언트가 취소 |
UNKNOWN (2) | 서버 내부 오류 (상세 불명) |
INVALID_ARGUMENT (3) | 잘못된 인수 |
DEADLINE_EXCEEDED (4) | 데드라인 초과 |
NOT_FOUND (5) | 자원 없음 |
ALREADY_EXISTS (6) | 이미 존재 |
PERMISSION_DENIED (7) | 권한 부족 |
UNAVAILABLE (14) | 서버 일시 불가 (재시도 가능) |
언제 gRPC를 선택하는가
gRPC는 다음 조건이 겹칠 때 REST보다 유리하다.
- 내부 마이크로서비스 통신: 클라이언트와 서버를 모두 직접 관리하고, 언어가 고정되어 있을 때.
- 고성능 요구: 초당 수만 건 이상의 요청에서 직렬화 오버헤드를 최소화해야 할 때.
- 양방향 스트리밍: 실시간 피드나 RPC 기반 이벤트 스트림이 필요할 때.
- 강타입 계약: 계약 우선 설계로 클라이언트-서버 간 타입 불일치 버그를 컴파일 타임에 잡고 싶을 때.
References
- https://grpc.io/docs/what-is-grpc/introduction/
- https://grpc.io/docs/what-is-grpc/core-concepts/
- https://grpc.io/docs/guides/status-codes/
- https://aws.amazon.com/compare/the-difference-between-grpc-and-rest/
- https://learn.microsoft.com/en-us/aspnet/core/grpc/comparison
- https://www.freecodecamp.org/news/what-is-grpc-protocol-buffers-stream-architecture/
- https://blog.nashtechglobal.com/what-is-grpc-protocol-buffers-streaming-and-architecture/