TL;DR

  • gRPC와 REST Callback (Webhook) - 서비스 간 통신 패턴 비교의 핵심 개념을 빠르게 파악할 수 있다.
  • 배경과 이유를 통해 왜 필요한지 맥락을 이해할 수 있다.
  • 특징과 상세 내용을 통해 실무 적용 포인트를 확인할 수 있다.

1. 개념

gRPC와 REST Callback (Webhook) - 서비스 간 통신 패턴 비교의 핵심 정의와 문제 공간을 간단히 정리한다.

2. 배경

이 주제가 등장한 기술적·조직적 배경과 기존 접근의 한계를 설명한다.

3. 이유

왜 지금 이 방식을 채택해야 하는지, 기대 효과와 트레이드오프를 함께 정리한다.

4. 특징

핵심 동작 방식, 장단점, 적용 시 주의점을 빠르게 훑을 수 있도록 요약한다.

5. 상세 내용

gRPC와 REST Callback (Webhook) - 서비스 간 통신 패턴 비교

작성일: 2026-02-26 카테고리: Backend / Communication / API Design 포함 내용: gRPC, REST Callback, Webhook, Protocol Buffers, HTTP/2, mTLS, HMAC, 마이크로서비스, 스트리밍, 비동기 통신


1. 탄생 배경

1.1 분산 시스템 통신의 진화

┌─────────────────────────────────────────────────────────────────┐
│                 분산 시스템 통신의 진화 타임라인                  │
│                                                                   │
│  1991  CORBA ──────── 복잡한 바이너리, 언어 독립 시도            │
│   │                                                               │
│  1998  SOAP ───────── XML 기반, WSDL 필수, 너무 무거움           │
│   │                                                               │
│  2000  REST ───────── HTTP 활용, 단순하고 직관적                 │
│   │                   → 웹 API의 사실상 표준이 됨                │
│   │                                                               │
│  2007  Webhook ────── Jeff Lindsay가 용어 제안                   │
│   │                   → 이벤트 기반 알림의 시작                  │
│   │                                                               │
│  2015  gRPC ──────── Google이 오픈소스화                         │
│                       → 마이크로서비스 시대의 고성능 통신        │
│                                                                   │
│  REST가 성공했지만 마이크로서비스 시대에 한계 드러남:            │
│  ├── 텍스트(JSON) 직렬화 → 바이너리 대비 느림                   │
│  ├── 스키마 강제 없음 → 서비스 간 계약 불명확                   │
│  ├── 단방향 통신 → 스트리밍 불가                                │
│  └── 폴링 기반 알림 → 리소스 낭비                               │
│                                                                   │
│  이 한계를 해결하기 위해 두 가지 방향이 등장:                    │
│  ├── 동기 고성능 통신: gRPC (HTTP/2 + Protocol Buffers)         │
│  └── 비동기 이벤트 알림: REST Callback (Webhook)                │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

1.2 gRPC의 탄생 (Google, 2015)

┌─────────────────────────────────────────────────────────────────┐
│                   gRPC의 탄생 배경                               │
│                                                                   │
│  Google 내부 시스템 "Stubby" (2001~):                            │
│  ├── Google 내부 모든 마이크로서비스 간 통신에 사용              │
│  ├── 초당 수십억 건의 RPC 호출 처리                              │
│  ├── 10년 넘게 실전 검증                                         │
│  └── 하지만 비공개, Google 인프라에 강하게 결합                  │
│                                                                   │
│  2015년, Google이 Stubby를 오픈소스화 → gRPC 탄생               │
│  ├── g = gRPC (재귀 약어, 또는 Google)                           │
│  ├── HTTP/2 기반 (Stubby는 자체 프로토콜)                        │
│  ├── Protocol Buffers (protobuf) 직렬화                          │
│  └── 2017년 CNCF (Cloud Native Computing Foundation) 편입        │
│                                                                   │
│  왜 만들었나?                                                    │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  REST의 한계          →  gRPC의 해결                     │    │
│  │  ─────────────────────────────────────────────────       │    │
│  │  JSON 텍스트 직렬화   →  Protocol Buffers 바이너리       │    │
│  │  스키마 부재           →  .proto 파일 강타입 계약         │    │
│  │  단방향 요청-응답      →  양방향 스트리밍                 │    │
│  │  HTTP/1.1 제약        →  HTTP/2 멀티플렉싱               │    │
│  │  수동 클라이언트 코드  →  protoc 자동 코드 생성           │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

1.3 REST Callback (Webhook)의 탄생

┌─────────────────────────────────────────────────────────────────┐
│                REST Callback (Webhook)의 탄생                    │
│                                                                   │
│  2007년, Jeff Lindsay가 "Webhook" 용어를 처음 제안              │
│  "웹의 파이프(pipe)를 만들자 - 서버가 서버에게 알려주자"        │
│                                                                   │
│  대중화 과정:                                                    │
│  ├── 2010  GitHub → push 이벤트 Webhook 지원                    │
│  ├── 2012  Stripe → 결제 이벤트 Webhook                         │
│  ├── 2014  Slack  → 봇/통합 Webhook                             │
│  └── 현재  거의 모든 SaaS가 Webhook 지원                        │
│                                                                   │
│  왜 만들었나?                                                    │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  ❌ 폴링 (Polling) 방식:                                │    │
│  │                                                          │    │
│  │  Client ──► "새 데이터 있어?" ──► Server                │    │
│  │  Client ◄── "없어"              ◄── Server              │    │
│  │  Client ──► "지금은?"           ──► Server              │    │
│  │  Client ◄── "아직 없어"         ◄── Server              │    │
│  │  Client ──► "지금은??"          ──► Server              │    │
│  │  Client ◄── "있어! 여기"        ◄── Server              │    │
│  │                                                          │    │
│  │  → 99%의 요청이 "없어"... 리소스 낭비!                  │    │
│  │                                                          │    │
│  │  ✅ Webhook (Callback) 방식:                             │    │
│  │                                                          │    │
│  │  Client ──► "변화 생기면 이 URL로 알려줘" ──► Server    │    │
│  │  (등록)                                                  │    │
│  │                                                          │    │
│  │  ... (시간 경과, Client는 다른 일 함) ...               │    │
│  │                                                          │    │
│  │  Client ◄── "이벤트 발생! POST 전송" ◄── Server        │    │
│  │                                                          │    │
│  │  → 이벤트 있을 때만 알려줌. 효율적!                     │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

2. 핵심 개념

2.1 gRPC란?

