본문으로 건너뛰기
AICosmus

Where tech meets the everyday — AI, fintech, swimming, and cars.

AICosmus

Where tech meets the everyday — AI, fintech, swimming, and cars.

  • 홈
  • IT기술
    • RAG
    • GRPC
    • Kotlin
    • LLM
    • 금융 IT
    • 에이전트
    • 제로Trust
    • 자동화
  • 일상
    • 자동차
    • 경제/재테크
    • 생활정보
  • About
    • Contact
    • Terms of Service
    • Disclaimer
    • Privacy – Policy
  • 홈
  • IT기술
    • RAG
    • GRPC
    • Kotlin
    • LLM
    • 금융 IT
    • 에이전트
    • 제로Trust
    • 자동화
  • 일상
    • 자동차
    • 경제/재테크
    • 생활정보
  • About
    • Contact
    • Terms of Service
    • Disclaimer
    • Privacy – Policy
gRPC 마이크로서비스 장애 차단 개념 일러스트
GRPC

gRPC 데드라인과 재시도 정책으로 장애 전파 차단하기

By AICosmus
2026년 07월 19일 10 Min Read
0

마이크로서비스에서 장애는 왜 ‘전염’될까

마이크로서비스 아키텍처를 운영하다 보면 한 서비스의 느려짐이 연쇄적으로 전체 시스템을 마비시키는 상황을 경험하게 됩니다. 특히 여름철처럼 트래픽이 급증하는 시기에는 하나의 느린 의존 서비스가 수십 개의 상위 서비스까지 타임아웃 지옥에 빠뜨리곤 합니다. REST 기반 시스템에서는 이 문제를 HTTP 클라이언트 타임아웃과 서킷 브레이커로 해결해왔지만, gRPC는 프로토콜 수준에서 훨씬 정교한 장애 전파 차단 메커니즘을 내장하고 있습니다.

gRPC의 데드라인(Deadline), 타임아웃 전파(Timeout Propagation), 재시도 정책(Retry Policy)은 단순히 ‘일정 시간 지나면 끊는다’는 수준이 아닙니다. 호출 체인 전체에 걸쳐 남은 시간 예산을 자동으로 전달하고, 실패한 요청을 서버 부하를 고려하며 지능적으로 재시도하는 체계적인 복원력 프레임워크입니다. 이 글에서는 이 메커니즘들의 내부 동작 원리를 이해하고, 실전 운영에서 어떻게 설계해야 장애 전파를 효과적으로 차단할 수 있는지 상세히 다루겠습니다.

gRPC 데드라인 전파 흐름도

gRPC 데드라인의 동작 원리와 전파 메커니즘

데드라인 vs 타임아웃: 핵심 차이점

REST 세계에서 흔히 쓰는 ‘타임아웃’은 단일 홉(hop)에서의 최대 대기 시간입니다. 클라이언트가 서버에 5초 타임아웃을 걸면, 해당 연결에서만 5초를 기다립니다. 하지만 서버가 내부적으로 또 다른 서비스를 호출한다면? 그 내부 호출에는 별도의 타임아웃이 적용되어 원래 클라이언트의 의도와 무관하게 동작합니다.

gRPC의 데드라인은 근본적으로 다릅니다. 데드라인은 ‘이 요청이 의미 있는 마지막 시각(absolute timestamp)’을 나타냅니다. 클라이언트가 “2026-07-19T14:00:00.500Z까지 응답을 받아야 한다”고 선언하면, 이 절대 시각이 호출 체인의 모든 서비스에 HTTP/2 헤더(grpc-timeout)로 전파됩니다. 중간 서비스는 자신이 소비한 시간을 제외한 남은 예산만큼만 하위 서비스를 기다릴 수 있습니다.

데드라인 전파의 실제 흐름

구체적인 예를 들어보겠습니다. API Gateway → OrderService → PaymentService → BankAPI라는 4단계 호출 체인이 있다고 가정합니다.

  • API Gateway가 전체 데드라인을 3000ms로 설정합니다.
  • OrderService에 도달하는 데 100ms가 소요되어, OrderService는 남은 2900ms의 예산을 받습니다.
  • OrderService 자체 처리에 200ms를 쓴 뒤 PaymentService를 호출하면, PaymentService는 2700ms의 예산을 받습니다.
  • PaymentService가 BankAPI를 호출할 때는 남은 예산에서 자신의 처리 시간을 뺀 값이 전달됩니다.

