infra
Platform

모듈 맵

[Infra Ops] 트래픽 제어와 이벤트 기반 연계 구조

0 / 52 완료

펼치기
0 / 52 완료0%

인프라 운영 & SRE · 25 / 52

[Infra Ops] 트래픽 제어와 이벤트 기반 연계 구조

API Gateway 역할과 rate limiting, Webhook 수신 구조와 재시도 패턴까지

🚨INCIDENT ALERT
HIGH

결제 서비스사에서 Webhook으로 결제 완료 이벤트를 보내준다고 합니다. 그런데 가끔 주문이 두 개 생성된다는 버그 신고가 들어옵니다. 로그를 보니 동일한 결제 완료 이벤트가 두 번 수신됐습니다. 한편 API Gateway 앞단에서는 특정 IP가 갑자기 초당 100개 요청을 보내 서버가 느려지는 일도 생겼습니다. 두 문제 모두 API Gateway와 Webhook 설계를 이해하면 해결됩니다.

이 모듈에서는 API Gateway의 역할과 Nginx Rate Limiting 설정, Webhook 수신 요구사항과 멱등성 패턴, 지수 백오프 재시도 전략을 다룹니다.

이번 챕터에서 배울 것
  • 1API Gateway가 서비스 앞에 위치하는 이유와 처리하는 공통 기능을 설명할 수 있다
  • 2Nginx limit_req_zone으로 Rate Limiting을 설정하고 동작을 확인할 수 있다
  • 3Webhook 수신 서버의 필수 요구사항(응답 시간, 멱등성, HTTPS)을 설명할 수 있다
  • 4429 응답 시 지수 백오프 재시도 전략을 설계하고 구현할 수 있다
  • 5Webhook 중복 수신을 멱등키(idempotency key)로 처리하는 방법을 적용할 수 있다

API Gateway의 역할

💡개념

왜 API Gateway가 필요한가

마이크로서비스 환경에서 각 서비스가 인증, Rate Limiting, 로깅, CORS를 개별적으로 구현하면 코드 중복이 발생하고 정책 일관성이 깨집니다. API Gateway는 모든 외부 요청의 단일 진입점(Single Entry Point)으로, 이런 공통 관심사를 한 곳에서 처리합니다.

왜 API Gateway가 필요한가 — 마이크로서비스마다 인증·Rate Limiting·로깅·CORS를 따로 구현하면 중복·정책 불일치가 생김. API Gateway가 모든 외부 요청의 단일 진입점에서 이 공통 관심사를 처리하고 뒤의 서비스로 라우팅 — 각 서비스는 비즈니스 로직에만 집중확대

API Gateway가 처리하는 공통 기능:

기능설명
인증/인가JWT 검증, API Key 확인 → 유효하지 않으면 401/403 반환
Rate Limiting클라이언트별 초당/분당 요청 수 제한 → 초과 시 429 반환
라우팅URL 경로 기반으로 적합한 백엔드 서비스로 프록시
로깅/추적모든 요청/응답 기록, 분산 트레이싱 헤더 주입
SSL TerminationHTTPS를 게이트웨이에서 종료, 내부는 HTTP
요청 변환헤더 추가/제거, 요청 본문 변환

서비스 구조:

API Gateway 라우팅 — 클라이언트→API Gateway(인증·Rate Limiting·로깅)→경로별로 /api/users(User)·/api/orders(Order)·/api/products(Product) 내부 서비스로 분배확대

주요 API Gateway 제품 비교:

제품특징적합 상황
Kong플러그인 기반, DB 또는 DB-less 모드엔터프라이즈, 다양한 플러그인 필요
AWS API Gateway완전관리형, Lambda 연동 용이AWS 환경, 서버리스 아키텍처
Nginx가볍고 유연, 직접 설정 필요단순 라우팅/Rate Limiting, 소규모
Traefik컨테이너 친화적, 자동 서비스 디스커버리Kubernetes/Docker 환경

Rate Limiting — 남용 방지와 서버 보호

💡개념

Nginx limit_req_zone으로 Rate Limiting 구현