┌─────────────────────────────────────────────────────────────────┐
│                       gRPC란?                                    │
│                                                                   │
│  gRPC = Google Remote Procedure Call                             │
│       = 원격 함수를 마치 로컬 함수처럼 호출하는 프레임워크      │
│                                                                   │
│  구성 요소:                                                      │
│  ├── .proto 파일: 서비스와 메시지 구조 정의                      │
│  ├── protoc 컴파일러: .proto → 각 언어 코드 자동 생성           │
│  ├── HTTP/2: 전송 프로토콜 (멀티플렉싱, 헤더 압축)             │
│  └── Protocol Buffers: 바이너리 직렬화 (JSON 대비 ~10배 빠름)  │
│                                                                   │
│  .proto 파일 예시:                                               │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  syntax = "proto3";                                      │    │
│  │                                                          │    │
│  │  package order;                                          │    │
│  │                                                          │    │
│  │  service OrderService {                                  │    │
│  │    // Unary: 단일 요청 → 단일 응답                      │    │
│  │    rpc GetOrder (OrderRequest)                           │    │
│  │        returns (OrderResponse);                          │    │
│  │                                                          │    │
│  │    // Server Streaming: 단일 요청 → 응답 스트림         │    │
│  │    rpc ListOrders (ListRequest)                          │    │
│  │        returns (stream OrderResponse);                   │    │
│  │                                                          │    │
│  │    // Client Streaming: 요청 스트림 → 단일 응답         │    │
│  │    rpc BatchCreate (stream CreateRequest)                │    │
│  │        returns (BatchResponse);                          │    │
│  │                                                          │    │
│  │    // Bidirectional: 양방향 스트림                       │    │
│  │    rpc OrderChat (stream ChatMessage)                    │    │
│  │        returns (stream ChatMessage);                     │    │
│  │  }                                                       │    │
│  │                                                          │    │
│  │  message OrderRequest {                                  │    │
│  │    int64 order_id = 1;                                   │    │
│  │  }                                                       │    │
│  │                                                          │    │
│  │  message OrderResponse {                                 │    │
│  │    int64 order_id = 1;                                   │    │
│  │    string status = 2;                                    │    │
│  │    int32 total_amount = 3;                               │    │
│  │    repeated Item items = 4;                              │    │
│  │  }                                                       │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  4가지 통신 패턴:                                                │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  1. Unary (단일):                                       │    │
│  │     Client ──[요청]──► Server                           │    │
│  │     Client ◄──[응답]── Server                           │    │
│  │     → REST와 유사, 가장 기본                            │    │
│  │                                                          │    │
│  │  2. Server Streaming (서버 스트리밍):                    │    │
│  │     Client ──[요청]──► Server                           │    │
│  │     Client ◄──[응답1]── Server                          │    │
│  │     Client ◄──[응답2]── Server                          │    │
│  │     Client ◄──[응답N]── Server                          │    │
│  │     → 실시간 피드, 대량 데이터 전송                     │    │
│  │                                                          │    │
│  │  3. Client Streaming (클라이언트 스트리밍):              │    │
│  │     Client ──[요청1]──► Server                          │    │
│  │     Client ──[요청2]──► Server                          │    │
│  │     Client ──[요청N]──► Server                          │    │
│  │     Client ◄──[응답]── Server                           │    │
│  │     → 파일 업로드, 센서 데이터 수집                     │    │
│  │                                                          │    │
│  │  4. Bidirectional Streaming (양방향 스트리밍):           │    │
│  │     Client ──[요청1]──► Server                          │    │
│  │     Client ◄──[응답1]── Server                          │    │
│  │     Client ──[요청2]──► Server                          │    │
│  │     Client ◄──[응답2]── Server                          │    │
│  │     → 채팅, 실시간 게임, 양방향 데이터 교환             │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

2.2 REST Callback (Webhook)이란?

┌─────────────────────────────────────────────────────────────────┐
│                  REST Callback (Webhook)이란?                     │
│                                                                   │
│  Webhook = "역방향 API"                                          │
│  일반 API: 클라이언트가 서버에게 데이터 요청                     │
│  Webhook:  서버가 클라이언트에게 이벤트 알려줌                   │
│                                                                   │
│  핵심 구조:                                                      │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  1) 등록 단계:                                          │    │
│  │     수신자 ──► "이 URL로 알려줘" ──► 발신자              │    │
│  │     POST /webhooks                                       │    │
│  │     {                                                    │    │
│  │       "url": "https://my-app.com/webhook/payment",      │    │
│  │       "events": ["payment.completed", "payment.failed"] │    │
│  │     }                                                    │    │
│  │                                                          │    │
│  │  2) 이벤트 발생 시:                                     │    │
│  │     발신자 ──► HTTP POST ──► 수신자 등록 URL             │    │
│  │     POST https://my-app.com/webhook/payment              │    │
│  │     {                                                    │    │
│  │       "event": "payment.completed",                     │    │
│  │       "data": {                                          │    │
│  │         "payment_id": "pay_abc123",                     │    │
│  │         "amount": 50000,                                │    │
│  │         "currency": "KRW"                               │    │
│  │       },                                                │    │
│  │       "timestamp": "2026-02-26T10:30:00Z"               │    │
│  │     }                                                    │    │
│  │                                                          │    │
│  │  3) 수신자 응답:                                        │    │
│  │     200 OK → 정상 수신 확인                             │    │
│  │     5xx    → 실패, 발신자가 재시도                      │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  실제 사용 사례:                                                 │
│  ├── GitHub: push, PR, issue 이벤트 알림                        │
│  ├── Stripe: 결제 완료, 환불, 구독 변경 알림                    │
│  ├── Slack: 메시지 이벤트, 봇 상호작용                          │
│  └── AWS SNS: 클라우드 이벤트 HTTP 구독                         │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

3. 동작 원리 비교

3.1 gRPC 통신 흐름