만약 BankAPI가 느려져서 남은 예산을 초과하면, gRPC는 즉시 DEADLINE_EXCEEDED(코드 4) 에러를 반환합니다. 이때 핵심은 불필요한 작업이 즉시 중단된다는 점입니다. BankAPI의 응답을 기다리는 PaymentService, OrderService 모두 데드라인 초과를 감지하고 처리를 중단합니다.

코드로 보는 데드라인 설정

Go 언어에서 gRPC 데드라인을 설정하는 패턴을 살펴보겠습니다. context 패키지의 WithDeadline 또는 WithTimeout 함수를 사용합니다.

클라이언트 측에서는 ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)로 컨텍스트를 생성하고, 이 ctx를 RPC 호출에 전달합니다. defer cancel()을 반드시 호출하여 리소스 누수를 방지해야 합니다.

서버 측에서는 수신된 컨텍스트의 데드라인을 확인할 수 있습니다. ctx.Deadline() 메서드로 남은 시간을 조회하고, 하위 서비스 호출 시 이 컨텍스트를 그대로 전달하면 데드라인이 자동 전파됩니다. Python에서는 context.time_remaining()으로 남은 시간을 확인할 수 있으며, Java에서는 Deadline.after()를 CallOptions에 설정합니다.

데드라인 미설정의 위험성

데드라인을 설정하지 않으면 gRPC 요청은 기본적으로 무한 대기합니다. 이는 운영 환경에서 극도로 위험합니다. 느린 의존 서비스 하나가 연결 풀을 고갈시키고, 고루틴이나 스레드가 무한히 쌓이면서 OOM(Out of Memory)으로 서비스가 죽는 시나리오가 빈번하게 발생합니다. 구글 내부에서도 “항상 데드라인을 설정하라”는 것이 gRPC 사용의 첫 번째 규칙으로 강조됩니다.

타임아웃 버짓 설계 전략

호출 체인에서의 시간 배분 원칙

타임아웃 버짓 설계는 단순히 “각 서비스에 적당한 시간을 준다”는 것이 아닙니다. 전체 호출 체인의 SLO(Service Level Objective)를 기준으로 역산하여 각 구간의 예산을 배분하는 체계적인 접근이 필요합니다.

계층별 타임아웃 버짓 설계 가이드

효과적인 타임아웃 버짓 설계를 위한 핵심 원칙을 정리하면 다음과 같습니다.

  • 외부 데드라인에서 내부로 역산합니다. 사용자 대면 API의 SLO가 2초라면, 중간 서비스들의 합산 처리 시간은 반드시 2초 미만이어야 합니다. 각 서비스의 p99 지연 시간을 측정하고, 여유 마진(보통 10~20%)을 두어 할당합니다.
  • 하위 호출의 데드라인은 상위보다 항상 짧아야 합니다. OrderService가 2500ms 예산을 받았는데, PaymentService 호출에 2500ms를 그대로 주면 OrderService 자신의 후처리 시간이 없습니다. 자체 처리 시간과 네트워크 오버헤드를 고려한 마진을 반드시 확보하세요.
  • 재시도 시간을 예산에 포함해야 합니다. 재시도 정책이 최대 2회 재시도를 허용한다면, 단일 시도 타임아웃 × 3(원래 + 재시도 2회)이 전체 예산 안에 들어와야 합니다.

서비스 계층별 데드라인 설정 패턴

실전에서 자주 사용되는 계층별 패턴을 소개합니다.

Edge Layer(API Gateway, BFF)에서는 사용자 경험 SLO를 기준으로 최상위 데드라인을 설정합니다. 일반적으로 웹 API는 1~5초, 모바일은 3~10초, 배치 작업은 30~300초 범위입니다. 이 레이어에서 설정한 데드라인이 전체 체인의 절대 상한이 됩니다.

