gRPC 기본과 Proto 관리

이재상·2026년 1월 10일

요약
1. gRPC는 HTTP/2와 Protobuf 기반으로 REST API 대비 높은 성능과 타입 안정성을 제공한다.
2. Channel, Streaming, Metadata, Error Code 등 기존 HTTP API와 다른 개념을 이해하는 것이 중요하다.
3. proto는 서버 레포지토리에서 단일 소스로 관리하고, 자동화로 클라이언트에 배포하는 구조가 운영상 가장 안정적이었다.

서론


현재 회사로 이직하면서 처음으로 공부하게된 개념이 gRPC였다.
기존에도 gRPC 개념이나 동작 방식은 어느정도 알고 있었지만, 웹 기반 API를 개발하는 입장에서 활용하기 어려웠고, MSA 내부 통신에서 써야할만큼 메리트가 있는가?에 대한 의문도 존재했다.

하지만 모바일 게임 회사라는 특징상 웹에서 벗어날 수 있었고, REST API보다는 비교적 핵에서 더 안전한 gRPC를 사용하고 있었고 공부를 시작하게 됐다.

본문

gRPC 기본 개념

gRPC는 기본적으로 HTTP/2 프로토콜을 사용하며, Protocol Buffers (ProtoBuf) 통해 압축된 데이터를 기반으로 통신한다.
따라서 아쉽지만 일반적인 웹 환경에서는 grpc-web과 같은 기술을 통해 HTTP1으로 Proxy 해준 다음 우회적으로 사용을 할 수 있다.

gRPC에서는 Channel이라는 개념이 존재하는데, Channel을 통해 서로 통신할 수 있다. (DB Connection과 유사하다)
1개의 Channel에서 여러개의 Service Stub을 관리할 수 있기 때문에 일반적인 경우에는 Client에서 1개의 Channel을 생성해서 여러개의 Service들과 통신할 때 공유해서 사용한다.

위와 같은 특성때문에 요청마다 Connection을 맺는 HTTP1 기반의 REST API보다 네트워크 오버헤드가 적어서 성능적으로 우수하다.

통신 방식

gRPC에서는 4가지 통신 방식을 지원한다.

Unary 통신

  • 가장 기본적인 1:1 통신 방식으로 REST API와 비슷하다.

Server Streaming

  • Client에서 요청을 보내서 서버와 연결하고 서버가 스트리밍 방식으로 응답한다.
  • gRPC는 기본적으로 응답 데이터 크기 제한이 존재하는데 (물론 옵션으로 늘릴순 있다), 큰 데이터를 내려줘야할 때나 로그성으로 실시간으로 보내줄때 활용하면 좋다.

Client Streaming

  • 위와 반대로 Client가 서버한테 Streaming 형태로 데이터를 전송하는 방식이다.
  • 주로 Client가 실시간성으로 이벤트를 발송해야할 때 활용할 수 있다.

Bi-direction Streaming

  • 서버와 클라이언트가 양방향에서 스트리밍 방식으로 통신한다.
  • 실시간 채팅이나 동기화 방식이 필요할 때 활용할 수 있다.

이처럼 1대1 통신과 Streaming 통신을 지원하는데, Streaming 통신에서 유의할 점은 Channel Timeout 설정에 따라서 재연결 시도가 잦을 수 있기 때문에 상황에 맞춰서 설정을 해야한다.

다른 특징

  • 기본적으로 TLS 암호화 통신이 존재한다.
    - 패킷을 가로채도 내용을 확인하기 어려울 뿐만 아니라 정의된 proto 파일이 없으면 데이터를 해석하기도 어렵다.
    • 따라서 기본적으로 설정해줘야하는 HTTP1 방식의 REST API보다 비교적 보안적으로 좋다고 느껴진다.
  • 다양한 언어에서 통신할 수 있는 구조를 가지고 있기 때문에 클라이언트와 서버가 언어가 다르더라도 문제가 없다.
    • 이미 정의된 proto 파일을 기반으로 타입과 기초 함수들을 구현해준다.
    • 서버는 Typescript 기반 Node 서버였고, 클라이언트는 C#이였는데 protoc를 통해 각자의 언어의 기초 코드를 생성할 수 있었다.
  • HTTP1 REST API에서 사용하는 Header 개념과 비슷하게 gRPC Metadata라는 개념이 존재한다.
    • 기존과 동일하게 인증 토큰이나 공통 Context 정보들을 담아서 통신할 수 있다.
  • HTTP Status (200, 400, 500)과 같이 gRPC Status Code도 존재한다. (gRPC Status Code)

gRPC 단점

위에는 HTTP1에 비해서 좋은 점을 이야기 했다면 단점도 분명하게 존재한다.