┌─────────────────────────────────────────────────────────────────┐
│                    gRPC 통신 흐름 상세                            │
│                                                                   │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  [Client Application]                                   │    │
│  │       │                                                  │    │
│  │       │ orderService.getOrder(request)                   │    │
│  │       ▼                                                  │    │
│  │  [Generated Stub] ← protoc이 자동 생성한 코드           │    │
│  │       │                                                  │    │
│  │       │ Protocol Buffers 직렬화 (객체 → 바이너리)       │    │
│  │       ▼                                                  │    │
│  │  [Channel] ← HTTP/2 연결 관리 (연결 풀링, 멀티플렉싱)  │    │
│  │       │                                                  │    │
│  │       │ HTTP/2 프레임으로 전송                           │    │
│  │       ▼                                                  │    │
│  │  ═══════════ 네트워크 (HTTP/2 + TLS) ════════════       │    │
│  │       │                                                  │    │
│  │       ▼                                                  │    │
│  │  [Server Interceptor] ← 인증, 로깅, 메트릭              │    │
│  │       │                                                  │    │
│  │       │ Protocol Buffers 역직렬화 (바이너리 → 객체)     │    │
│  │       ▼                                                  │    │
│  │  [Service Implementation] ← 실제 비즈니스 로직          │    │
│  │       │                                                  │    │
│  │       │ 응답 생성 → 직렬화 → 역순으로 전송              │    │
│  │       ▼                                                  │    │
│  │  [Client]가 응답 수신                                    │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  핵심 특징:                                                      │
│  ├── 하나의 TCP 연결에 여러 RPC 동시 처리 (멀티플렉싱)         │
│  ├── 바이너리 직렬화로 JSON 대비 페이로드 크기 ~60% 감소       │
│  ├── 헤더 압축 (HPACK)으로 반복 헤더 최소화                    │
│  └── Deadline/Timeout 내장: 요청별 제한 시간 설정              │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

3.2 REST Callback 통신 흐름

┌─────────────────────────────────────────────────────────────────┐
│                 REST Callback (Webhook) 통신 흐름                │
│                                                                   │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  [단계 1: Webhook 등록]                                  │    │
│  │  수신자 ──► POST /webhooks ──► 발신자(Provider)         │    │
│  │            {url, events, secret}                         │    │
│  │  수신자 ◄── 201 Created     ◄── 발신자                  │    │
│  │            {webhook_id, status: "active"}                │    │
│  │                                                          │    │
│  │  [단계 2: 이벤트 발생 감지]                              │    │
│  │  발신자 내부에서 이벤트 발생                             │    │
│  │  (예: 결제 완료, 코드 push, 주문 상태 변경)             │    │
│  │                                                          │    │
│  │  [단계 3: Webhook 전송]                                  │    │
│  │  발신자 ──► POST (수신자 URL) ──► 수신자                │    │
│  │  Headers:                                                │    │
│  │    Content-Type: application/json                        │    │
│  │    X-Webhook-Signature: sha256=abc123...                 │    │
│  │    X-Webhook-ID: evt_12345                               │    │
│  │  Body: {event, data, timestamp}                          │    │
│  │                                                          │    │
│  │  [단계 4: 수신자 처리 및 응답]                           │    │
│  │  수신자 ──► 200 OK ──► 발신자                           │    │
│  │  (5초 이내 응답 권장)                                    │    │
│  │                                                          │    │
│  │  [단계 5: 실패 시 재시도]                                │    │
│  │  수신자가 5xx 또는 timeout이면:                          │    │
│  │  ├── 1차 재시도: 1분 후                                 │    │
│  │  ├── 2차 재시도: 5분 후                                 │    │
│  │  ├── 3차 재시도: 30분 후                                │    │
│  │  ├── 4차 재시도: 2시간 후                               │    │
│  │  └── 최종 실패: 알림 또는 Webhook 비활성화              │    │
│  │  (Exponential Backoff 패턴)                              │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  주의 사항:                                                      │
│  ├── 수신 측은 반드시 public URL 필요 (방화벽 뒤면 안 됨)      │
│  ├── 멱등성 처리 필수 (같은 이벤트 중복 수신 가능)             │
│  ├── Webhook ID로 중복 감지                                     │
│  └── 빠른 응답 후 비동기 처리 권장 (큐에 넣고 200 반환)        │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

4. 상세 비교표

┌─────────────────────────────────────────────────────────────────┐
│              gRPC vs REST Callback 상세 비교                     │
│                                                                   │
│  ┌────────────┬─────────────────┬─────────────────────────┐    │
│  │ 항목        │ gRPC             │ REST Callback           │    │
│  ├────────────┼─────────────────┼─────────────────────────┤    │
│  │ 프로토콜   │ HTTP/2            │ HTTP/1.1 (주로)         │    │
│  ├────────────┼─────────────────┼─────────────────────────┤    │
│  │ 데이터형식 │ Protocol Buffers  │ JSON (텍스트)           │    │
│  │            │ (바이너리)        │                         │    │
│  ├────────────┼─────────────────┼─────────────────────────┤    │
│  │ 통신방향   │ 양방향 스트리밍   │ 단방향                  │    │
│  │            │                   │ (서버→클라이언트)       │    │
│  ├────────────┼─────────────────┼─────────────────────────┤    │
│  │ 통신패턴   │ 동기              │ 비동기                  │    │
│  │            │ (요청-응답)       │ (이벤트 기반)           │    │
│  ├────────────┼─────────────────┼─────────────────────────┤    │
│  │ 스키마     │ .proto (강타입)   │ 자유 형식               │    │
│  │            │                   │ (OpenAPI 선택적)        │    │
│  ├────────────┼─────────────────┼─────────────────────────┤    │
│  │ 성능       │ 높음              │ 보통                    │    │
│  │            │ (바이너리,        │ (텍스트,                │    │
│  │            │  멀티플렉싱)      │  연결당 1요청)          │    │
│  ├────────────┼─────────────────┼─────────────────────────┤    │
│  │ 코드 생성  │ 자동 (protoc)     │ 수동 또는               │    │
│  │            │ 11개 언어 지원    │ OpenAPI codegen         │    │
│  ├────────────┼─────────────────┼─────────────────────────┤    │
│  │ 브라우저   │ 제한적            │ 완전 지원               │    │
│  │            │ (gRPC-Web 필요)  │                         │    │
│  ├────────────┼─────────────────┼─────────────────────────┤    │
│  │ 디버깅     │ 어려움            │ 쉬움                    │    │
│  │            │ (바이너리)        │ (JSON 가독성)           │    │
│  ├────────────┼─────────────────┼─────────────────────────┤    │
│  │ 연결 모델  │ 지속적            │ 일회성                  │    │
│  │            │ (Long-lived)      │ (이벤트마다 새 연결)    │    │
│  ├────────────┼─────────────────┼─────────────────────────┤    │
│  │ 결합도     │ 강한 결합         │ 느슨한 결합             │    │
│  │            │ (.proto 공유)     │ (URL만 알면 됨)         │    │
│  ├────────────┼─────────────────┼─────────────────────────┤    │
│  │ 적합한     │ 내부 서비스 간    │ 외부 시스템 알림        │    │
│  │ 상황       │ 고성능 동기 통신  │ 이벤트 기반 통지        │    │
│  └────────────┴─────────────────┴─────────────────────────┘    │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