Domain Service Layer(주문, 결제, 재고 등)에서는 수신된 데드라인을 존중하되, 하위 호출에 더 짧은 서브 데드라인을 적용합니다. ctx.Deadline()으로 남은 시간을 확인하고, 자체 처리 예상 시간을 뺀 값을 하위 호출의 상한으로 사용하는 패턴이 일반적입니다. 남은 시간이 최소 임계값(예: 100ms) 미만이면 하위 호출을 시도하지 않고 즉시 DEADLINE_EXCEEDED를 반환하는 가드 로직도 중요합니다.

Infrastructure Layer(DB, 캐시, 외부 API)에서는 해당 인프라의 특성에 맞는 타임아웃을 설정합니다. Redis 호출은 50~200ms, PostgreSQL 쿼리는 500~2000ms, 외부 결제 API는 5~15초가 일반적입니다. 다만 상위에서 전파된 데드라인이 이보다 짧다면 전파된 값이 우선합니다.

데드라인 오버라이드가 필요한 경우

때로는 전파된 데드라인을 무시하고 새로운 데드라인을 설정해야 하는 경우가 있습니다. 대표적인 사례는 fire-and-forget 패턴의 비동기 작업입니다. 예를 들어 주문 처리 후 알림 발송은 원래 요청의 데드라인과 무관하게 별도의 타임아웃으로 실행되어야 합니다. 이 경우 새로운 컨텍스트를 생성하여 독립적인 데드라인을 부여합니다.

또한 중요도가 낮은 부가 호출(추천, 개인화 등)에는 상위 데드라인보다 훨씬 짧은 타임아웃을 걸고, 실패 시 기본값으로 폴백하는 패턴도 자주 사용됩니다. 이를 통해 핵심 경로의 지연 시간에 비핵심 의존성이 영향을 주지 않도록 격리합니다.

재시도 정책(Retry Policy) 구성과 실전 패턴

gRPC 내장 재시도 메커니즘

gRPC는 클라이언트 레벨에서 투명한 재시도를 지원하는 서비스 설정(Service Config)을 내장하고 있습니다. 이 기능은 애플리케이션 코드 변경 없이 재시도 정책을 적용할 수 있다는 점에서 강력합니다.

서비스 설정의 retryPolicy 섹션에서 정의할 수 있는 핵심 파라미터는 다음과 같습니다.

  • maxAttempts: 최대 시도 횟수(원래 요청 포함). 예를 들어 3으로 설정하면 원래 시도 1회 + 재시도 최대 2회입니다.
  • initialBackoff / maxBackoff: 재시도 간 대기 시간의 초기값과 최대값. 지수 백오프가 적용되며, 각 시도마다 initialBackoff × 2^(시도횟수-1)로 증가하되 maxBackoff를 초과하지 않습니다.
  • backoffMultiplier: 백오프 승수. 기본 2.0이며 조정 가능합니다.
  • retryableStatusCodes: 재시도할 gRPC 상태 코드 목록. 모든 에러를 재시도하면 안 됩니다.

재시도 가능한 상태 코드 분류

어떤 에러를 재시도할지 결정하는 것은 재시도 정책의 핵심입니다. gRPC 상태 코드를 재시도 적합성 기준으로 분류하면 다음과 같습니다.

안전하게 재시도 가능한 코드:

  • UNAVAILABLE(14): 서비스 일시 불가. 일시적 네트워크 문제, 서버 과부하, 롤링 배포 중 발생. 가장 대표적인 재시도 대상입니다.
  • RESOURCE_EXHAUSTED(8): 리소스 한계 초과. 단, rate limit에 의한 것이라면 백오프를 충분히 줘야 합니다.
  • ABORTED(10): 트랜잭션 충돌. 낙관적 동시성 제어에서 재시도로 해결 가능합니다.

조건부 재시도 가능한 코드:

  • DEADLINE_EXCEEDED(4): 데드라인 초과. 남은 전체 데드라인 예산이 있어야만 재시도 의미가 있습니다.
  • INTERNAL(13): 서버 내부 에러. 일시적 버그일 수 있지만, 재시도해도 같은 에러가 반복될 수 있어 제한적으로 사용합니다.

