구글이 만든 고성능 RPC 프레임워크. HTTP/2 위에서 Protocol Buffers로 통신한다.
RPC란
원격 호출을 로컬 함수 호출처럼 보이게 하는 방식이다.
// 네트워크 통신인데 그냥 메서드 호출처럼 쓴다
UserResponse user = stub.getUser(UserRequest.newBuilder().setId(1).build());
REST가 "자원"을 다룬다면 RPC는 "행위(함수)"를 다룬다.
계약 우선 — .proto 파일
syntax = "proto3";
service UserService {
rpc GetUser (UserRequest) returns (UserResponse);
rpc ListUsers (ListRequest) returns (stream UserResponse); // 스트리밍
}
message UserRequest { int64 id = 1; }
message UserResponse {
int64 id = 1;
string name = 2;
string email = 3;
}
이 파일 하나로 서버·클라이언트 코드가 자동 생성된다. 자바·Go·파이썬·Node 등 언어가 달라도 같은 계약을 공유한다.
"문서와 구현이 어긋나는" 문제가 원천적으로 없다.
왜 빠른가
① Protocol Buffers — 이진 직렬화
-
JSON — : {"id":1,"name":"김철수"} 약 30 바이트, 파싱 필요
-
Proto : 08 01 12 09 ... — 약 12 바이트, 필드 번호 기반
-
크기 3~10배 작고, 파싱은 훨씬 빠르다
필드 이름을 보내지 않고 번호(= 1, = 2)만 보내기 때문이다.
그래서 .proto에서 필드 번호는 절대 바꾸면 안 된다 — 호환성이 깨진다.
② HTTP/2
- 멀티플렉싱 : 한 연결로 여러 요청 동시 처리 (HOL Blocking 없음)
- 헤더 압축(HPACK)
- 서버 푸시
- 양방향 스트리밍
네 가지 통신 방식 — REST에 없는 것
① Unary : 요청 1 → 응답 1 (일반 호출)
② Server streaming : 요청 1 → 응답 N (실시간 알림, 대용량 목록)
③ Client streaming : 요청 N → 응답 1 (파일 업로드, 로그 수집)
④ Bidirectional : 요청 N ↔ 응답 N (채팅, 실시간 협업)
스트리밍이 1급 시민이라는 점이 REST와의 큰 차이다.
한계 — 브라우저에서 직접 못 쓴다
브라우저의 fetch API는 HTTP/2 프레임을 직접 제어할 수 없다.
브라우저 ──✗── gRPC 서버
브라우저 ──── gRPC-Web 프록시(Envoy) ──── gRPC 서버
gRPC-Web을 쓰면 가능하지만 프록시가 필요하고 양방향 스트리밍은 지원되지 않는다.
다른 어려움
- 이진이라 사람이 못 읽는다 → 디버깅에 grpcurl 같은 도구 필요
- 브라우저 개발자 도구에서 내용 확인 불가
- 기존 HTTP 인프라(캐시, WAF, 로그)와 잘 안 맞는다
- 코드 생성 단계가 빌드에 추가된다
어디에 쓰나 — 명확한 자리가 있다
✅ 마이크로서비스 간 내부 통신 ← 가장 대표적 ✅ 다국어 환경 (Go 서버 ↔ 자바 서버) ✅ 실시간 스트리밍이 필요한 경우 ✅ 모바일 ↔ 서버 (트래픽 절약이 중요)
❌ 공개 API (외부 개발자가 쓰기 어렵다) ❌ 브라우저 직접 호출 ❌ 간단한 CRUD
전형적인 구성
브라우저 ──REST/GraphQL──► [API 게이트웨이] ──gRPC──► [내부 서비스들]
사람이 읽기 쉬운 바깥 성능이 중요한 안쪽
스키마 진화 규칙
✅ 새 필드 추가 (새 번호로) ✅ 필드 이름 변경 (번호가 같으면 호환) ❌ 필드 번호 변경·재사용 ← 데이터가 깨진다 ❌ 타입 변경
삭제한 필드는 reserved 로 표시해 번호 재사용을 막는다
reserved 3, 4; 라고 적어 두면 실수로 그 번호를 다시 쓰는 것을 컴파일러가 막는다.