5. 장단점

5.1 gRPC 장점/단점

┌─────────────────────────────────────────────────────────────────┐
│                     gRPC 장점/단점                                │
│                                                                   │
│  ✅ 장점:                                                        │
│  ├── 높은 성능                                                   │
│  │   ├── Protocol Buffers: JSON 대비 직렬화 ~10배 빠름          │
│  │   ├── 페이로드 크기 ~60% 감소                                │
│  │   └── HTTP/2 멀티플렉싱: 하나의 연결에 다중 요청             │
│  │                                                               │
│  ├── 강타입 계약 (.proto)                                        │
│  │   ├── 컴파일 타임에 타입 오류 감지                            │
│  │   ├── Breaking change 자동 감지                               │
│  │   └── 서비스 간 명확한 인터페이스 계약                        │
│  │                                                               │
│  ├── 양방향 스트리밍                                             │
│  │   ├── 실시간 데이터 전송 가능                                 │
│  │   └── 채팅, 모니터링, IoT에 적합                              │
│  │                                                               │
│  ├── 코드 자동 생성                                              │
│  │   ├── protoc으로 11개 언어 클라이언트/서버 코드 생성          │
│  │   └── Java, Go, Python, C++, Kotlin, Swift 등                 │
│  │                                                               │
│  └── 내장 Deadline/Timeout                                       │
│      └── 요청별 제한 시간 설정으로 장애 전파 방지                │
│                                                                   │
│  ❌ 단점:                                                        │
│  ├── 브라우저 직접 지원 불가                                     │
│  │   └── gRPC-Web 또는 Envoy 프록시 필요                        │
│  │                                                               │
│  ├── 바이너리라서 디버깅 어려움                                  │
│  │   ├── curl로 바로 테스트 불가                                 │
│  │   └── grpcurl, Postman gRPC 등 별도 도구 필요                │
│  │                                                               │
│  ├── HTTP/2 필수                                                 │
│  │   ├── 일부 프록시/로드밸런서가 HTTP/2 미지원                  │
│  │   └── AWS ALB는 gRPC 지원하지만 설정 필요                    │
│  │                                                               │
│  ├── 학습 곡선                                                   │
│  │   ├── Protocol Buffers 문법 학습 필요                         │
│  │   └── 빌드 파이프라인에 protoc 통합 필요                     │
│  │                                                               │
│  └── REST 대비 작은 생태계                                       │
│      └── 도구, 문서, 커뮤니티가 REST보다 적음                   │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

5.2 REST Callback (Webhook) 장점/단점

┌─────────────────────────────────────────────────────────────────┐
│                REST Callback (Webhook) 장점/단점                 │
│                                                                   │
│  ✅ 장점:                                                        │
│  ├── 구현 간단                                                   │
│  │   ├── HTTP POST + JSON만 있으면 됨                            │
│  │   ├── 어떤 언어/프레임워크든 쉽게 구현                       │
│  │   └── curl로 테스트 가능                                      │
│  │                                                               │
│  ├── 표준 HTTP → 인프라 친화적                                   │
│  │   ├── 방화벽, 프록시, CDN 모두 통과                           │
│  │   └── 별도 프로토콜 지원 불필요                               │
│  │                                                               │
│  ├── 디버깅 쉬움                                                 │
│  │   ├── JSON 페이로드 사람이 읽기 쉬움                          │
│  │   └── 웹 브라우저, Postman 등으로 확인 가능                   │
│  │                                                               │
│  ├── 기존 인프라 활용                                            │
│  │   └── 웹 서버만 있으면 수신 가능                              │
│  │                                                               │
│  └── 폴링 대비 효율적                                            │
│      ├── 이벤트 발생 시에만 네트워크 사용                        │
│      └── 불필요한 요청 제거                                      │
│                                                                   │
│  ❌ 단점:                                                        │
│  ├── 수신 측이 public endpoint 필요                              │
│  │   ├── NAT 뒤, localhost에서 수신 불가                         │
│  │   └── 개발 시 ngrok 등 터널링 도구 필요                      │
│  │                                                               │
│  ├── 전달 보장 어려움 (at-least-once)                            │
│  │   ├── 네트워크 장애 시 메시지 유실 가능                       │
│  │   └── 재시도 시 중복 수신 가능 → 멱등성 처리 필수            │
│  │                                                               │
│  ├── 순서 보장 없음                                              │
│  │   ├── 이벤트 발생 순서와 수신 순서가 다를 수 있음             │
│  │   └── 재시도로 인해 순서 역전 가능                            │
│  │                                                               │
│  ├── 수신 측 장애 시 메시지 유실 가능                            │
│  │   ├── 재시도 횟수 초과 시 영구 유실                           │
│  │   └── Dead Letter Queue 등 별도 대비 필요                    │
│  │                                                               │
│  └── 스키마 강제 없음                                            │
│      ├── 발신자가 페이로드 구조 변경 가능                        │
│      └── 버전 관리를 수동으로 해야 함                            │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

6. 신뢰할 수 있는 통신 - 상호 인증과 보안

6.1 gRPC의 신뢰 기반 통신

┌─────────────────────────────────────────────────────────────────┐
│                 gRPC의 신뢰 기반 통신                             │
│                                                                   │
│  gRPC는 3가지 보안 메커니즘을 제공:                              │
│  ├── 1. mTLS (Mutual TLS) - 가장 일반적                         │
│  ├── 2. Token 기반 인증 (JWT, OAuth2)                            │
│  └── 3. Channel/Call Credentials 결합                            │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

mTLS (Mutual TLS)