절대 재시도하면 안 되는 코드:

  • INVALID_ARGUMENT(3): 잘못된 인자. 재시도해도 결과가 같습니다.
  • NOT_FOUND(5): 리소스 미존재. 없는 건 다시 해도 없습니다.
  • ALREADY_EXISTS(6): 중복 생성 시도. 멱등하지 않은 생성 요청의 재시도는 위험합니다.
  • PERMISSION_DENIED(7): 권한 부족. 재시도로 권한이 생기지 않습니다.
  • UNAUTHENTICATED(16): 인증 실패. 토큰 갱신 후 재시도하는 별도 로직이 필요합니다.

멱등성(Idempotency)과 재시도 안전성

재시도에서 가장 중요한 전제는 멱등성입니다. 같은 요청을 여러 번 보내도 결과가 동일해야 재시도가 안전합니다. GET/조회 성격의 RPC는 본질적으로 멱등하지만, 생성/수정/삭제 RPC는 주의가 필요합니다.

멱등성을 보장하는 대표적인 패턴은 클라이언트가 고유한 요청 ID(idempotency key)를 생성하여 요청에 포함하는 것입니다. 서버는 이 키를 기준으로 중복 요청을 감지하고, 이미 처리된 요청이면 이전 결과를 그대로 반환합니다. Proto 메시지에 string request_id 필드를 추가하는 것이 일반적인 패턴입니다.

gRPC 서비스 설정에서 retryPolicy 대신 hedgingPolicy를 사용할 수도 있습니다. 헤징은 데드라인 내에서 동일 요청을 여러 서버에 동시에 보내 가장 빠른 응답을 취하는 전략입니다. 이 역시 멱등한 읽기 전용 RPC에서만 안전하게 사용할 수 있습니다.

gRPC 재시도 정책 의사결정 플로우차트

서비스 설정(Service Config) JSON 구조

gRPC의 재시도 정책은 서비스 설정 JSON으로 정의합니다. 이 설정은 네임 리졸버(DNS, Consul, etcd 등)를 통해 동적으로 배포하거나, 클라이언트 코드에서 직접 지정할 수 있습니다.

실전에서 권장하는 서비스 설정 구조는 메서드 단위로 세분화하는 것입니다. 읽기 RPC(GetOrder, ListItems 등)에는 적극적인 재시도를, 쓰기 RPC(CreateOrder, ProcessPayment 등)에는 보수적인 재시도를 적용합니다. name 필드에 service와 method를 지정하여 RPC별로 다른 정책을 부여할 수 있으며, method를 빈 문자열로 두면 해당 서비스의 모든 메서드에 기본 정책으로 적용됩니다.

waitForReady 옵션도 함께 고려해야 합니다. 이 옵션을 true로 설정하면 서버가 아직 Ready 상태가 아닐 때(연결 수립 중) 즉시 실패하지 않고 Ready가 될 때까지 대기합니다. 롤링 배포 시 짧은 불가 시간을 투명하게 넘길 수 있지만, 데드라인과 함께 사용해야 무한 대기를 방지할 수 있습니다.

장애 전파 차단 고급 패턴

서킷 브레이커와 gRPC의 조합

gRPC 자체에는 서킷 브레이커가 내장되어 있지 않지만, Interceptor 레이어에서 구현하거나 서비스 메시(Istio, Linkerd)의 서킷 브레이커를 활용할 수 있습니다. 데드라인과 재시도만으로는 부족한 시나리오가 있습니다.

하위 서비스가 완전히 다운되어 모든 요청이 UNAVAILABLE을 반환하는 상황을 생각해보세요. 재시도 정책이 3회 시도를 허용한다면, 모든 클라이언트가 3배의 요청을 쏟아부어 이미 과부하된 서버를 더 압박합니다. 이를 ‘retry storm(재시도 폭풍)’이라 부르며, 장애를 복구하기는커녕 악화시킵니다.

서킷 브레이커는 일정 실패율을 초과하면 하위 호출을 차단(open 상태)하고, 일정 시간 후 제한적으로 시도(half-open)하여 복구를 확인하는 패턴입니다. gRPC Interceptor에서 서킷 브레이커를 구현할 때는 메서드 단위 또는 서비스 단위로 상태를 관리하고, open 상태에서는 즉시 UNAVAILABLE을 반환하여 불필요한 네트워크 왕복을 차단합니다.

