gRPC + Spring Boot — 고급 (Reflection·Health·LB·gRPC-Web)

2026-05-03확률과 통계 마스터 노트

gRPC + Spring Boot 마스터 노트 시리즈 10편 (마지막). Reflection으로 동적 스키마 발견, Health Check 표준 프로토콜, gzip·snappy 압축, 클라이언트 사이드·프록시 사이드 로드 밸런싱, gRPC-Web으로 브라우저 통합, Channel KeepAlive 관리, Service Discovery 통합, 운영 체크리스트까지 — 시리즈 마무리.

이 글은 gRPC + Spring Boot 마스터 노트 시리즈의 마지막 열 번째 편입니다. 1~9편이 핵심이었다면, 이번엔 운영 환경의 고급 주제 — Reflection·Health·LB·gRPC-Web·Channel 관리.

운영에서 부딪히는 디테일 모음. 한 번 정리해두면 두고두고 참고. 시리즈 마무리.

처음 고급 주제가 어렵게 느껴지는 이유

처음 이 단원이 어렵게 느껴지는 이유는 두 가지예요. 첫째, 각 주제가 독립적입니다. 둘째, 실제 시나리오 없이는 막연합니다.

해결법은 한 가지예요. 각 주제를 "운영의 어떤 문제를 풀까"로 보기. Reflection = 디버깅, Health = 모니터링, LB = 확장, gRPC-Web = 브라우저, Channel = 연결 관리. 각자 명확한 답.

Reflection — 동적 스키마 발견

@Configuration
public class GrpcConfig {
    
    @Bean
    public ServerInterceptor protoReflection() {
        return ProtoReflectionService.newInstance();
    }
}

또는:

@GrpcService
public class ReflectionService extends ProtoReflectionService { }

서버가 자기 스키마 노출 → 클라이언트 자동 발견.

# grpcurl로 자동 발견
grpcurl -plaintext localhost:9090 list

# 서비스 메서드
grpcurl -plaintext localhost:9090 list UserService

# 메시지 스키마
grpcurl -plaintext localhost:9090 describe UserRequest

여기서 시험 함정이 하나 있어요. Reflection은 운영 환경 OFF 권장. 스키마 노출 = 보안 위험. 개발·스테이징만.

Health Check — 표준 프로토콜

import io.grpc.health.v1.HealthGrpc;
import io.grpc.health.v1.HealthCheckRequest;
import io.grpc.health.v1.HealthCheckResponse;

@Bean
public HealthStatusManager healthStatusManager() {
    HealthStatusManager manager = new HealthStatusManager();
    manager.setStatus("UserService", HealthCheckResponse.ServingStatus.SERVING);
    return manager;
}
grpcurl -plaintext -d '{"service": "UserService"}' \
  localhost:9090 grpc.health.v1.Health/Check
# {"status": "SERVING"}

Kubernetes Liveness·Readiness Probe

livenessProbe:
  exec:
    command: ["grpc_health_probe", "-addr=:9090"]

readinessProbe:
  exec:
    command: ["grpc_health_probe", "-addr=:9090"]

grpc_health_probe 바이너리 사용.

여기서 정말 중요한 시험 함정 — Health Check는 운영 표준. K8s·로드 밸런서가 의존. 항상 활성화.

Compression — 메시지 압축

서버

grpc:
  server:
    compression: gzip

클라이언트

@GrpcClient("user-service")
private UserServiceGrpc.UserServiceBlockingStub stub;

public User getUser(String id) {
    return stub.withCompression("gzip").getUser(request);
}

Custom

@Bean
public GrpcServerConfigurer compressionConfigurer() {
    return serverBuilder -> ((NettyServerBuilder) serverBuilder)
        .compressorRegistry(CompressorRegistry.getDefaultInstance())
        .decompressorRegistry(DecompressorRegistry.getDefaultInstance());
}
알고리즘 비율 속도
gzip 높음 중간
snappy 중간 빠름
identity (압축 X) - 가장 빠름

여기서 시험 함정이 하나 있어요. 작은 메시지 (< 1KB) = 압축 비효율. CPU 소비 > 네트워크 절감. 큰 페이로드만 압축 권장.

로드 밸런싱

1. 클라이언트 사이드 LB

grpc:
  client:
    user-service:
      address: dns:///user-service.default.svc.cluster.local

DNS A 레코드 = 여러 IP → 자동 round-robin.