┌─────────────────────────────────────────────────────────────────┐
│               mTLS (Mutual TLS) - 상호 인증서 검증               │
│                                                                   │
│  일반 TLS vs mTLS:                                               │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  일반 TLS (한쪽만 검증):                                │    │
│  │  Client ──► "너 진짜 서버 맞아?" ──► Server             │    │
│  │  Client ◄── "여기 내 인증서"       ◄── Server           │    │
│  │  Client: "OK, 믿을게" → 통신 시작                       │    │
│  │  → 서버만 검증, 클라이언트는 누구든 접속 가능           │    │
│  │                                                          │    │
│  │  mTLS (양쪽 모두 검증):                                 │    │
│  │  Client ──► "너 진짜 서버 맞아?" ──► Server             │    │
│  │  Client ◄── "내 인증서, 너 인증서도 줘" ◄── Server     │    │
│  │  Client ──► "여기 내 인증서"      ──► Server            │    │
│  │  양쪽 모두 검증 완료 → 통신 시작                        │    │
│  │  → 서버도 클라이언트도 서로 신원 확인!                  │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  mTLS Handshake 과정:                                            │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  [1] Client → Server: ClientHello                        │    │
│  │      (지원 TLS 버전, 암호화 목록)                        │    │
│  │                                                          │    │
│  │  [2] Server → Client: ServerHello                        │    │
│  │      + Server Certificate (서버 인증서)                  │    │
│  │      + CertificateRequest (클라이언트 인증서 요청)      │    │
│  │                                                          │    │
│  │  [3] Client: 서버 인증서를 CA로 검증                    │    │
│  │                                                          │    │
│  │  [4] Client → Server: Client Certificate                 │    │
│  │      (클라이언트 인증서 제시)                            │    │
│  │                                                          │    │
│  │  [5] Server: 클라이언트 인증서를 CA로 검증              │    │
│  │                                                          │    │
│  │  [6] 양쪽 검증 완료 → 암호화된 채널 생성               │    │
│  │      모든 gRPC 메시지가 이 채널로 전송                  │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  Kubernetes에서의 mTLS:                                          │
│  ├── Istio (Service Mesh): 자동으로 Pod 간 mTLS 주입            │
│  │   └── 애플리케이션 코드 수정 없이 sidecar proxy가 처리       │
│  ├── Linkerd: 마찬가지로 자동 mTLS                               │
│  └── 인증서 갱신도 자동 (cert-manager 등)                        │
│                                                                   │
│  장점:                                                           │
│  ├── 양쪽 모두 신원 확인 → 스푸핑 방지                          │
│  ├── 통신 전체 암호화 → 도청 불가                               │
│  └── Service Mesh와 결합 시 무설정(Zero-config)                  │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

Token 기반 인증 및 Channel 수준 보안

┌─────────────────────────────────────────────────────────────────┐
│            gRPC Token 기반 인증 & Channel 보안                    │
│                                                                   │
│  Token 기반 인증:                                                │
│  ├── JWT 또는 OAuth2 토큰을 gRPC Metadata(헤더)에 포함          │
│  ├── Server Interceptor에서 매 요청마다 토큰 검증               │
│  └── Call Credentials API로 자동 토큰 주입                      │
│                                                                   │
│  Channel 수준 보안 체계:                                         │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  ChannelCredentials (채널 수준):                         │    │
│  │  └── TLS 채널 설정 (암호화, 서버 인증서 검증)           │    │
│  │                                                          │    │
│  │  CallCredentials (요청 수준):                            │    │
│  │  └── 매 요청마다 인증 정보 첨부 (JWT, OAuth Token)      │    │
│  │                                                          │    │
│  │  CompositeCredentials (결합):                            │    │
│  │  └── ChannelCredentials + CallCredentials 동시 적용      │    │
│  │  └── TLS로 채널 암호화 + JWT로 요청 인증                │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  Kotlin 구현 예시 (서버 측 Interceptor):                         │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  class AuthInterceptor : ServerInterceptor {             │    │
│  │                                                          │    │
│  │    override fun <Req, Resp> interceptCall(               │    │
│  │      call: ServerCall<Req, Resp>,                        │    │
│  │      headers: Metadata,                                  │    │
│  │      next: ServerCallHandler<Req, Resp>                  │    │
│  │    ): ServerCall.Listener<Req> {                         │    │
│  │                                                          │    │
│  │      val token = headers.get(                            │    │
│  │        Metadata.Key.of("authorization",                  │    │
│  │          Metadata.ASCII_STRING_MARSHALLER)                │    │
│  │      )                                                   │    │
│  │                                                          │    │
│  │      if (token == null || !validateJwt(token)) {         │    │
│  │        call.close(                                       │    │
│  │          Status.UNAUTHENTICATED                          │    │
│  │            .withDescription("Invalid token"),            │    │
│  │          Metadata()                                      │    │
│  │        )                                                 │    │
│  │        return object : ServerCall.Listener<Req>() {}     │    │
│  │      }                                                   │    │
│  │                                                          │    │
│  │      return next.startCall(call, headers)                │    │
│  │    }                                                     │    │
│  │  }                                                       │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  Kotlin 구현 예시 (클라이언트 측 mTLS + Token):                  │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  // TLS 채널 생성 (mTLS)                                │    │
│  │  val channelCreds = TlsChannelCredentials.newBuilder()   │    │
│  │    .keyManager(clientCert, clientKey)  // 클라이언트 인증│    │
│  │    .trustManager(caCert)              // CA 인증서       │    │
│  │    .build()                                              │    │
│  │                                                          │    │
│  │  // 요청별 JWT 토큰 첨부                                │    │
│  │  val callCreds = CallCredentials { applier ->            │    │
│  │    val headers = Metadata()                              │    │
│  │    headers.put(authKey, "Bearer $jwtToken")              │    │
│  │    applier.apply(headers)                                │    │
│  │  }                                                       │    │
│  │                                                          │    │
│  │  // 채널 + 토큰 결합                                    │    │
│  │  val channel = Grpc.newChannelBuilder(                   │    │
│  │    "order-service:50051", channelCreds                   │    │
│  │  ).build()                                               │    │
│  │                                                          │    │
│  │  val stub = OrderServiceGrpc.newBlockingStub(channel)    │    │
│  │    .withCallCredentials(callCreds)                       │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

6.2 REST Callback (Webhook)의 신뢰 기반 통신

HMAC 서명 검증

