gRPC 성능 모범 사례

gRPC 성능 모범 사례 (Performance Best Practices)

마이크로서비스가 많아지면 RPC 성능이 병목이 되기 쉬워요. gRPC 성능 문서는 언어 공통 조언과 C++·Java·Python별 조언을 나눠 담고 있어요. 핵심은 "그래도 스트림과 채널은 필요한 곳에만"이라는 뉘앙스예요.

출처: https://grpc.io/docs/guides/performance/

먼저 언어 공통으로 적용되는 조언이에요.

  • 스텁과 채널 재사용: 가능하면 스텁·채널을 재사용해요. 매 호출마다 새로 만들면 연결·로드밸런싱 비용이 반복돼요.
  • keepalive ping 사용: 활동이 적을 때 HTTP/2 연결을 살려 두면, 초기 RPC가 지연 없이 바로 나가요. C++에서는 GRPC_ARG_KEEPALIVE_TIME_MS 같은 채널 인자로 제어해요.
  • 스트리밍은 신중히: 오래 지속되는 데이터 흐름은 스트리밍 RPC가 적합해요. 다만 스트림은 한번 시작되면 로드밸런싱이 안 되고, 작은 규모에서 좋을 수 있지만 규모가 커지면 확장성을 떨어뜨릴 수 있어요. "gRPC를 최적화하기 위해 스트림을 쓰는 게 아니라, 애플리케이션을 최적화하기 위해" 쓰라는 게 핵심이에요.
  • 고부하 영역 처리: 한 채널은 제한된 수의 동시 스트림을 갖고, 한도에 도달하면 추가 RPC는 대기열에 쌓여요. 고부하·장기 스트리밍 RPC가 많으면 성능 문제가 생길 수 있는데, 임시방편으로 (1) 고부하 영역마다 별도 채널을 만들거나 (2) 채널 풀을 써서 여러 연결에 RPC를 분산할 수 있어요.

언어별로도 특이점이 있어요.

  • C++: 성능에 민감한 서버라면 Sync API보다 callback API를 우선 고려해요(Truly 고QPS면 completion-queue async API가 나을 수도 있어요).
  • Java: non-blocking 스텁으로 RPC를 병렬화하고, 워크로드에 맞는 스레드를 제한한 커스텀 executor를 써요.
  • Python: 다른 언어와 달리 스트리밍 RPC가 스레드를 추가로 만들어 단항 RPC보다 훨씬 느려요. asyncio를 쓰면 개선될 수 있고, future API는 스레드를 추가로 만들므로 피하는 게 좋아요.

더 알아보기