실무에서 MSA 환경을 운영하다 보니,
일관성 있는 데이터 동기화와 안정적인 운영을 위해 서비스 간 통신 방식을 정확히 정리하고 선택해야겠다는 생각이 들었습니다.
이 글에서는 REST와 gRPC를 비교해 언제 어떤 걸 쓰면 좋을지, 기준을 잡아보려 합니다.
REST vs gRPC 한눈에 비교
REST와 gRPC는 모두 서비스 간 통신을 위한 기술이지만, 출발점이 다르고, 잘 맞는 사용 시나리오도 다릅니다.
REST는 HTTP를 기반으로 한 리소스 중심의 통신 방식이고,
gRPC는 원격 메서드를 호출하는 RPC(Remote Procedure Call) 모델에 가깝습니다.
이 차이가 설계 방식, 성능, 운영 경험 전반에 영향을 줍니다.
| 항목 | REST | gRPC |
| 통신 모델 | 리소스 중심 (URL + HTTP Method) | 메서드 호출 중심 (RPC) |
| 전송 프로토콜 | HTTP/1.1 (주로) | HTTP/2 |
| 데이터 포맷 | JSON (사람 친화적) | Protobuf (바이너리, 경량) |
| 요청/응답 | 요청 1 ↔ 응답 1 | Unary + Streaming |
| 스트리밍 | 기본 미지원 (SSE/WebSocket 필요) | 서버/클라이언트/양방향 기본 지원 |
| 스키마 관리 | 느슨함 (OpenAPI 등 별도 문서) | .proto로 강한 계약 |
| 코드 생성 | 수동 구현 | 클라이언트/서버 Stub 자동 생성 |
| 브라우저 접근 | 매우 쉬움 | 직접 호출 어려움 (프록시 필요) |
| 디버깅 | curl, 브라우저로 즉시 가능 | grpcurl 등 전용 도구 필요 |
| 주 사용처 | 외부 API, BFF, CRUD | 내부 서비스 통신, 고성능 RPC |
한 줄로 정리하면
- REST는 사람이 읽기 쉽고, 브라우저와 잘 맞으며, 외부에 공개하기 좋은 범용 API에 적합합니다.
- gRPC는 서비스 간 계약이 명확하고, 호출이 많거나 지연에 민감한 내부 통신에 적합합니다.
그래서 MSA 환경에서는 “외부는 REST, 내부는 gRPC” 같은 혼합 패턴이 자주 사용됩니다.
REST와 gRPC의 근본적인 차이: RPC 관점에서 보기
REST는 리소스를 중심으로 한 통신 방식입니다.
URL과 HTTP 메서드로 “무엇을 한다”를 표현하고, 응답은 상태 코드와 JSON으로 돌려받습니다.
사람이 읽기 쉽고, 브라우저와 궁합이 좋다는 점이 가장 큰 장점입니다.
반면 gRPC는 “원격 메서드를 호출한다”는 RPC 모델에 가깝습니다.
URL보다 메서드 시그니처가 중요하고, 요청과 응답은 .proto로 정의된 메시지를 그대로 주고받습니다.
그래서 gRPC를 쓰다 보면 API를 만든다기보다 인터페이스를 정의한다는 느낌에 더 가깝습니다.
아래 그림은 gRPC가 내부적으로 어떻게 RPC 호출을 처리하는지 보여줍니다.
클라이언트는 메서드를 호출하지만, 실제로는 Stub과 Runtime이 직렬화와 네트워크 전송을 담당합니다.