Rate Limiting 없이 서비스를 운영하면 악의적인 요청이나 버그가 있는 클라이언트가 서버 자원을 독점합니다. Nginx의 limit_req_zone은 클라이언트별로 요청 속도를 제한하는 방식으로, 별도 Gateway 없이 Nginx만으로도 기본적인 보호가 가능합니다.

Nginx Rate Limiting 설정:

Nginx
# /etc/nginx/nginx.conf 또는 /etc/nginx/conf.d/rate-limit.conf

http {
    # -- Rate Limit Zone 정의 --
    # $binary_remote_addr: 클라이언트 IP (바이너리 형식, 메모리 절약)
    # zone=api_limit:10m: 'api_limit'이란 이름, 10MB 공유 메모리 (약 16만 IP 저장 가능)
    # rate=10r/s: 초당 10개 요청 허용
    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;

    # 로그인 같은 민감한 엔드포인트는 더 엄격하게
    limit_req_zone $binary_remote_addr zone=login_limit:10m rate=5r/m;

    server {
        listen 80;

        # -- API 엔드포인트에 Rate Limiting 적용 --
        location /api/ {
            # burst=20: 순간적으로 20개까지 큐에 대기 허용
            # nodelay: 큐 대기 없이 즉시 처리 (burst 초과분은 429)
            limit_req zone=api_limit burst=20 nodelay;
            limit_req_status 429;     # 초과 시 반환할 상태 코드

            proxy_pass http://backend;
        }

        # 로그인은 더 엄격하게
        location /api/login {
            limit_req zone=login_limit burst=3 nodelay;
            limit_req_status 429;
            proxy_pass http://backend;
        }

        # Rate Limit 초과 응답 커스터마이징
        error_page 429 @rate_limit_exceeded;
        location @rate_limit_exceeded {
            default_type application/json;
            return 429 '{"error":"too_many_requests","message":"요청 한도를 초과했습니다. 잠시 후 다시 시도하세요.","retry_after":1}';
        }
    }
}

지수 백오프 재시도 로직 (클라이언트 측):

Python
import time
import requests

def call_api_with_retry(url, max_retries=5):
    for attempt in range(max_retries):
        try:
            response = requests.get(url, timeout=10)

            if response.status_code == 429:
                # Retry-After 헤더가 있으면 그 시간만큼 대기
                retry_after = int(response.headers.get('Retry-After', 0))
                wait_time = retry_after if retry_after > 0 else (2 ** attempt)
                print(f"Rate limited. Waiting {wait_time}s (attempt {attempt + 1})")
                time.sleep(wait_time)
                continue

            return response

        except requests.exceptions.Timeout:
            wait_time = 2 ** attempt  # 1, 2, 4, 8, 16초
            print(f"Timeout. Waiting {wait_time}s (attempt {attempt + 1})")
            time.sleep(wait_time)

    raise Exception(f"API 호출 실패: {max_retries}회 재시도 초과")

Webhook 수신 구조

💡개념

Webhook의 동작 방식과 수신 서버 요구사항

결제 서비스사에서 "Webhook이 응답이 없어 재전송하고 있다"는 연락이 왔습니다. 동시에 주문이 두 개씩 생성된다는 버그 신고도 들어옵니다. Webhook 수신 서버가 처리하는 데 3초씩 걸렸고, 그 사이 발신측이 재시도를 했습니다. "2초 내 응답"과 "멱등성"을 모르면 Webhook을 제대로 운영할 수 없습니다.

Webhook은 이벤트 주도 방식입니다. 우리가 외부 서비스에 "이 URL로 이벤트 보내줘"라고 등록하면, 이벤트(결제 완료, 배송 시작, SMS 발송 결과 등) 발생 시 외부 서비스가 우리 서버로 HTTP POST를 보냅니다.

Webhook 흐름:

Webhook 흐름 — 결제 서비스(발신)가 결제 완료 이벤트 발생 시 우리 서버(수신)로 POST /webhook/payment, 서명 검증·주문 상태 갱신 후 2초 내 200 OK 응답(처리는 비동기)확대

Webhook 수신 서버의 핵심 요구사항:

요구사항이유미충족 시
2초 내 응답발신측 timeout 방지timeout → 실패로 판단 → 재시도 → 중복 이벤트
멱등성재시도 시 중복 처리 방지결제 두 번 처리, 이메일 두 번 발송 등
HTTPS이벤트 데이터 암호화대부분의 외부 서비스가 HTTPS만 허용
서명 검증위조 요청 차단공격자가 결제 완료 이벤트 위조 가능

멱등성 구현 패턴 (Node.js/Express 예시):

JS
// webhook 수신 핸들러
const processedEvents = new Set();  // 실제로는 Redis나 DB 사용

app.post('/webhook/payment', async (req, res) => {
    // 1. 즉시 200 OK 응답 (2초 제한 준수)
    res.status(200).json({ received: true });

    // 2. 이후 비동기로 실제 처리
    const eventId = req.headers['x-event-id'] || req.body.event_id;

    // 3. 중복 체크 (멱등성)
    if (processedEvents.has(eventId)) {
        console.log(`중복 이벤트 무시: ${eventId}`);
        return;
    }

    // 4. 서명 검증 (발신측에서 제공하는 시크릿 사용)
    const signature = req.headers['x-webhook-signature'];
    const expectedSig = hmac('sha256', process.env.WEBHOOK_SECRET, JSON.stringify(req.body));
    if (signature !== expectedSig) {
        console.error('서명 불일치 — 위조 요청 차단');
        return;
    }

    // 5. 처리 완료 기록
    processedEvents.add(eventId);

    // 6. 실제 비즈니스 로직 (비동기)
    await processPaymentComplete(req.body);
});

Webhook 패턴 — Push vs Pull 비교확대

💡개념

웹훅 이벤트 한 건이 수신·처리되는 순서 — POST 도착부터 ACK까지 6단계

위 요구사항 표가 "수신 서버가 무엇을 만족해야 하나"라면, 여기서는 이벤트 한 건이 어떤 순서로 흘러가며 각 실패가 어디서 드러나는지를 봅니다. 핵심은 순서입니다 — 검증한 뒤 빠르게 응답(ACK)하고, 무거운 처리는 그다음으로 미뤄야 타임아웃·재전송·부하가 한꺼번에 터지지 않습니다. 아래는 웹훅 POST 한 건이 우리 서버 안에서 지나는 6단계입니다.

TEXT
[결제사]  POST /webhook/payment   (X-Signature · X-Event-ID · JSON)
   │
   ① 수신        게이트웨이가 POST 접수 → 원문(raw body) 그대로 보존
   │              → 파싱·재직렬화 전에 보존해야 서명이 맞음
   │
   ② 서명 검증    같은 시크릿으로 raw body에 HMAC 재계산 → 상수시간 비교
   │              불일치 → 위조로 보고 거부(4xx), 이후 단계 안 감
   │
   ③ 재전송·멱등  타임스탬프 허용오차(±N분) 확인 + 이벤트 ID 중복 조회
   │              이미 처리한 ID → 처리 건너뛰고 곧장 2xx
   │
   ④ 큐 적재      검증 통과분을 메시지 큐에 넣음 (무거운 처리 분리)
   │
   ⑤ ACK         2초 안에 2xx 반환 → 발신측 타임아웃·재전송 차단
   ▼
   ⑥ 비동기 처리  워커가 핸들러 실행 → 성공 시 이벤트 ID 저장(멱등 확정)
[내부 처리 완료]

각 단계에서 무슨 일을 하고, 어긋나면 어떤 증상인가:

단계하는 일여기서 어긋나면
① 수신·원문 보존POST를 받고 파싱 전 raw body를 보존파싱 후 재직렬화(JSON.stringify)한 값으로 검증 → 정상 이벤트가 전부 서명 불일치
② 서명 검증시크릿으로 raw body에 HMAC 재계산, 상수시간 비교검증 생략·== 비교 → 위조 이벤트 통과 또는 타이밍 공격 노출
③ 재전송·멱등타임스탬프 허용오차 + 이벤트 ID 중복 판별멱등 없음 → 재전송된 결제 완료가 주문을 두 번 생성
④ 큐 적재통과분을 큐에 넣어 무거운 처리를 분리핸들러에서 동기로 무거운 작업(정산·메일) → 응답 지연
⑤ ACK2초 안에 2xx 반환응답이 2초 초과 → 발신측 타임아웃 → 재전송 폭주(부하 악순환)
⑥ 비동기 처리·기록워커가 핸들러 실행 후 이벤트 ID 저장처리 전에 ID를 먼저 확정 저장하면, 처리 실패분이 재전송돼도 멱등에 걸려 영영 처리 안 됨