재시도 예산(Retry Budget)과 재시도 쓰로틀링

retry storm을 방지하는 또 다른 접근은 재시도 예산입니다. gRPC 서비스 설정의 retryThrottling 섹션에서 maxTokens와 tokenRatio를 설정하여 클라이언트 단위의 재시도 빈도를 제한할 수 있습니다.

동작 원리는 토큰 버킷과 유사합니다. 클라이언트는 maxTokens(예: 10) 만큼의 재시도 토큰을 보유하고, 재시도할 때마다 1토큰을 소비합니다. 성공적인 요청이 올 때마다 tokenRatio(예: 0.1)만큼 토큰이 회복됩니다. 토큰이 바닥나면 더 이상 재시도하지 않고 즉시 에러를 전파합니다.

이 메커니즘은 정상 상황에서는 넉넉한 재시도를 허용하되, 대규모 장애 시에는 자동으로 재시도를 억제하여 하위 서비스의 복구를 돕습니다. 서비스 설정에서 다음과 같이 정의합니다: retryThrottling의 maxTokens를 10, tokenRatio를 0.1로 설정하면 100회 연속 재시도 후 토큰이 고갈되어 재시도가 중단됩니다.

헤징(Hedging) 요청 전략

헤징은 지연 시간의 꼬리(tail latency)를 줄이는 공격적인 전략입니다. 동일한 요청을 약간의 시차를 두고 여러 백엔드에 동시 전송하고, 가장 먼저 돌아오는 성공 응답을 채택합니다. 나머지 진행 중인 요청은 취소합니다.

gRPC 서비스 설정의 hedgingPolicy에서 maxAttempts(동시 전송 수), hedgingDelay(다음 헤지 전송까지의 지연), nonFatalStatusCodes(헤지 트리거가 아닌 코드)를 설정합니다. hedgingDelay를 0으로 설정하면 모든 헤지를 동시에 보내고, 양수 값을 주면 첫 번째 시도가 해당 시간 내에 응답하지 않을 때 다음 헤지를 발송합니다.

헤징은 읽기 전용, 멱등한 RPC에서만 사용해야 합니다. 쓰기 RPC에 헤징을 적용하면 중복 쓰기가 발생합니다. 또한 헤징은 서버 부하를 maxAttempts 배로 증가시킬 수 있으므로, 전체 시스템 용량을 고려하여 신중하게 적용해야 합니다. p99 지연 시간을 기준으로 hedgingDelay를 설정하면(예: p50 지연 시간으로 설정) 정상 시에는 헤지가 발동하지 않고 느린 경우에만 추가 시도가 나가도록 최적화할 수 있습니다.

로드 밸런싱과 장애 격리

gRPC의 클라이언트 사이드 로드 밸런싱은 장애 격리에 중요한 역할을 합니다. 기본 pick_first 정책은 하나의 서버에 모든 요청을 보내므로, 해당 서버가 느려지면 모든 요청이 영향을 받습니다. round_robin으로 변경하면 요청이 분산되지만, 느린 서버에도 동일 비율로 요청이 가므로 여전히 문제입니다.

더 고급 접근은 outlier detection(이상치 감지)입니다. Envoy나 Istio 같은 서비스 메시에서 제공하는 이 기능은, 특정 백엔드의 에러율이 임계값을 초과하면 해당 백엔드를 로드 밸런싱 풀에서 일시적으로 제거합니다. 이를 통해 장애 노드의 영향이 전체 클라이언트로 전파되는 것을 방지합니다.

gRPC 서킷 브레이커 상태 전이 다이어그램

운영 환경 모니터링과 튜닝

핵심 메트릭 수집

