Distributed System/Grpc

gRPC Memory & Resource Management

여백의 기록 2026. 1. 13. 09:57
반응형

이 글은 gRPC Java 공식 문서의 Performance 및 Resource Usage 내용을 기준으로, gRPC 서비스를 운영할 때 메모리가 어디서 사용되고, 어떤 상황에서 OOM이나 리소스 고갈이 발생하는지, 그리고 이를 설정과 설계로 어떻게 예방하는지를 정리한 글입니다.

기준 문서: https://grpc.io/docs/guides/performance/

📌 카테고리: Dev > gRPC


1. gRPC에서 메모리 문제는 왜 늦게 드러날까?

gRPC 메모리 문제는 보통 다음 특징을 가진다.

  • 에러 없이 트래픽을 정상 처리하다가
  • 부하가 누적된 뒤
  • 갑자기 OOM이나 응답 지연으로 나타난다

이는 gRPC가 연결 기반이고, 메시지를 버퍼링하며 처리하기 때문이다. 즉, 요청 하나하나는 가볍지만, 누적된 리소스 사용이 문제를 만든다.

2. gRPC에서 메모리를 사용하는 주요 지점

  • 요청/응답 메시지 버퍼
  • Streaming RPC에서의 메시지 큐
  • HTTP/2 프레임 버퍼
  • 직렬화/역직렬화 중간 객체

특히 Streaming RPC에서는 연결이 살아 있는 동안 버퍼가 유지되기 때문에 메모리 점유 시간이 길어진다.

3. 메시지 크기 제한은 반드시 설정해야 한다

gRPC는 기본적으로 단일 메시지 크기를 제한할 수 있는 옵션을 제공한다.

이 제한을 두지 않으면, 대용량 요청 하나로도 메모리가 급격히 증가할 수 있다.

NettyServerBuilder
  .forPort(9090)
  .maxInboundMessageSize(4 * 1024 * 1024) // 4MB
  .addService(MyGrpcService())
  .build()
  • 입력 메시지 크기 상한을 명시
  • 비정상적으로 큰 요청을 초기에 차단

4. Streaming RPC에서 메모리가 늘어나는 패턴

Streaming RPC에서 메모리 사용이 증가하는 대표적인 상황은 다음과 같다.

  • 서버가 메시지를 빠르게 보내고
  • 클라이언트가 느리게 소비하는 경우

이 경우 메시지는 전송되지 못한 상태로 버퍼에 쌓이고, Flow Control이 걸리기 전까지 메모리 사용이 증가한다.

5. 무한 스트리밍이 위험한 이유

아래와 같은 구현은 메모리 관점에서 특히 위험하다.

override fun streamData(
  request: Request,
  responseObserver: StreamObserver<Response>
) {
  while (true) {
    responseObserver.onNext(fetchNext())
  }
}

이 코드는 메시지 개수, 크기, 전송 시간에 대한 어떤 제한도 두지 않는다. 결과적으로 메모리 사용은 트래픽에 비례해 증가한다.

6. 실무에서 가장 안전한 패턴: 전송량 상한을 둔다

Streaming을 사용하더라도, 한 요청에서 전송할 수 있는 데이터의 양을 애플리케이션 레벨에서 제한하는 것이 가장 안전하다.

override fun listUsers(
  request: ListUsersRequest,
  responseObserver: StreamObserver<User>
) {
  val limit = if (request.limit > 0) request.limit else 500
  val users = userRepository.findUsers(request.cursor, limit)

  for (user in users) {
    responseObserver.onNext(user.toGrpc())
  }
  responseObserver.onCompleted()
}
  • 한 요청당 메모리 사용량 예측 가능
  • Streaming 연결 수 증가 시에도 안정적
  • Retry, Deadline 설계와 충돌하지 않음

7. 힙 메모리와 네이티브 버퍼

gRPC Java(Netty 기반)는 힙 메모리뿐 아니라 네이티브 메모리도 함께 사용한다.

  • JVM 힙은 GC 대상
  • 네이티브 버퍼는 OS 메모리 사용

따라서 힙 사용량이 안정적이어도, 전체 프로세스 메모리는 계속 증가할 수 있다.

8. 관측 지표로 메모리 문제를 조기에 감지하기

  • In-flight Streaming RPC 수
  • Streaming 평균 지속 시간
  • 처리량 대비 메모리 사용량

에러율은 낮은데 메모리 사용량만 지속적으로 증가한다면, Streaming 또는 메시지 크기 제한을 먼저 의심하는 것이 좋다.

9. 실무 체크리스트

  • 메시지 크기 제한을 설정했는가?
  • Streaming RPC에 전송량 상한이 있는가?
  • 무한 스트리밍 구현이 존재하지 않는가?
  • 메모리 증가를 관측 지표로 확인하고 있는가?

gRPC Memory & Resource Management — 공식 문서 기반 정리
반응형