즉 웹훅 사고는 대개 세 지점에서 납니다 — ①②의 서명(정상인데 전부 거부되면 raw body가 아니라 재조립본으로 검증한 것), ③의 멱등(주문 중복이면 이벤트 ID 기록이 빠진 것), ⑤의 응답 시간(재전송 폭주면 핸들러가 동기로 오래 걸린 것). 핵심 순서는 "검증 → 빠른 ACK → 비동기 처리"이고, 이 순서가 뒤집혀 무거운 처리를 ACK 앞에 두면 타임아웃·재전송·부하가 함께 터집니다. curl -w "%{time_total}"로 응답 시간을, 로그의 이벤트 ID 중복으로 멱등을 각각 확인하면 어느 단계인지 좁혀집니다.

실습 — Rate Limiting과 Webhook 테스트

1Nginx Rate Limiting 설정 확인

현재 Nginx 설정에서 Rate Limiting 관련 지시어를 확인합니다.

로컬 터미널
# Nginx 전체 설정에서 Rate Limiting 설정 확인
nginx -T | grep limit_req

# limit_req_zone 정의와 limit_req 적용 위치 확인
nginx -T | grep -E "limit_req_zone|limit_req "

# Rate Limiting 동작 테스트 (빠르게 11개 요청 → 일부 429)
for i in $(seq 1 15); do
    curl -s -o /dev/null -w "Request $i: %{http_code}\n" http://localhost/api/test
done
# 처음 10개는 200, 이후는 429 또는 503 (설정에 따라 다름)
nginx -T | grep limit_req
🔍실행 후 확인할 것
  • nginx -T | grep limit_req_zone으로 정의 위치와 rate 값을 먼저 확인 — rate=10r/s이면 초당 10요청 허용. burst 값이 없으면 초과 요청이 즉시 503으로 거부됨(burst 설정으로 순간 트래픽 허용 가능)
  • 반복 요청 테스트에서 429가 나오면 rate limit 동작 확인 — 첫 10개 요청이 200이고 11번째부터 429면 정상. 모두 200이면 limit_req 지시자가 location 블록에 적용 안 된 것
  • Nginx error.log에 "limiting requests"가 있고 429도 반환되는 조합이면 설정 완료 — 로그는 있는데 429가 안 나오면 return 429가 아닌 nodelay 옵션이 설정된 것으로 요청이 지연만 되고 거부 안 됨
2간단한 Webhook 수신 서버 테스트

nc(netcat)로 임시 수신 서버를 열고 Webhook 요청을 받아봅니다.

로컬 터미널
# 터미널 1: nc로 8888 포트 수신 대기
nc -l -p 8888

# 터미널 2: 별도 창에서 Webhook 발송 테스트
curl -X POST http://localhost:8888/webhook/test \
  -H "Content-Type: application/json" \
  -H "X-Event-ID: evt-001" \
  -d '{"event":"payment.done","order_id":"ORD-001","amount":50000}'

# 터미널 1에서 수신된 HTTP 요청 전체 내용 확인:
# POST /webhook/test HTTP/1.1
# Host: localhost:8888
# Content-Type: application/json
# X-Event-ID: evt-001
# ...
# {"event":"payment.done","order_id":"ORD-001","amount":50000}
nc -l -p 8888
🔍실행 후 확인할 것
  • nc 터미널에 HTTP 요청 헤더가 표시됐는지 먼저 확인 — 아무것도 없으면 Webhook 발송 측이 우리 서버 IP/포트가 아닌 다른 주소로 보내는 것. 헤더 첫 줄에서 POST /endpoint HTTP/1.1 형식 확인
  • X-Event-ID 헤더가 없으면 Webhook 발송 측 설정 누락 — 이벤트 ID가 없으면 중복 수신 시 멱등성 보장 불가. 실제 운영 서버는 이 ID를 DB에 저장해 중복 처리를 막아야 함
  • 요청 본문 수신은 됐지만 Webhook 발송 측에 타임아웃 오류가 나면 — 수신 서버가 2초 내 응답하지 않은 것. 실제 처리 로직(DB 저장 등)은 비동기로 분리하고 즉시 200 OK를 먼저 반환해야 재시도 폭탄 방지