데드라인과 재시도 정책을 운영에 적용했다면, 그 효과를 측정하고 지속적으로 튜닝해야 합니다. 반드시 추적해야 할 핵심 메트릭은 다음과 같습니다.

  • grpc_client_attempt_duration_seconds: 개별 시도(재시도 포함) 단위의 지연 시간 히스토그램. 재시도가 전체 지연에 얼마나 기여하는지 파악할 수 있습니다.
  • grpc_client_attempts_per_call: 하나의 논리적 호출당 평균 시도 횟수. 1에 가까울수록 건강한 상태이며, 지속적으로 높다면 하위 서비스 불안정을 나타냅니다.
  • deadline_exceeded_total: DEADLINE_EXCEEDED 에러 발생 빈도. 급증 시 타임아웃 예산이 너무 빠듯하거나 하위 서비스가 느려진 신호입니다.
  • retry_budget_exhausted_total: 재시도 예산 고갈 횟수. 잦다면 하위 서비스의 근본 문제를 해결해야 합니다.
  • circuit_breaker_state: 서킷 브레이커 상태 변화(closed → open → half-open). 상태 전이 시점과 빈도를 추적합니다.

데드라인 튜닝 프로세스

최적의 데드라인 값은 이론으로 정할 수 없고, 실제 트래픽 패턴에서 반복적으로 조정해야 합니다. 권장하는 튜닝 프로세스는 다음과 같습니다.

첫째, 기준선을 수립합니다. 각 RPC의 p50, p90, p99, p999 지연 시간을 최소 2주간 수집합니다. 주중/주말, 피크/오프피크의 패턴 차이를 반드시 파악합니다.

둘째, 초기 데드라인을 p99의 2~3배로 설정합니다. 이는 정상적인 변동은 수용하되 비정상적 지연은 차단하는 보수적 시작점입니다. 예를 들어 p99가 200ms인 RPC라면 데드라인을 400~600ms로 시작합니다.

셋째, DEADLINE_EXCEEDED 비율을 관찰합니다. 정상 트래픽에서 0.1~1% 범위가 건강한 상태입니다. 5% 이상이면 데드라인이 너무 빠듯한 것이고, 0%에 가까우면 데드라인이 너무 느슨하여 보호 효과가 없는 것입니다.

넷째, 계절성과 트래픽 변동을 고려합니다. 이벤트 기간이나 여름 시즌처럼 트래픽이 급증하는 시기에는 서버 지연이 평소보다 높아지므로, 동적으로 데드라인을 조정하거나 충분한 마진을 사전에 확보해야 합니다.

장애 시나리오별 동작 검증

Chaos Engineering 접근법으로 다양한 장애 시나리오에서 데드라인·재시도·서킷 브레이커가 기대대로 동작하는지 검증합니다. 대표적인 테스트 시나리오:

  • 느린 의존성(Slow Dependency): 하위 서비스에 인위적 지연을 주입하여 데드라인 초과가 적절히 발생하고 상위로 전파되는지 확인합니다.
  • 부분 장애(Partial Failure): 백엔드 인스턴스 일부만 에러를 반환하게 하여 재시도가 건강한 인스턴스로 라우팅되는지 확인합니다.
  • 전체 장애(Total Failure): 모든 백엔드가 에러를 반환할 때 서킷 브레이커가 열리고, 재시도 예산이 고갈되어 retry storm이 발생하지 않는지 확인합니다.
  • 복구(Recovery): 장애 후 서비스가 복구될 때 서킷 브레이커가 half-open으로 전이하고, 점진적으로 트래픽이 회복되는지 확인합니다.

실전 체크리스트와 안티패턴

운영 투입 전 필수 체크리스트

gRPC 서비스를 프로덕션에 배포하기 전, 다음 항목을 반드시 점검하세요.

  • 모든 RPC에 데드라인이 설정되었는가? 단 하나의 데드라인 없는 호출도 전체 시스템의 취약점이 됩니다. 린터나 Interceptor에서 데드라인 미설정을 감지하여 경고하는 가드를 추가하세요.
  • 재시도 대상 RPC가 멱등한가? 비멱등 RPC에 재시도를 적용하면 중복 처리로 인한 데이터 불일치가 발생합니다. 반드시 멱등성 키를 구현하거나, 재시도 대상에서 제외하세요.
  • 재시도 예산(retryThrottling)을 설정했는가? 무제한 재시도는 retry storm의 원인입니다. 반드시 maxTokens로 상한을 두세요.
  • 데드라인에 재시도 시간이 포함되었는가? 전체 데드라인 3초에 시도당 타임아웃 2초, 최대 3회 시도면 첫 시도만 의미 있고 나머지는 데드라인 초과로 즉시 실패합니다. 시도당 타임아웃 × 최대 시도 횟수 ≤ 전체 데드라인이어야 합니다.
  • 서버 측에서 데드라인을 확인하고 조기 종료하는가? 무거운 처리(대량 쿼리, 파일 생성 등)를 시작하기 전 ctx.Err()를 체크하여, 이미 만료된 컨텍스트에서는 작업을 시작하지 않도록 합니다.