┌─────────────────────────────────────────────────────────────────┐
│          HMAC 서명 검증 - Webhook 보안의 핵심                    │
│                                                                   │
│  가장 널리 쓰이는 Webhook 보안 방식                              │
│  GitHub, Stripe, Slack 등이 채택                                 │
│                                                                   │
│  원리:                                                           │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  [사전 준비]                                            │    │
│  │  발신자와 수신자가 Secret Key를 공유                    │    │
│  │  (Webhook 등록 시 생성, 예: whsec_abc123...)            │    │
│  │                                                          │    │
│  │  [전송 시 - 발신자]                                     │    │
│  │  1. JSON payload 준비                                   │    │
│  │  2. HMAC-SHA256(secret, payload) → 서명 생성            │    │
│  │  3. 서명을 헤더에 포함하여 전송                         │    │
│  │                                                          │    │
│  │  POST https://my-app.com/webhook                        │    │
│  │  X-Hub-Signature-256: sha256=a1b2c3d4e5f6...           │    │
│  │  Content-Type: application/json                         │    │
│  │  {"event": "push", "ref": "refs/heads/main", ...}      │    │
│  │                                                          │    │
│  │  [수신 시 - 수신자]                                     │    │
│  │  1. 요청 body(payload) 추출                             │    │
│  │  2. 같은 Secret으로 HMAC-SHA256 재계산                  │    │
│  │  3. 헤더의 서명과 비교                                  │    │
│  │  4. 일치 → 신뢰, 불일치 → 거부 (403)                  │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  GitHub Webhook 서명 검증 (Kotlin):                              │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  fun verifyGitHubSignature(                              │    │
│  │    payload: String,                                      │    │
│  │    signatureHeader: String,  // "sha256=abc..."         │    │
│  │    secret: String                                        │    │
│  │  ): Boolean {                                            │    │
│  │    val mac = Mac.getInstance("HmacSHA256")               │    │
│  │    mac.init(SecretKeySpec(                                │    │
│  │      secret.toByteArray(), "HmacSHA256"                  │    │
│  │    ))                                                    │    │
│  │    val computed = "sha256=" + mac                        │    │
│  │      .doFinal(payload.toByteArray())                     │    │
│  │      .joinToString("") { "%02x".format(it) }            │    │
│  │                                                          │    │
│  │    // Timing-safe 비교 (타이밍 공격 방지)               │    │
│  │    return MessageDigest.isEqual(                          │    │
│  │      computed.toByteArray(),                              │    │
│  │      signatureHeader.toByteArray()                       │    │
│  │    )                                                     │    │
│  │  }                                                       │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  왜 HMAC인가?                                                    │
│  ├── Secret을 모르면 서명 위조 불가                              │
│  ├── payload가 변조되면 서명 불일치                              │
│  └── 발신자 신원 + 메시지 무결성 동시 보장                      │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

Webhook Secret + Timestamp (Replay Attack 방지)

┌─────────────────────────────────────────────────────────────────┐
│           Timestamp 기반 Replay Attack 방지                      │
│                                                                   │
│  HMAC만으로는 부족한 이유:                                       │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  ❌ Replay Attack (재전송 공격):                         │    │
│  │  1. 공격자가 정상 Webhook 요청을 네트워크에서 캡처      │    │
│  │  2. 동일 요청을 나중에 그대로 재전송                    │    │
│  │  3. 서명이 유효하므로 수신자가 수락!                    │    │
│  │  → 결제 Webhook이면 이중 결제 처리 위험                 │    │
│  │                                                          │    │
│  │  ✅ Timestamp + HMAC으로 방지:                           │    │
│  │  1. 서명에 타임스탬프 포함                              │    │
│  │  2. 수신자가 현재 시각과 비교                           │    │
│  │  3. 5분 이상 지난 요청은 거부                           │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  Stripe 방식 (v1 서명 스킴):                                     │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  서명 대상 = "{timestamp}.{payload}"                    │    │
│  │                                                          │    │
│  │  Stripe-Signature 헤더:                                 │    │
│  │  t=1708934400,                                          │    │
│  │  v1=5257a869e7ecebeda32affa62cdca3fa51c...,             │    │
│  │  v0=6ffbb59b2300aae63f272406069a9788598b...             │    │
│  │                                                          │    │
│  │  수신자 검증 로직:                                      │    │
│  │  1. t (타임스탬프) 추출                                 │    │
│  │  2. 현재 시각 - t > 300초면 거부 (5분 초과)             │    │
│  │  3. signed_payload = "{t}.{body}" 구성                  │    │
│  │  4. HMAC-SHA256(secret, signed_payload) 계산            │    │
│  │  5. v1 값과 비교                                        │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  Kotlin 구현 예시 (Stripe 방식):                                 │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  fun verifyStripeWebhook(                                │    │
│  │    payload: String,                                      │    │
│  │    sigHeader: String,                                    │    │
│  │    secret: String,                                       │    │
│  │    tolerance: Long = 300  // 5분                         │    │
│  │  ): Boolean {                                            │    │
│  │    val parts = sigHeader.split(",")                      │    │
│  │      .associate {                                        │    │
│  │        val (k, v) = it.split("=", limit = 2)            │    │
│  │        k.trim() to v.trim()                              │    │
│  │      }                                                   │    │
│  │                                                          │    │
│  │    val timestamp = parts["t"]?.toLongOrNull()            │    │
│  │      ?: return false                                     │    │
│  │                                                          │    │
│  │    // Replay attack 방지: 5분 초과 거부                  │    │
│  │    val now = Instant.now().epochSecond                    │    │
│  │    if (abs(now - timestamp) > tolerance)                  │    │
│  │      return false                                        │    │
│  │                                                          │    │
│  │    // 서명 검증                                         │    │
│  │    val signedPayload = "$timestamp.$payload"             │    │
│  │    val mac = Mac.getInstance("HmacSHA256")               │    │
│  │    mac.init(SecretKeySpec(                                │    │
│  │      secret.toByteArray(), "HmacSHA256"))                │    │
│  │    val expected = mac.doFinal(                            │    │
│  │      signedPayload.toByteArray()                         │    │
│  │    ).toHex()                                             │    │
│  │                                                          │    │
│  │    return MessageDigest.isEqual(                          │    │
│  │      expected.toByteArray(),                              │    │
│  │      (parts["v1"] ?: "").toByteArray()                   │    │
│  │    )                                                     │    │
│  │  }                                                       │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

기타 Webhook 보안 방식