트러블슈팅

원인: 백엔드 서비스 프로세스는 살아있지만 응답이 지연되거나(응답 timeout 초과), keepalive 연결이 끊어진 상태에서 Gateway가 재연결하기 전에 요청이 들어온 경우입니다. 또는 백엔드가 Gateway의 IP에서 오는 연결을 방화벽으로 차단한 경우입니다.

로컬 터미널
# Gateway의 업스트림 에러 로그 확인
grep "upstream" /var/log/nginx/error.log | tail -20
# 출력 예: [error] upstream timed out (110: Connection timed out)
#         [error] connect() failed (111: Connection refused)

# 백엔드 서버 직접 접속 테스트 (Gateway 우회)
curl -v http://192.168.10.11:8080/actuator/health
# → 200이면 백엔드는 정상, Gateway→백엔드 구간 문제

# Gateway 서버에서 백엔드로 TCP 연결 확인
nc -zv 192.168.10.11 8080

# Nginx proxy timeout 설정 확인 및 조정
nginx -T | grep -E "proxy_(connect|send|read)_timeout"
# 너무 짧으면 증가
# proxy_connect_timeout 10s;
# proxy_read_timeout 60s;

해결: proxy_read_timeout을 백엔드 응답 시간에 맞게 조정하고, upstream의 keepalive 설정을 추가합니다. 방화벽 문제라면 Gateway IP에서 백엔드 포트로의 inbound 규칙을 확인합니다.

원인: Webhook 수신 서버의 응답이 2초를 넘기는 경우 발신측이 timeout으로 판단하고 재전송합니다. 수신 서버가 응답을 보내기 전에 이미 처리를 시작했다면, 재전송 이벤트가 오면 동일 주문이 두 번 처리됩니다.

로컬 또는 서버
# 수신 서버 응답 시간 확인
curl -w "\nTime: %{time_total}s\n" -X POST http://localhost/webhook/payment \
  -H "Content-Type: application/json" \
  -d '{"event":"payment.done","order_id":"ORD-TEST"}'
# 2초 이상이면 발신측이 timeout으로 처리

# 애플리케이션 로그에서 중복 이벤트 확인
grep "ORD-001" /var/log/app/webhook.log
# 동일 order_id가 두 번 이상 나타나면 중복 처리 중

# 해결 방안 확인:
# 1. 응답을 먼저 보내고 처리는 비동기로 → 즉시 200 OK
# 2. 이벤트 ID를 DB나 Redis에 기록하여 중복 체크
# 예: Redis SETNX로 멱등키 설정 (이미 있으면 중복)
# redis-cli SET webhook:evt-001 1 NX EX 86400
# → (nil)이면 이미 처리된 이벤트

해결: Webhook 핸들러를 "즉시 200 응답 → 비동기 처리" 패턴으로 변경하고, 이벤트 ID를 처리 완료 후 DB 또는 Redis에 저장하여 중복 수신 시 건너뛰는 멱등성 로직을 추가합니다.

심화 — 서명은 붙였는데 전부 위조로 걸린다

💡개념

심화: 웹훅 서명 검증의 실제 — 무엇에 서명했고, 무엇을 비교하는가