API 설계 방식의 차이
REST와 gRPC의 가장 큰 차이는 API를 바라보는 관점에서 드러납니다.
REST가 리소스를 중심으로 설계된다면, gRPC는 서비스가 제공하는 동작(행위) 을 중심으로 설계됩니다.
REST: 리소스를 기준으로 설계하기
REST에서는 URL이 곧 리소스를 의미합니다.
HTTP 메서드를 조합해 “이 리소스에 대해 무엇을 할 것인지”를 표현합니다.
GET /users/{userId}
POST /users
DELETE /users/{userId}
이 구조에서는
- URL = 리소스의 위치
- HTTP 메서드 = 행위
라는 역할 분담이 명확합니다.
그래서 CRUD 위주의 API나 외부 공개 API에서는 REST 방식이 직관적이고 문서화도 쉽습니다.
브라우저나 curl로 바로 호출해 볼 수 있다는 점 역시 큰 장점입니다.
gRPC: 동작(메서드)을 기준으로 설계하기
gRPC에서는 URL보다 메서드 시그니처가 중심이 됩니다.
어떤 리소스를 다루는 지보다, “이 서비스가 어떤 기능을 제공하는가”가 먼저 정의됩니다.
service VacationService {
rpc GetUserVacations(GetUserVacationsRequest)
returns (GetUserVacationsResponse);
rpc CreateVacation(CreateVacationRequest)
returns (CreateVacationResponse);
}
여기서 중요한 점은:
- API가 아니라 인터페이스를 정의한다는 느낌
- 요청/응답 구조가 .proto로 강하게 고정된다는 점입니다.
REST처럼 “이 URL이 무슨 의미지?”를 고민하기보다, 메서드 이름과 시그니처만 봐도 서비스의 책임이 드러납니다.
설계할 때 고민 포인트
REST와 gRPC를 각각 설계해보니, 자연스럽게 고민의 출발점이 달라졌습니다.
- REST를 설계할 때는
→ “이 리소스를 어떻게 쪼갤까?”
→ “URL을 어떻게 표현하면 REST스럽지?” - gRPC를 설계할 때는
→ “이 서비스가 외부에 제공해야 할 기능은 무엇일까?”
→ “이 메서드의 입력과 출력은 어디까지가 책임일까?”
그래서 gRPC에서는 API 설계보다는 서비스 인터페이스 설계에 더 가까운 사고가 필요했습니다.
같은 기능을 REST와 gRPC로 표현하면
같은 “사용자의 휴가 목록 조회” 기능이라도 표현 방식은 확연히 달라집니다.
REST
GET /users/{userId}/vacations
gRPC
rpc GetUserVacations(GetUserVacationsRequest)
returns (GetUserVacationsResponse);
REST는 리소스 구조가 먼저 보이고,
gRPC는 행위와 계약이 먼저 보입니다.
이 차이 때문에, 외부 공개 API나 BFF에서는 REST가 자연스럽고 내부 서비스 간 통신에서는 gRPC가 더 명확하게 느껴졌습니다.
설계 관점에서의 정리
- REST는
→ 리소스 모델링이 중요하고
→ HTTP 스펙과 잘 어울리는 설계가 핵심입니다. - gRPC는
→ 서비스의 책임과 기능 경계를 명확히 정의하는 것이 중요하고
→ 강한 스키마 계약을 기반으로 한 통신에 적합합니다.
그래서 MSA 환경에서는 “어떤 기능을 어디에 노출할 것인가”를 먼저 정한 뒤,
그 성격에 맞춰 REST와 gRPC를 선택하는 편이 가장 안정적인 것이라고 생각합니다.
성능과 스트리밍에서의 차이
REST와 gRPC의 성능 차이는 어디서 나올까?
REST와 gRPC의 성능 차이는 단순히 구현체의 문제가 아니라, 기반이 되는 프로토콜과 데이터 전송 방식의 차이에서 비롯됩니다.
REST는 주로 HTTP/1.1과 JSON을 사용합니다.
요청과 응답이 텍스트 기반이고, 호출이 늘어날수록 헤더 크기와 JSON 파싱 비용이 반복적으로 발생합니다.
반면 gRPC는 HTTP/2를 기반으로 동작하며, Protobuf라는 바이너리 포맷을 사용해 전송 데이터가 작고 처리 비용이 낮습니다.
HTTP/1.1
Client ---[Req1: HTML]---> Server
Client <---[Resp1: HTML]-- Server
Client ---[Req2: CSS]---> Server
Client <---[Resp2: CSS]-- Server
Client ---[Req3: JS]----> Server
Client <---[Resp3: JS]--- Server
HTTP/2
Client ---[Stream 1: Req HTML]---> Server ---[Stream 2: Req CSS]---> [Stream 3: Req JS]--->
<---[Stream 3: Resp JS]--- <---[Stream 2: Resp CSS]--- <---[Stream 1: Resp HTML]---
호출이 많아질수록 체감되는 차이
단건 요청에서는 REST와 gRPC의 차이가 크게 느껴지지 않을 수 있습니다.
하지만 MSA 환경처럼 서비스 간 호출이 빈번해질수록
작은 지연과 오버헤드가 쌓여 전체 응답 시간에 영향을 주게 됩니다.
이런 상황에서는
- 요청·응답 크기가 작고
- 연결 재사용과 헤더 압축이 기본으로 제공되는
gRPC 쪽이 더 안정적으로 느껴졌습니다.