흔한 안티패턴과 해결책

안티패턴 1: 모든 에러를 재시도

retryableStatusCodes에 모든 에러 코드를 넣는 것은 위험합니다. INVALID_ARGUMENT를 재시도해봐야 결과는 같고 서버 리소스만 낭비합니다. 반드시 일시적 에러(UNAVAILABLE, RESOURCE_EXHAUSTED)만 선별적으로 재시도하세요.

안티패턴 2: 재시도에 고정 간격 사용

initialBackoff를 1초로 설정하고 backoffMultiplier를 1.0으로 두면 매 재시도마다 정확히 1초를 기다립니다. 다수의 클라이언트가 같은 시각에 재시도하여 서버에 요청이 몰리는 thundering herd 현상이 발생합니다. 반드시 지수 백오프 + 지터(jitter)를 사용하세요. gRPC의 기본 백오프는 ±20%의 랜덤 지터를 자동 적용합니다.

안티패턴 3: 데드라인 없이 재시도만 활성화

데드라인이 없으면 느린 서버에 대한 재시도가 무한히 반복될 수 있습니다. maxAttempts가 3이라도, 각 시도가 30초씩 걸리면 전체 호출이 90초 동안 블로킹됩니다. 데드라인은 재시도의 전체 시간 상한을 보장하는 안전 장치입니다.

안티패턴 4: 서킷 브레이커 임계값을 너무 민감하게 설정

1회 에러만으로 서킷이 열리면 정상적인 네트워크 글리치에도 불필요하게 트래픽이 차단됩니다. 최소 5~10회의 연속 에러 또는 50% 이상의 에러율을 기준으로 설정하되, 트래픽이 충분할 때만 통계적으로 의미 있는 판단을 내리도록 최소 요청 수(minimum requests) 조건을 함께 사용하세요.

안티패턴 5: 호출 체인 각 레이어에서 독립적으로 재시도

A → B → C 체인에서 B도 재시도하고 A도 재시도하면, C에 도달하는 요청은 기하급수적으로 증폭됩니다(A의 3회 × B의 3회 = 최대 9회). 가능하면 재시도는 가장 바깥 레이어(Edge)에서만 수행하고, 내부 서비스 간에는 즉시 에러를 전파하는 것이 안전합니다. 또는 재시도 예산으로 총량을 제한하세요.

언어별 구현 팁

Go에서는 context 패키지가 데드라인 전파를 자연스럽게 지원합니다. gRPC 서버 핸들러의 첫 번째 인자인 ctx에 이미 클라이언트의 데드라인이 담겨 있으므로, 하위 호출 시 이 ctx를 그대로 전달하면 됩니다. 서비스 설정 JSON은 grpc.WithDefaultServiceConfig() DialOption으로 전달합니다.

Python에서는 context.time_remaining()으로 남은 데드라인을 확인합니다. 재시도는 grpc의 서비스 설정을 JSON 문자열로 전달하거나, tenacity 같은 라이브러리로 래핑할 수 있지만, gRPC 네이티브 재시도가 서버 부하를 더 잘 고려하므로 우선 사용을 권장합니다.

Java/Kotlin에서는 Deadline.after(duration, TimeUnit)을 CallOptions에 추가합니다. ManagedChannelBuilder의 defaultServiceConfig()로 서비스 설정을 전달하며, enableRetry()를 명시적으로 호출해야 재시도가 활성화됩니다(기본 비활성).

Node.js/TypeScript에서는 deadline 옵션을 Date 객체 또는 밀리초 타임스탬프로 전달합니다. @grpc/grpc-js의 서비스 설정 지원은 다른 언어 대비 제한적이므로, grpc-retry 미들웨어나 자체 Interceptor 구현이 필요할 수 있습니다.

마무리: 복원력은 설계하는 것이다