"서명 검증으로 위조를 막는다"는 한 줄은 쉽지만, 실제로 붙여 보면 정상 이벤트가 전부 막히거나 반대로 검증이 사실상 무력한 경우가 흔합니다. 서명이 정확히 무엇을 보증하고 어디서 어긋나는지를 알아야 합니다.

  • 원문(raw body)에 대한 지문이다: 발신사는 공유 시크릿으로 자신이 보낸 본문 바이트에 HMAC(예: HMAC-SHA256)을 계산해 헤더(X-Signature 등)에 담습니다. 수신측이 같은 시크릿으로 같은 바이트에 다시 계산해 값이 같으면, 그 시크릿을 아는 발신자가 보냈고 내용이 변조되지 않았음이 보장됩니다.
  • 재직렬화하면 지문이 깨진다: 여기서 대부분 사고가 납니다. 프레임워크가 본문을 JSON 객체로 파싱한 뒤 우리가 그것을 다시 문자열로 만들어(JSON.stringify) 서명을 계산하면, 키 순서·공백·유니코드 이스케이프가 원문과 달라져 지문이 어긋납니다. 발신자가 서명한 건 "그들이 보낸 원문"이지 "우리가 재조립한 것"이 아닙니다 — 반드시 수신 원문 바이트로 검증해야 합니다.
  • 비교는 상수시간으로: 서명 문자열을 일반 ==로 비교하면 일치 길이에 따라 응답 시간이 미세하게 달라져, 이론상 한 바이트씩 맞춰가는 타이밍 공격이 가능합니다. hmac.compare_digest류의 상수시간 비교를 씁니다.
  • 서명만으로는 재전송을 못 막는다: 공격자가 과거의 정상 요청을 그대로 다시 쏘면 서명은 여전히 유효합니다. 그래서 서명 대상에 타임스탬프를 포함시키고, 수신측이 허용오차(예: ±5분) 밖이면 거부하며, 이벤트 ID로 멱등 처리를 더해야 재전송·중복까지 막힙니다.

정리하면 안전한 웹훅 검증은 "원문 바이트 + 상수시간 비교 + 타임스탬프 허용오차 + 멱등"의 조합이지, HMAC 한 줄이 아닙니다.

상황: 검증 코드를 추가한 뒤로 모든 웹훅이 서명 불일치로 401 처리됩니다. 발신사 대시보드에는 우리 응답이 실패로 찍혀 재전송이 쌓입니다. 시크릿도 문서대로 넣었고 알고리즘(HMAC-SHA256)도 맞습니다.

원인: 수신 프레임워크가 본문을 이미 JSON으로 파싱한 상태에서, 검증 코드가 그 객체를 JSON.stringify로 다시 문자열로 만들어 HMAC을 계산하고 있었습니다. 재직렬화 과정에서 공백·키 순서·유니코드 이스케이프가 발신 원문과 달라져, 같은 시크릿·같은 알고리즘인데도 지문이 어긋납니다. 검증 대상이 "원문"이 아니라 "재조립본"이었던 것입니다.

진단: 발신사 문서에서 "raw body 기준 서명"인지 확인합니다. 수신 시점의 원문 바이트 길이(Content-Length)와 우리가 재직렬화한 문자열의 길이를 로그로 대조하면 대개 다릅니다. 원문과 재조립본을 나란히 찍어 공백·이스케이프 차이를 눈으로 확인합니다.

해결: 해당 웹훅 라우트만 본문을 파싱 전에 원문으로 보존하도록 바꿉니다(예: express.raw({ type: 'application/json' })를 쓰거나 body-parser의 verify 콜백에서 rawBody를 저장). 그 원문 바이트로 HMAC을 계산하고, 비교는 상수시간 함수로 합니다. 재발·재전송 방지를 위해 타임스탬프 허용오차 검증과 이벤트 ID 멱등 처리를 함께 넣습니다.

💼
실무 맥락
현업 패턴

실제 업무에서 이 지식이 쓰이는 상황:

결제 연동이나 배송 추적, SMS 발송 결과 수신 등 외부 서비스 연동은 대부분 Webhook으로 이루어집니다. 신입 개발자나 주니어 인프라 담당자가 가장 자주 실수하는 부분이 "2초 내 응답"과 "멱등성" 두 가지입니다.

Webhook 수신 서버 구성 체크리스트:

로컬 또는 서버
# 1. 응답 시간 확인 (2초 이내여야 함)
curl -w "응답시간: %{time_total}s\n" -X POST http://localhost/webhook/test \
  -H "Content-Type: application/json" -d '{}'

# 2. HTTPS 설정 확인 (대부분 외부 서비스가 요구)
curl -vI https://our-server.com/webhook/payment 2>&1 | grep -E "SSL|TLS|Verify"