@GrpcClient(value = "user-service", configurations = LoadBalancingConfiguration.class)
private UserServiceGrpc.UserServiceBlockingStub stub;

2. 프록시 사이드 LB — Envoy·Linkerd

Client → Envoy/Linkerd Proxy → Server 1, 2, 3

Service Mesh 표준. 자동 LB·관찰성·재시도.

3. K8s Headless Service + 클라이언트 LB

apiVersion: v1
kind: Service
metadata:
  name: user-service-headless
spec:
  clusterIP: None
  selector:
    app: user-service

여기서 정말 중요한 시험 함정 — gRPC + 일반 K8s Service = LB 안 됨 (RSocket과 같은 문제). Headless Service + 클라이언트 LB 또는 Envoy.

Service Discovery 통합

grpc:
  client:
    user-service:
      address: discovery:///user-service   # Eureka·Consul·Nacos

gRPC-Web — 브라우저 통합

브라우저는 HTTP/2 직접 X (특히 Trailers·full-duplex). gRPC-Web으로 변환.

Browser → HTTP/1.1 또는 fetch → gRPC-Web Proxy → gRPC Server
                                       (Envoy·gRPC-Web Proxy·grpc-web-spring)

서버 — gRPC-Web 활성화

implementation 'org.lognet:grpc-spring-boot-starter:5.x'
grpc:
  server:
    in-process-name: my-app   # gRPC-Web 활성화

또는 Envoy 프록시:

# envoy.yaml
http_filters:
  - name: envoy.filters.http.grpc_web

TypeScript 클라이언트

import { UserServiceClient } from './generated/user_service_grpc_web_pb';

const client = new UserServiceClient('https://api.example.com');
client.getUser(req, {}, (err, response) => { ... });

여기서 시험 함정이 하나 있어요. gRPC-Web 제한 — Bidirectional Streaming 미지원 (또는 부분). 단방향 (Unary·Server Streaming만 안전).

Channel 관리

KeepAlive

grpc:
  client:
    user-service:
      enable-keep-alive: true
      keep-alive-time: 30s
      keep-alive-timeout: 5s
      keep-alive-without-calls: true

연결 유휴 시 ping → 끊긴 연결 빠르게 감지.

서버 측

grpc:
  server:
    enable-keep-alive: true
    keep-alive-time: 30s
    permit-keep-alive-without-calls: true
    permit-keep-alive-time: 5s

여기서 정말 중요한 시험 함정 — 클라이언트·서버 keep-alive 시간 일치. 불일치 시 GOAWAY 프레임. 서버 = 클라이언트 keep-alive 허용해야.

Connection Pool

ManagedChannel channel = ManagedChannelBuilder
    .forTarget("user-service:9090")
    .keepAliveTime(30, TimeUnit.SECONDS)
    .build();

// 단일 채널 = 다중 RPC 멀티플렉싱 (HTTP/2)
// Pool 거의 불필요

HTTP/2 multiplexing으로 단일 채널이 충분.

Deadline 전파

// Service A
@GrpcService
public class ServiceA extends ServiceAImpl {
    
    @Autowired
    private ServiceBClient serviceB;
    
    @Override
    public void process(Request req, StreamObserver<Response> observer) {
        // Service B 호출 — Deadline 자동 전파
        Response b = serviceB.callB(req);   // 클라이언트 Deadline → B 자동 적용
        observer.onNext(toResponse(b));
        observer.onCompleted();
    }
}

여기서 정말 중요한 시험 함정 — Deadline 자동 전파. A 호출이 5초 → B 호출 시 자동 5초 (또는 남은 시간). 체인 전체 시간 제한.

Reflective Stub — 동적 호출

import io.grpc.stub.AbstractStub;

// 스키마 모르고 호출 — Reflection 사용
ServerReflectionGrpc.ServerReflectionStub stub = ServerReflectionGrpc.newStub(channel);

// 메서드 동적 발견 + 호출

특수 시나리오. 일반은 자동 생성 Stub 사용.

모니터링 — Prometheus

grpc:
  server:
    metric-server:
      enabled: true

자동 메트릭:

  • grpc.server.calls.duration (히스토그램)
  • grpc.server.calls.received (카운터)
  • 서비스·메서드·status별 분리

Grafana 대시보드

grpc-server-spring-boot-starter 표준 대시보드 활용.

분산 추적 — OpenTelemetry