스트리밍 방식의 차이
스트리밍 지원 여부는 REST와 gRPC를 가르는 또 하나의 중요한 기준이었습니다.
REST는 기본적으로 요청 → 응답 구조이기 때문에, 연속적인 데이터 전송이 필요할 경우 SSE나 WebSocket 같은 별도의 방식을 추가로 고려해야 합니다.
반면 gRPC는 서버 스트리밍, 클라이언트 스트리밍, 그리고 양방향 스트리밍을 통신 모델 자체로 제공합니다.
운영 / 디버깅 / 현실적인 제약
REST와 gRPC의 차이는 성능보다, 운영하면서 겪는 경험에서 더 분명해졌습니다.
REST는 문제가 생겼을 때 상황을 재현하기가 쉽습니다.
curl이나 브라우저로 바로 호출해 볼 수 있고, JSON 기반 응답이라 로그만 봐도 흐름을 빠르게 파악할 수 있었습니다.
반면 gRPC는 바이너리 통신이라 전용 도구(grpcurl 등)가 없으면 디버깅이 쉽지 않았습니다.
초기에는 운영 난이도가 더 높게 느껴졌습니다.
에러 처리 방식도 달랐습니다.
REST는 HTTP 상태 코드와 메시지를 비교적 자유롭게 표현할 수 있었지만, gRPC는 Status Code 체계를 잘 정하지 않으면 모든 에러가 비슷하게 보이기 쉬웠습니다.
대신 인터셉터를 통해 로깅이나 트레이싱을 공통으로 적용하기는 수월했습니다.
또 하나는 인프라 제약입니다.
gRPC는 HTTP/2 지원이 필요하고, 브라우저에서 직접 호출하기 어렵기 때문에 외부 공개 API보다는 내부 서비스 간 통신에 더 잘 맞았습니다.
이런 점들 때문에, REST와 gRPC는 우열보다는 역할이 다른 기술로 느껴졌습니다.
MSA에서의 혼합 운용 패턴
REST와 gRPC를 모두 써보니, MSA 환경에서는 둘 중 하나를 고르기보다 역할에 따라 나눠 쓰는 방식이 가장 자연스럽게 느껴졌습니다.
가장 흔했던 패턴은 외부는 REST, 내부는 gRPC였습니다.
브라우저나 모바일, 외부 파트너가 직접 호출하는 구간에서는 접근성과 디버깅이 쉬운 REST가 훨씬 편했습니다.
반대로 내부 서비스 간 호출에서는 지연과 호출 빈도가 중요해지면서 gRPC의 장점이 분명해졌습니다.



이 구조에서는 보통 API Gateway나 프록시가 경계 역할을 합니다.
외부 요청은 REST로 받고, 내부로 들어갈 때 gRPC로 변환해 전달하는 방식입니다.
덕분에 클라이언트는 기존 REST API를 그대로 사용하면서도, 내부 통신은 성능과 계약 측면에서 더 안정적으로 가져갈 수 있었습니다.
또 다른 패턴은 BFF + 내부 gRPC 구조였습니다.
BFF는 REST나 GraphQL로 클라이언트 요구에 맞게 응답을 구성하고, 실제 데이터 조회나 처리는 내부 gRPC 서비스에 위임합니다.
이렇게 나누니 클라이언트 변화와 내부 서비스 변경을 서로 독립적으로 가져갈 수 있었습니다.
실제로는 기존 REST API를 한 번에 바꾸기보다, 병목이 되는 구간부터 gRPC로 점진 전환하는 경우가 많았습니다.
외부 계약을 깨지 않으면서 내부 성능만 개선할 수 있어 리스크도 상대적으로 적었습니다.
이런 경험을 거치면서, REST와 gRPC는 경쟁 관계라기보다 MSA 안에서 서로 다른 역할을 맡는 도구에 가깝다는 생각이 들었습니다.
경계에 가까울수록 REST가, 내부로 깊어질수록 gRPC가 자연스럽게 자리 잡았습니다.
정리 및 선택 기준
REST와 gRPC를 비교해 보면, 결국 둘 중 하나가 더 좋다기보다는 어떤 위치에서, 어떤 역할을 맡기느냐의 문제에 가까웠습니다.
브라우저나 모바일, 외부 파트너처럼 사람과 맞닿아 있는 지점에서는 읽기 쉽고 디버깅이 쉬운 REST가 훨씬 편했습니다.
URL과 HTTP 메서드만으로도 의도가 드러나고, 문제가 생겼을 때 빠르게 확인할 수 있다는 점이 컸습니다.
반대로 서비스 안쪽으로 들어갈수록 호출 빈도, 지연, 계약 관리 같은 요소들이 중요해졌고, 이 지점에서는 gRPC의 장점이 분명하게 느껴졌습니다.
강한 스키마와 코드 생성, 스트리밍 지원 덕분에 내부 통신을 더 안정적으로 가져갈 수 있었습니다.
그래서 REST와 gRPC를 고를 때는 기술 자체보다 먼저 이런 질문을 던지게 됐습니다.
- 이 API를 누가 호출하는가
- 호출이 얼마나 자주, 얼마나 민감한가
- 이 경계가 외부 계약에 가까운가, 내부 구현에 가까운가
이 질문에 대한 답이 정해지면, REST와 gRPC 중 무엇을 써야 할지도 자연스럽게 따라왔습니다.
MSA 환경에서는 하나를 고집하기보다, 각각이 잘 어울리는 자리에 두는 것이 결국 가장 안전하고 현실적인 선택이었습니다