# 3. Webhook URL을 외부에서 접근 가능한지 확인
curl -m 5 https://our-server.com/webhook/payment
# Connection refused → 방화벽 또는 포트 미오픈

# 4. Rate Limiting 현황 확인
nginx -T | grep limit_req

API Gateway 장애 시 빠른 확인 순서:

서버 터미널
# Gateway 상태
systemctl status nginx kong

# 최근 에러 로그
tail -50 /var/log/nginx/error.log | grep -E "upstream|timeout|502|504"

# 백엔드 직접 접속 테스트
curl http://백엔드서버:포트/health

API Gateway와 Webhook을 올바르게 구성하면 서비스 안정성이 크게 높아집니다.


명령어·단축키 빠른 참조

API Gateway의 Rate Limiting 확인과 Webhook 수신 테스트·장애 격리에 쓴 명령을 모았습니다. "예" 열의 조합을 그대로 써도 됩니다.

명령어/단축키용도자주 쓰는 예
nginx -T실행 중 Nginx 전체 설정 덤프nginx -T | grep -E "limit_req_zone|limit_req "
curl -o /dev/null -w "%{http_code}" (반복)Rate Limiting 동작 테스트(429 유발)for i in $(seq 1 15); do curl -s -o /dev/null -w "%{http_code}\n" URL; done
nc -l임시 수신 서버로 Webhook 원문 확인nc -l -p 8888 (다른 창에서 curl POST)
curl -X POST -dWebhook 발송 시뮬레이션curl -X POST -H "X-Event-ID: evt-001" -d '{"event":"payment.done"}' URL
curl -w "%{time_total}"수신 서버 2초 응답 초과 여부 측정curl -w "%{time_total}s\n" -X POST -d '{}' URL/webhook
nc -zvGateway→백엔드 TCP 연결 확인nc -zv 192.168.10.11 8080
curl -v (백엔드 직결)Gateway 우회로 502 원인 격리curl -v http://192.168.10.11:8080/actuator/health
grep upstream error.log502/504 업스트림 오류 추적grep "upstream" /var/log/nginx/error.log | tail -20
redis-cli SET ... NX EX멱등키로 중복 이벤트 차단redis-cli SET webhook:evt-001 1 NX EX 86400 ((nil)=이미 처리됨)
curl -vIWebhook URL의 HTTPS·TLS 확인curl -vI https://our-server.com/webhook 2>&1 | grep -E "SSL|TLS"
systemctl statusGateway 프로세스 상태 확인systemctl status nginx kong

관련 모듈로 더 깊이:

다음 모듈에서는 NICE 본인인증, SMS 게이트웨이, 전자서명 같은 외부 기관 API 연계 실무를 다룹니다.

지식 확인

퀴즈 — 8문제

Q1

API Gateway를 서비스 앞에 두는 가장 핵심적인 이유는?

Q2

API 호출 시 429 Too Many Requests 에러를 받았을 때 올바른 재시도 전략은?

Q3

Webhook과 Polling의 차이로 가장 적절한 것은?

Q4

Webhook 수신 서버에 멱등성(idempotency)이 필요한 이유는?

Q5

Webhook 수신 서버에서 무거운 후처리(이메일 발송·정산 계산)를 동기로 처리했더니, 발신측이 같은 이벤트를 계속 재전송한다. 올바른 설계는?

Q6

Nginx limit_req_zone 설정에서 burst 파라미터는 어떤 역할을 하나?

Q7

[심화] 웹훅 HMAC 서명 검증을 안전하게 구현할 때 반드시 지켜야 하는 것으로 옳은 것은?

Q8

[심화] 발신사 문서대로 시크릿과 HMAC-SHA256을 맞췄는데, 서명 검증을 붙이자 정상 이벤트가 전부 불일치로 거부된다. 가장 유력한 원인은?

0 / 8 답변

🧪 실습으로 확인하기

Nginx 설치 및 기동

초급

Linux 서버에 Nginx를 설치하고 systemd 서비스로 등록하여 80포트에서 응답하는 상태까지 만든다.

40📋 3단계💻 직접 환경
실습 시작하기 →

이것도 배워보세요