테스트 및 디버깅 환경에서의 불편함

  • REST API는 웹 브라우저 개발자 도구를 통해 손쉽게 분석하고 데이터를 확인할 수 있었지만, gRPC에는 해당하는 기능이 존재하지 않는다.
  • 혹은 Swagger와 같은 UI 기반 명세/테스트 도구들이 많이 존재하는데 gRPC에는 크게 존재하지 않는다. (gRPC Reflection이라는 것이 존재하기는 하지만 기존 REST API방식에 비하면 불편하다.)
  • 또한 REST API와 다르게 proto 작성도 필요하기 때문에 초기 러닝 커브가 REST API에 비하면 분명히 존재한다.
  • 이에 초기에는 Postman을 활용해서 gRPC 테스트를 진행하다가 최근에는 K6와 같은 코드 기반 테스트를 통해 개발하고 있다.

Proto의 허술함(?)

  • proto에 optional이라는 키워드가 존재하는데 값이 있을 수도 있고 없을 수도 있다는 키워드다.
  • 하지만 optional이 아닌 Property에 값을 안넣고 요청을 보내도 발송이 된다.
    • 이런 경우 언어마다 기본값을 넣어주거나 undefined를 넣어주는데 완벽한 Type Safe는 아닌 느낌을 받는다.
  • 또한 상속 개념이 없어서 interface 정의를 중복해서 여러개를 하거나, Property를 추가해서 Depth를 추가해야만 하는 문제가 있다.
  • Any 타입이 없어서 정말 동적인 데이터에 대해서는 bytes나 JSON을 stringify해서 string으로 받아야만 한다.
    • google.protobuf.Any 라는 타입이 존재하긴 하지만... 따로 import를 해야하고 사용하기 불편해서 따로 사용하지는 않았다.

결론적으로는 단점에 비해 장점이 크다고 생각하고 있고, 단점들도 초기에만 느껴지고 적응하면 괜찮아서 그런지 현재는 웹 환경 제외하면 더 좋다고 생각하고 있다.

Proto 관리 방법

기존 REST API에서는 서버와 클라이언트가 Swagger와 같은 문서를 기반으로 협업을 진행했다면, gRPC는 proto 파일을 기반으로 협업을 진행한다.

proto 파일에는 Service (도메인), RPC (함수), Request Body, Response Body, Enum등이 정의되기 때문에 서로 proto 파일만 보더라도 어느정도 의도를 파악할 수 있다.

다만 결국에는 코드기 때문에 관리가 필요했고 아래와 같은 방법으로 관리를 했다.

  • 서버쪽 레포지토리에서 모든 proto에 대해서 관리를 진행했다.
    • proto 파일과 protoc를 통해 생성된 Typescript 코드, 그리고 서버 코드들에 대해서 관리했다.
  • GitHub Action을 통해 proto 파일 변경이 감지가 되면 Client Repository에 proto를 업데이트하는 단일 소스 방식을 택했다.
    • Client에서 proto가 변경되면 자동으로 C# 코드 형태로 생성해서 관리했다.

이렇게 관리하게된 계기는 아래와 같다.

  • 기존에는 서버 레포지토리 -> IDL 레포지토리 <- 클라이언트 레포지토리 형태로 관리를 했다.
  • 클라이언트에서 proto 변경을 하고 서버한테 알려주지 않거나 서버가 미처 수정하지 못하는 경우가 종종 존재했다.
  • 또한 서버 입장에서는 내려주기 어려운 데이터 형태로 구성을 하고 이미 클라이언트가 개발을 끝마치는 경우도 종종 있었다.
  • 이러한 문제를 해결하기 위해서 고민을 하다가, REST API도 결국 Client가 서버한테 변경 사항을 요청해서 서버가 변경하는 형태로 업무를 했기 때문에 위와 같은 방식으로 변경했고 이후 모두가 만족하고 운영상 이슈도 존재하지 않았다.

결론

gRPC는 성능, 타입 안정성, 서버 간 통신에 있어 강력한 장점을 가진 기술이다.
하지만 테스트 환경의 불편함과 러닝 커브로 인해 모든 상황에 적합한 것은 아니다.
당연하게도 REST API를 완전히 대체하기보다는, 적합한 영역에서 선택적으로 사용하는 것이 가장 현실적인 접근이라고 생각한다.

기타

  • 기존 웹 환경 백엔드 서비스를 개발할때와 다르게 네트워크 환경에 대한 고려를 많이 하게 됐다.
    • 예를 들면 모바일 기기에서 서버로 요청을 보낼때 네트워크가 끊기면 Client 입장에서는 gRPC Deadline Exceed 오류를 받게 된다.
    • 이는 서버가 요청을 오랫동안 안주는 (HTTP에서는 504 Gateway timeout)에서도 Deadline Exceed 오류가 발생하기 때문에 설계 단계에서 여러 고민을 했었다.
profile
문제를 코드로만 보지 않고 구조와 흐름으로 해결하는 백엔드 개발자

0개의 댓글