┌─────────────────────────────────────────────────────────────────┐
│              기타 REST Callback 보안 방식                         │
│                                                                   │
│  1. mTLS (양방향 TLS):                                           │
│  ├── REST Callback에서도 사용 가능                               │
│  ├── 발신자가 수신자 URL 호출 시 양쪽 인증서 교환               │
│  ├── 가장 강력하지만 설정 복잡                                   │
│  └── 수신자가 클라이언트 인증서 관리해야 함                     │
│                                                                   │
│  2. IP Whitelist (IP 허용 목록):                                 │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  수신자 방화벽/리버스 프록시 설정:                       │    │
│  │  allow 192.30.252.0/22;    # GitHub Webhook IP 대역     │    │
│  │  allow 140.82.112.0/20;    # GitHub Webhook IP 대역     │    │
│  │  deny all;                                               │    │
│  │                                                          │    │
│  │  장점: 단순, 네트워크 수준 차단                         │    │
│  │  단점: IP 변경 시 수동 업데이트, CDN 사용 시 복잡       │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  3. OAuth2 Bearer Token:                                         │
│  ├── Webhook 등록 시 수신자가 Bearer Token 발급               │
│  ├── 발신자가 콜백 요청 시 Authorization 헤더에 포함             │
│  ├── 수신자가 토큰 유효성 검증                                   │
│  └── 토큰 만료/갱신 관리 필요                                    │
│                                                                   │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  발신자 → 수신자 Webhook 전송:                          │    │
│  │  POST /webhook/payment                                   │    │
│  │  Authorization: Bearer eyJhbGciOiJIUzI1NiI...           │    │
│  │  Content-Type: application/json                          │    │
│  │  {"event": "payment.completed", ...}                    │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  권장 조합 (Defense in Depth):                                   │
│  ├── HMAC 서명 + Timestamp (필수)                                │
│  ├── IP Whitelist (추가 보안)                                    │
│  └── HTTPS 필수 (전송 구간 암호화)                               │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

6.3 보안 비교 다이어그램 및 요약표

┌─────────────────────────────────────────────────────────────────┐
│         gRPC mTLS vs Webhook HMAC 서명 흐름 비교                 │
│                                                                   │
│  [gRPC mTLS 흐름]                                                │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  Client                           Server                │    │
│  │    │                                 │                   │    │
│  │    │── ClientHello ────────────────►│                   │    │
│  │    │◄── ServerHello + ServerCert ───│                   │    │
│  │    │    + CertificateRequest        │                   │    │
│  │    │── ClientCert ─────────────────►│                   │    │
│  │    │   (상호 인증서 검증 완료)       │                   │    │
│  │    │◄══ 암호화된 gRPC 채널 수립 ═══►│                   │    │
│  │    │── RPC Call (바이너리) ────────►│                   │    │
│  │    │◄── RPC Response ──────────────│                   │    │
│  │    │                                 │                   │    │
│  │  → 채널 수립 후 모든 통신이 암호화됨                    │    │
│  │  → 인증은 연결 시 1회, 이후 자동 적용                   │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  [Webhook HMAC 서명 흐름]                                        │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  발신자(Provider)                  수신자(Consumer)      │    │
│  │    │                                 │                   │    │
│  │    │  [이벤트 발생]                  │                   │    │
│  │    │  1. payload 생성                │                   │    │
│  │    │  2. HMAC-SHA256(secret,         │                   │    │
│  │    │     timestamp+payload) = sig    │                   │    │
│  │    │                                 │                   │    │
│  │    │── POST + sig헤더 ────────────►│                   │    │
│  │    │                                 │  1. sig 추출      │    │
│  │    │                                 │  2. timestamp확인 │    │
│  │    │                                 │  3. HMAC 재계산   │    │
│  │    │                                 │  4. 서명 비교     │    │
│  │    │◄── 200 OK ────────────────────│                   │    │
│  │    │                                 │                   │    │
│  │  → 매 요청마다 서명 계산/검증                           │    │
│  │  → HTTPS로 전송 구간 암호화 (별도)                      │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│                       보안 비교 요약표                            │
│                                                                   │
│  ┌──────────────┬──────────────────┬──────────────────────┐    │
│  │ 보안 항목     │ gRPC              │ REST Callback        │    │
│  ├──────────────┼──────────────────┼──────────────────────┤    │
│  │ 주요 인증     │ mTLS              │ HMAC 서명            │    │
│  │ 방식          │ (상호 인증서)     │ (공유 Secret)        │    │
│  ├──────────────┼──────────────────┼──────────────────────┤    │
│  │ 전송 암호화   │ TLS 내장          │ HTTPS (별도 설정)    │    │
│  │               │ (HTTP/2 + TLS)    │                      │    │
│  ├──────────────┼──────────────────┼──────────────────────┤    │
│  │ 메시지        │ .proto 스키마     │ HMAC-SHA256          │    │
│  │ 무결성        │ + TLS             │ 서명 검증            │    │
│  ├──────────────┼──────────────────┼──────────────────────┤    │
│  │ Replay        │ TLS가 자체 방지   │ Timestamp 검증       │    │
│  │ 방지          │                   │ (수동 구현)          │    │
│  ├──────────────┼──────────────────┼──────────────────────┤    │
│  │ 토큰 인증     │ Metadata에        │ Authorization        │    │
│  │               │ JWT/OAuth2        │ Bearer Token         │    │
│  ├──────────────┼──────────────────┼──────────────────────┤    │
│  │ IP 제한       │ 네트워크 정책     │ IP Whitelist         │    │
│  │               │ (K8s NetworkPolicy)│                     │    │
│  ├──────────────┼──────────────────┼──────────────────────┤    │
│  │ 설정 난이도   │ Service Mesh면    │ HMAC은 간단          │    │
│  │               │ 자동 (쉬움)       │ mTLS는 복잡          │    │
│  ├──────────────┼──────────────────┼──────────────────────┤    │
│  │ 적합한 환경   │ 내부 서비스       │ 외부 시스템          │    │
│  │               │ (신뢰 경계 내)    │ (인터넷 경유)        │    │
│  └──────────────┴──────────────────┴──────────────────────┘    │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

7. 실전 선택 가이드

7.1 이것을 선택하라

┌─────────────────────────────────────────────────────────────────┐
│                     실전 선택 가이드                              │
│                                                                   │
│  gRPC를 선택하라:                                                │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  ✅ 내부 마이크로서비스 간 동기 통신                     │    │
│  │  ✅ 고성능이 필요한 경우 (대량 데이터, 낮은 지연)       │    │
│  │  ✅ 양방향 스트리밍이 필요한 경우                        │    │
│  │  ✅ 강타입 계약으로 서비스 간 안정성 확보                │    │
│  │  ✅ 다중 언어(polyglot) 마이크로서비스 환경              │    │
│  │  ✅ Kubernetes / Service Mesh 환경                       │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  REST Callback (Webhook)을 선택하라:                             │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  ✅ 외부 시스템에 이벤트 알림 전송                       │    │
│  │  ✅ 느슨한 결합이 필요한 경우                            │    │
│  │  ✅ 기존 HTTP 인프라만으로 충분한 경우                   │    │
│  │  ✅ 이벤트 기반 비동기 통지                              │    │
│  │  ✅ 파트너/고객에게 실시간 알림 제공                     │    │
│  │  ✅ 빠른 통합이 필요한 경우 (간단한 구현)               │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  둘 다 사용하라 (가장 흔한 패턴):                                │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  ✅ 내부 서비스: gRPC (고성능 동기 통신)                 │    │
│  │  ✅ 외부 알림:   REST Callback (이벤트 통지)             │    │
│  │                                                          │    │
│  │  예: 결제 시스템                                        │    │
│  │  ├── 주문 서비스 ─[gRPC]─► 결제 서비스 (내부)          │    │
│  │  ├── 결제 서비스 ─[gRPC]─► 재고 서비스 (내부)          │    │
│  │  └── 결제 서비스 ─[Webhook]─► 가맹점 알림 (외부)       │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