implementation 'io.opentelemetry.instrumentation:opentelemetry-grpc-1.6'
@Bean
public ServerInterceptor otelInterceptor(OpenTelemetry otel) {
    return GrpcTelemetry.create(otel).newServerInterceptor();
}

@Bean
public ClientInterceptor otelClientInterceptor(OpenTelemetry otel) {
    return GrpcTelemetry.create(otel).newClientInterceptor();
}

자동 trace ID 전파·서비스 체인 추적.

시리즈 마무리 — 10편 종합

1편부터 10편까지의 흐름:

주제 한 줄
1 기초 gRPC = HTTP/2 + Protobuf, 4 RPC 모드
2 Protobuf 메시지·필드 번호·진화 규칙
3 Unary RPC 1:1, Stub 3종, Deadline·Metadata
4 Server Streaming 1:N, 페이징·실시간·로그
5 Client Streaming N:1, 업로드·집계
6 Bidirectional N:N, 채팅·게임·트레이딩
7 Interceptors 인증·로깅·메트릭 횡단 관심사
8 Error Handling 16 Status Code·Rich Errors
9 Security TLS·mTLS·JWT·Spring Security
10 고급 Reflection·Health·LB·gRPC-Web·Channel

gRPC의 거의 모든 운영 패턴을 한 번에 통찰할 토대.

운영 체크리스트

✓ TLS 활성화 (운영)
✓ mTLS (마이크로서비스 사이) 또는 Service Mesh
✓ Health Check (K8s probe·grpc_health_probe)
✓ Reflection 운영 OFF
✓ Compression (큰 페이로드)
✓ Deadline (클라이언트·자동 전파)
✓ KeepAlive (클라이언트·서버 시간 일치)
✓ 클라이언트 사이드 LB 또는 Envoy
✓ 헤드리스 Service (K8s)
✓ Prometheus 메트릭
✓ OpenTelemetry tracing
✓ JWT 또는 OAuth2 (인증)
✓ @PreAuthorize (인가)
✓ Rate Limit (인터셉터)
✓ Retry Policy (재시도 가능 status만)
✓ 명시적 이미지 태그 (latest X)
✓ Audit Log
✓ ExceptionHandler 글로벌
✓ 입력 검증 (Bean Validation)
✓ Streaming 자원 정리 (취소 감지)

시험 직전 한 번 더 — 자주 헷갈리는 함정 모음

여기까지가 10편의 핵심입니다. 시험 직전 또는 실무에서 헷갈릴 때 다시 펼쳐 볼 수 있게 압축 노트로 마무리할게요.

  • Reflection = 동적 스키마 발견 (grpcurl 친화)
  • 운영 환경 OFF (보안 위험)
  • Health Check = grpc.health.v1.Health/Check 표준
  • K8s probe — grpc_health_probe 바이너리
  • 운영 표준
  • Compression — gzip / snappy / identity
  • 작은 메시지 (< 1KB) = 압축 비효율
  • 로드 밸런싱 — 클라이언트 사이드 (DNS·Headless Service) / Envoy 프록시 / Service Mesh
  • gRPC + 일반 K8s Service = LB 안 됨 (Headless Service 필요)
  • gRPC-Web = 브라우저 통합, Envoy·proxy 변환
  • Bidirectional 미지원 또는 부분
  • Channel KeepAlive — 클라이언트·서버 시간 일치
  • HTTP/2 multiplexing = 단일 채널이면 충분
  • Deadline 자동 전파 (체인 전체 시간 제한)
  • Prometheus 메트릭 자동 (grpc-server-spring-boot-starter)
  • OpenTelemetry tracing = GrpcTelemetry.newServerInterceptor
  • 자동 trace ID 전파
  • 운영 체크 — TLS·mTLS·Health·Reflection OFF·Compression·Deadline·KeepAlive·LB·메트릭·tracing·JWT·@PreAuthorize·Rate Limit·Retry·Audit·ExceptionHandler·Validation·Streaming 정리

시리즈 다른 편 (시리즈 마지막)

공식 문서: gRPC Docs / grpc-spring-boot-starter / Envoy gRPC 에서 더 깊이.

gRPC + Spring Boot 마스터 시리즈는 여기서 마무리. 1편부터 10편까지의 흐름이 머리에 남으면 마이크로서비스 통신·CNCF 표준·운영 패턴을 한 번에 통찰할 토대가 됩니다.

※ 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

답글 남기기

error: Content is protected !!