이 글은 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에 전송량 상한이 있는가?
- 무한 스트리밍 구현이 존재하지 않는가?
- 메모리 증가를 관측 지표로 확인하고 있는가?