7.2 실제 아키텍처 예시

┌─────────────────────────────────────────────────────────────────┐
│                   실제 아키텍처 예시                              │
│                                                                   │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │       [Kubernetes 클러스터 (내부)]                       │    │
│  │  ┌──────────────────────────────────────────────┐       │    │
│  │  │  Service Mesh (Istio) - 자동 mTLS             │       │    │
│  │  │                                                │       │    │
│  │  │  ┌───────────┐  gRPC   ┌──────────────┐      │       │    │
│  │  │  │ API       │────────►│ Order        │      │       │    │
│  │  │  │ Gateway   │         │ Service      │      │       │    │
│  │  │  └───────────┘         └──────┬───────┘      │       │    │
│  │  │                               │ gRPC          │       │    │
│  │  │                               ▼               │       │    │
│  │  │                        ┌──────────────┐      │       │    │
│  │  │                        │ Payment      │      │       │    │
│  │  │                        │ Service      │      │       │    │
│  │  │                        └──────┬───────┘      │       │    │
│  │  │                               │ gRPC          │       │    │
│  │  │                               ▼               │       │    │
│  │  │                        ┌──────────────┐      │       │    │
│  │  │                        │ Inventory    │      │       │    │
│  │  │                        │ Service      │      │       │    │
│  │  │                        └──────────────┘      │       │    │
│  │  └────────────────────────────────────────────────┘       │    │
│  │                               │                           │    │
│  │                               │ REST Callback             │    │
│  │                               │ (HMAC 서명 + HTTPS)       │    │
│  │                               ▼                           │    │
│  │       [외부 시스템]                                       │    │
│  │  ┌──────────────┐    ┌──────────────┐                    │    │
│  │  │ 가맹점       │    │ 파트너       │                    │    │
│  │  │ Webhook 수신 │    │ Webhook 수신 │                    │    │
│  │  └──────────────┘    └──────────────┘                    │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  내부 통신 (gRPC):                                               │
│  ├── Istio sidecar가 자동으로 mTLS 적용                         │
│  ├── 서비스 간 .proto 파일 공유 (git submodule 등)              │
│  ├── HTTP/2 멀티플렉싱으로 고성능                               │
│  └── 서비스별 Interceptor로 인증/인가 처리                      │
│                                                                   │
│  외부 알림 (REST Callback):                                      │
│  ├── HMAC-SHA256 서명 + Timestamp (Replay 방지)                 │
│  ├── HTTPS 필수 (전송 구간 암호화)                               │
│  ├── 재시도 with Exponential Backoff                             │
│  ├── Webhook 이벤트 로그 저장 (감사 추적)                        │
│  └── 수신 측 장애 대비 Dead Letter Queue                        │
│                                                                   │
│  핵심 원칙:                                                      │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  "신뢰 경계(Trust Boundary)를 기준으로 분리"             │    │
│  │                                                          │    │
│  │  내부 (신뢰 경계 안) → gRPC + mTLS                      │    │
│  │  외부 (신뢰 경계 밖) → REST Callback + HMAC             │    │
│  │                                                          │    │
│  │  이유:                                                   │    │
│  │  ├── gRPC: 스키마 공유 가능, 고성능, 양방향             │    │
│  │  │   → 내부 서비스끼리는 .proto 공유가 자연스럽         │    │
│  │  │                                                       │    │
│  │  └── Webhook: 느슨한 결합, 표준 HTTP                    │    │
│  │      → 외부 파트너에게 .proto 강제할 수 없음            │    │
│  │      → HTTP + JSON이 범용적                             │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

8. 정리

┌─────────────────────────────────────────────────────────────────┐
│             gRPC vs REST Callback 핵심 정리                      │
│                                                                   │
│  gRPC:                                                           │
│  ├── Google이 Stubby를 오픈소스화 (2015)                         │
│  ├── HTTP/2 + Protocol Buffers = 고성능 바이너리 통신            │
│  ├── 4가지 스트리밍 패턴 (Unary, Server, Client, Bidi)          │
│  ├── .proto 파일로 강타입 계약 + 자동 코드 생성                 │
│  ├── 보안: mTLS (Service Mesh 자동) + JWT/OAuth2                │
│  └── 적합: 내부 마이크로서비스 간 동기 고성능 통신              │
│                                                                   │
│  REST Callback (Webhook):                                        │
│  ├── Jeff Lindsay가 2007년 용어 제안                             │
│  ├── HTTP POST + JSON = 역방향 API (서버→클라이언트 알림)       │
│  ├── 이벤트 기반 비동기 통지 (폴링의 대안)                      │
│  ├── 재시도 + Exponential Backoff로 전달 보장                    │
│  ├── 보안: HMAC 서명 + Timestamp (Replay 방지)                  │
│  └── 적합: 외부 시스템 이벤트 알림, 느슨한 결합                 │
│                                                                   │
│  보안의 핵심:                                                    │
│  ├── gRPC: mTLS로 양쪽 인증서 검증 (K8s에선 자동)              │
│  ├── Webhook: HMAC-SHA256 서명 + Timestamp + HTTPS              │
│  └── 둘 다: 신뢰 경계에 따라 적절히 선택                        │
│                                                                   │
│  실전 패턴:                                                      │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  내부 서비스 ←─ gRPC (mTLS) ─→ 내부 서비스              │    │
│  │       │                                                  │    │
│  │       └── REST Callback (HMAC) ──→ 외부 파트너/고객     │    │
│  │                                                          │    │
│  │  "내부는 gRPC, 외부는 Webhook"                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

관련 키워드

gRPC, REST Callback, Webhook, Protocol Buffers, HTTP/2, mTLS, HMAC-SHA256, 마이크로서비스, 스트리밍, 비동기 통신, Service Mesh, Istio, protobuf, Replay Attack