gRPC의 데드라인, 재시도, 서킷 브레이커는 각각이 독립된 도구가 아니라, 함께 작동하여 시스템 복원력을 구성하는 방어 계층입니다. 데드라인은 무한 대기를 방지하고, 재시도는 일시적 실패를 투명하게 복구하며, 서킷 브레이커와 재시도 예산은 대규모 장애 시 retry storm을 억제합니다.

핵심을 다시 정리하면, 첫째 모든 RPC에 반드시 데드라인을 설정하고, 둘째 재시도는 멱등한 RPC에만 선별적으로 적용하며, 셋째 재시도 예산과 서킷 브레이커로 증폭을 방지하고, 넷째 모니터링 메트릭으로 지속적으로 튜닝합니다.

마이크로서비스의 복원력은 한 번 설정하고 잊는 것이 아니라, 트래픽 패턴과 시스템 변화에 맞춰 꾸준히 다듬어가는 과정입니다. 오늘 소개한 패턴들을 하나씩 적용하고, 실제 메트릭을 관찰하면서 여러분의 시스템에 최적화된 복원력 전략을 만들어가시길 바랍니다.

Photo by Asia Culture Center on Pexels


🔗 함께 보면 좋은 글

  • gRPC Proto 스키마 설계와 버전 관리 실전 가이드
  • gRPC 스트리밍 패턴 4가지 실전 구현 가이드
  • gRPC Interceptor 완벽 가이드: 인증부터 로깅까지

Tags:

gRPC데드라인마이크로서비스장애전파차단재시도정책
작성자

AICosmus

Follow Me
다른 기사
opencode MCP 서버 연동 개념 일러스트
Previous

[opencode 12일 집중 — 터미널 네이티브 AI 코딩 에이전트 완전 정복] 9/12화: opencode MCP 서버 연동 — 외부 도구·데이터 확장 실전 가이드

opencode 비대화형 자동화 모드 커버
Next

[opencode 12일 집중 — 터미널 네이티브 AI 코딩 에이전트 완전 정복] 10/12화: opencode serve·run 자동화 완전 가이드 — 헤드리스 AI 코딩

댓글 없음! 첫 댓글을 남겨보세요.

답글 남기기 응답 취소

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

최신 글

  • [opencode 시즌 2 심화 — 나만의 도메인 특화 에이전트 만들기] 1/12화: opencode 에이전트 아키텍처 완전 해부 — 2026 Primary·Subagent 5계층 구조
  • Kotlin 코루틴 핵심 5가지 개념과 실전 활용법
  • [opencode 12일 집중 — 터미널 네이티브 AI 코딩 에이전트 완전 정복] 12/12화: opencode 로컬 모델 완전 가이드 2026 — Ollama·에어갭·규제 환경 도입 체크리스트
  • LLM 파인튜닝 실전 5단계 — 2026 LoRA 완벽 가이드
  • 금융 앱 생체인증 작동 원리, 지문·얼굴 보안 5단계 완전 해부

최신 댓글

  1. [온프레미스 AI Assistant 아키텍처 — Qwen3·Qwen3-VL 14일 설계] 9/14화: 온프레미스 RAG 파이프라인 — bge-m3·Qdrant 자체 호스팅 실전의 Dockerfile 최적화 실전 가이드 — 빌드·크기·보안 총정리 - AICosmus
  2. RAG 평가 프레임워크, 답변 품질을 수치로 측정하는 법의 RAG 리랭킹 가이드, 검색 결과 정확도 높이는 법 - AICosmus
  3. RAG 평가 프레임워크, 답변 품질을 수치로 측정하는 법의 RAG 리랭킹 가이드, 검색 결과 정확도 높이는 법 - AICosmus
  4. gRPC Interceptor 완벽 가이드: 인증부터 로깅까지의 gRPC 데드라인과 재시도 정책으로 장애 전파 차단하기 - AICosmus
  5. gRPC Interceptor 완벽 가이드: 인증부터 로깅까지의 gRPC 데드라인과 재시도 정책으로 장애 전파 차단하기 - AICosmus
  • About
  • Contact
  • Disclaimer
  • Privacy - Policy
  • Terms of Service
Copyright 2026 — AICosmus. All rights reserved. Blogsy WordPress Theme