Web-Network 실전 가이드북
이 문서의 목적
이 문서는 Web-Network 아래의 85개 문서를 실제 개발/운영 상황에서 다시 찾아가게 만드는 안내서다. 네트워크 개념을 다시 요약하려는 문서가 아니라, 장애 알림을 받았거나 API 계약을 설계하거나 인프라 팀과 변경을 맞춰야 할 때 “무엇을 보고, 어떤 질문을 하고, 어느 문서로 돌아갈지”를 빠르게 잡기 위한 지도다.
- 먼저 상황을 읽는다.
- 증거를 어떤 계층으로 나눌지 생각한다.
찾아볼 문서로 돌아가 상세 원리와 명령을 확인한다.- 마지막에는 한 문장 판단 기준만 가져간다.
먼저 보는 빠른 길찾기
| 지금 마주친 상황 | 먼저 볼 Case | 핵심 관찰 |
|---|---|---|
| 간헐적 504, timeout, 느린 API | Case 1, Case 5, Case 16 | curl -w, p95/p99, pool pending, upstream time |
| 배포 후 일부 사용자만 이전 화면을 봄 | Case 2, Case 14, Case 19 | DNS TTL, CDN Age, cache key, purge timeline |
| 브라우저에서만 로그인/요청 실패 | Case 3, Case 18 | Set-Cookie, Cookie, Origin, preflight, DevTools |
| 모바일/파트너만 HTTPS 실패 | Case 4, Case 15 | SNI, chain, truststore, ALPN, TLS policy |
| 외부 API 장애가 전체 장애로 번짐 | Case 5, Case 12 | timeout 정렬, retry budget, idempotency, breaker |
| 업로드/다운로드/장기 연결이 자주 깨짐 | Case 6, Case 7 | body limit, buffering, idle timeout, draining |
| LB 502/503/504와 app log 부재 | Case 8, Case 16 | 응답 주체, target health, proxy/LB access log |
| 이벤트 전 capacity와 병목이 걱정됨 | Case 9, Case 10 | headroom, load test, shared resource, rare limit |
| 도메인, 인증서, 관리자 경계를 설계함 | Case 11, Case 17 | DNS, cookie scope, TLS termination, 운영 기준 |
| 인프라 팀과 변경/장애를 맞춰야 함 | Case 13, Case 16, Case 20 | 요청 정보, owner, rollback, postmortem action |
| 세부 HTTP 계약이 실제 코드에서 흔들림 | 보충 Case 1, 보충 Case 2, 보충 Case 7 | Accept, Content-Type, ETag, If-Match, 민감 header |
| 고급 운영 선택을 인프라와 맞춰야 함 | 보충 Case 3, 보충 Case 4, 보충 Case 5, 보충 Case 6, 보충 Case 8 | HTTP/3, mTLS, WebClient timeout, WAF/LB, rare limit runbook |
실전 Case
Case 1. 주문 API가 가끔 504를 내고, 서버 CPU는 낮다
상황
- 주문 API에서 사용자는 가끔 timeout을 본다.
- app CPU는 낮고, 평균 응답 시간은 괜찮아 보인다.
- NGINX나 LB에는 504가 찍히지만 application log에는 일부 요청만 남는다.
관찰할 증거 또는 확인할 단서
curl -w로 DNS/TCP/TLS/first byte/total time을 분리한다.- LB/proxy의
upstream_response_time,upstream_status, app trace의 DB acquire time을 본다. - DB pool active/pending, HTTP client pool pending, retry count, p95/p99를 함께 본다.
먼저 생각해보기
- 요청은 앱까지 도달했는가, 아니면 proxy/LB에서 timeout이 났는가?
- 느린 구간은 query 실행인가, pool acquire인가, 외부 API 호출인가?
- timeout 값은 client, LB, proxy, app, downstream 순서로 정렬되어 있는가?
찾아볼 문서
- 전체 요청 경로 상세
- 계층별 관찰 지점 상세
- HTTP Client Connection Pool 상세
- Timeout 종류와 정렬 상세
- 병목 구분 상세
- 타임아웃과 지연 장애 분석 상세
실전 행동
- 504가 생성된 계층을 먼저 찾는다.
- trace에서 DB acquire, query, external call, serialization 시간을 분리한다.
- timeout을 늘리기 전에 pool pending과 retry 증가가 있는지 확인한다.
정리
- CPU가 낮은 장애는 “아무 일도 안 하는 서버”가 아니라 “어딘가에서 기다리는 서버”일 수 있다.
가져갈 한 문장
- 느린 요청은 CPU보다 먼저 queue와 timeout의 위치를 찾는다.
Case 2. 배포했는데 일부 사용자만 이전 화면을 계속 본다
상황
- 배포는 성공했고 origin 서버는 새 버전을 응답한다.
- 일부 사용자는 예전 HTML이나 JS를 계속 받는다.
- 새 API와 오래된 asset 조합 때문에 프론트 오류가 난다.
관찰할 증거 또는 확인할 단서
Cache-Control,Age,ETag,Last-Modified, CDN cache status를 본다.- CDN 응답과 origin 응답을 같은 URL로 비교한다.
- 배포 시각, purge 요청 시각, edge별 반영 시각을 timeline으로 둔다.
먼저 생각해보기
- 브라우저 cache, CDN edge, origin, application cache 중 어디의 응답인가?
- HTML과 asset의 TTL 전략이 서로 맞는가?
- purge로 해결할 문제인가, versioned URL로 피해야 할 문제인가?
찾아볼 문서
- Cache CDN Conditional Request 압축 정리
- HTTP Cache 기본 상세
- ETag와 Conditional Request 상세
- CDN Origin과 Purge 상세
- Cache 정합성 장애 상세
- DNS TTL과 배포 전파 상세
실전 행동
- 사용자가 받은 응답의 cache header를 먼저 확보한다.
- CDN과 origin을 분리해 비교한다.
- asset은 fingerprint로, HTML은 짧은 TTL 또는 재검증으로 가는지 점검한다.
정리
- 캐시 장애는 “안 바뀐다”가 아니라 “어느 cache key의 어떤 응답이 재사용되는가”로 바꿔야 좁혀진다.
가져갈 한 문장
- 배포와 cache는 purge 버튼이 아니라 version, TTL, compatibility의 조합으로 안전해진다.
Case 3. API는 200인데 브라우저에서는 로그인된 상태가 아니다
상황
- 로그인 응답은 200이고
Set-Cookie도 내려간 것처럼 보인다. - 다음 요청에 cookie가 붙지 않거나, preflight에서 막힌다.
- 서버 간
curl은 성공하지만 브라우저 fetch는 실패한다.
관찰할 증거 또는 확인할 단서
- DevTools에서 cookie rejected reason을 본다.
- 실제 요청의
Cookie,Origin,Access-Control-*,Set-Cookie를 확인한다. OPTIONSpreflight와 실제 요청을 분리해서 본다.
먼저 생각해보기
- 쿠키가 저장되지 않았는가, 저장됐지만 전송되지 않았는가?
- CORS가 응답 노출을 막는가, preflight가 본 요청을 막는가?
- SameSite, Secure, Domain, Path, credential fetch 설정이 서로 맞는가?
찾아볼 문서
- Cookie Session SameSite CORS 압축 정리
- Cookie 속성 상세
- Session과 인증 상태 상세
- SameSite와 CSRF 상세
- CORS와 Preflight 상세
- 브라우저 보안 디버깅 상세
- 브라우저와 서버 경계 상세
실전 행동
Set-Cookie수신, cookie 저장, cookie 전송, CORS 노출을 각각 다른 단계로 본다.- credential CORS는 allowlist,
Allow-Credentials,Vary: Origin, SameSite를 세트로 점검한다. - Spring Security filter 이전에 CORS 처리가 되는지 확인한다.
정리
- 브라우저 보안 문제는 서버가 200을 냈는지만 봐서는 풀리지 않는다.
가져갈 한 문장
- 브라우저 인증 장애는
Set-Cookie와Cookie사이의 빈칸을 증거로 채우는 작업이다.
Case 4. 모바일 앱이나 파트너사만 HTTPS 호출에 실패한다
상황
- 최신 브라우저에서는 정상 접속된다.
- 특정 모바일 버전, 오래된 Java client, 파트너사 환경에서만 TLS 오류가 난다.
- 앱 서버에는 요청 로그가 없다.
관찰할 증거 또는 확인할 단서
openssl s_client -servername ... -showcerts로 SNI와 chain을 본다.curl -v --http2와time_appconnect로 TLS 구간을 분리한다.- Java client의
PKIX path building failed, hostname mismatch, ALPN 협상 실패를 확인한다.
먼저 생각해보기
- TLS가 어느 구간에서 종료되는가?
- 실패 client의 truststore, TLS version, cipher, SNI 지원은 무엇인가?
- 인증서 발급 성공과 LB/CDN/proxy 반영 성공을 혼동하고 있지 않은가?
찾아볼 문서
- HTTPS TLS 인증서 압축 정리
- TLS Handshake 상세
- 인증서 Chain과 SNI 상세
- TLS Termination과 mTLS 상세
- TLS 디버깅 상세
- Forwarded Header와 Client IP 상세
실전 행동
- SNI 포함/미포함 결과를 비교한다.
- chain, SAN, issuer, 만료일, ALPN 결과를 기록한다.
- 인프라 팀에는 hostname, client runtime, 발생 시각,
openssl결과를 같이 보낸다.
정리
- TLS 장애는 “사이트가 안 열린다”가 아니라 client 종류와 termination 구간에 따라 달라지는 검증 실패다.
가져갈 한 문장
- HTTPS 실패에서 앱 로그가 없으면 TLS handshake 이전의 증거부터 모은다.
Case 5. 외부 API 장애가 우리 서비스 전체 장애로 번진다
상황
- 추천 API나 결제 API가 느려진 뒤 우리 서비스의 전체 p99가 같이 무너진다.
- retry가 늘고 thread나 connection이 오래 붙잡힌다.
- 일부 기능 장애가 핵심 API 장애로 번진다.
관찰할 증거 또는 확인할 단서
- external call latency, timeout, retry attempt, circuit breaker open count를 본다.
- HTTP client pool active/idle/pending을 본다.
- retry 대상 method가 멱등인지, idempotency key가 있는지 확인한다.
먼저 생각해보기
- timeout은 dependency별로 분리되어 있는가?
- retry가 recovery를 돕는가, traffic을 증폭하는가?
- fallback은 정확성을 해치지 않는가?
찾아볼 문서
- Timeout Retry Idempotency Circuit Breaker 압축 정리
- Timeout 종류와 정렬 상세
- Retry와 장애 증폭 상세
- Circuit Breaker Bulkhead Fallback 상세
- Spring과 Resilience 설정 상세
- HTTP Client Connection Pool 상세
- Pool 고갈 장애 상세
실전 행동
- 외부 API별 timeout, retry, breaker, bulkhead를 분리한다.
- non-idempotent 요청은 자동 retry 전에 중복 처리 계약을 확인한다.
- 부가 기능은 degraded response나 fallback으로 핵심 기능과 분리한다.
정리
- resilience 설정은 장애를 없애는 장식이 아니라 장애가 퍼지는 길을 좁히는 설계다.
가져갈 한 문장
- 외부 API 호출은 timeout, retry, pool, breaker를 하나의 계약으로 본다.
Case 6. 파일 업로드가 413, 502, 504를 오가며 실패한다
상황
- 작은 파일은 성공하지만 큰 파일은 proxy에서 413이 나거나 중간에 끊긴다.
- app log에는 요청이 없거나, body를 읽다가 timeout이 난다.
- 사용자에게는 그냥 업로드 실패로 보인다.
관찰할 증거 또는 확인할 단서
Content-Length,Transfer-Encoding, multipart boundary를 확인한다.- NGINX
client_max_body_size, proxy buffering, read timeout을 확인한다. - LB/proxy/app 중 어느 계층이 응답을 만들었는지 본다.
먼저 생각해보기
- body size 제한은 CDN, LB, proxy, app 중 어디에 있는가?
- streaming이 필요한 요청을 proxy가 buffering하고 있지 않은가?
- 긴 업로드를 동기 요청으로 유지해야 하는가, 비동기 처리로 바꿔야 하는가?
찾아볼 문서
- HTTP 기본 구조 압축 정리
- Message Framing과 Body 상세
- NGINX Timeout과 Buffer 상세
- 요청 유형별 네트워크 판단 상세
- Status Code 운영 해석 상세
실전 행동
- 413이면 body limit부터 찾고, 504면 upstream 처리 시간과 timeout 정렬을 본다.
- 업로드 endpoint는 일반 API와 timeout/buffer 정책을 분리한다.
- 큰 파일은 pre-signed URL이나 비동기 처리 전환도 검토한다.
정리
- 업로드 장애는 애플리케이션 로직보다 HTTP body와 proxy 경계에서 먼저 갈라지는 경우가 많다.
가져갈 한 문장
- 큰 body는 API 로직 전에 framing, buffering, size limit을 통과해야 한다.
Case 7. SSE나 WebSocket이 1분쯤 지나면 조용히 끊긴다
상황
- 로컬에서는 괜찮은데 운영에서는 SSE나 WebSocket이 일정 시간 뒤 끊긴다.
- 서버는 에러를 크게 남기지 않는다.
- 사용자는 알림이 가끔 사라진다고 말한다.
관찰할 증거 또는 확인할 단서
- LB, proxy, app, client idle timeout 값을 나열한다.
- WebSocket upgrade header, SSE buffering, heartbeat 주기를 본다.
- draining 중 장기 연결이 어떻게 종료되는지 확인한다.
먼저 생각해보기
- 연결이 idle로 판단되는 계층은 어디인가?
- heartbeat가 proxy/LB idle timeout보다 짧은가?
- 배포 중 연결을 어떻게 끊고 재연결하게 할 것인가?
찾아볼 문서
- TCP 연결 Keep-Alive Connection Pool 압축 정리
- Keep-Alive 동작 상세
- Idle Timeout 불일치 상세
- Idle Timeout과 장기 연결 상세
- NGINX Timeout과 Buffer 상세
- 요청 유형별 네트워크 판단 상세
실전 행동
- 연결 유형별로 timeout chain을 표로 만든다.
- SSE는 buffering off와 heartbeat를, WebSocket은 upgrade와 reconnect/backoff를 확인한다.
- 배포 시 draining과 client reconnect 동작을 함께 테스트한다.
정리
- 장기 연결은 연결 유지보다 연결이 끊긴 뒤 회복하는 계약이 더 중요할 때가 많다.
가져갈 한 문장
- 장기 연결 장애는 idle timeout, buffering, draining, reconnect를 한 줄로 세워서 본다.
Case 8. Cloud LB가 502를 반환하는데 app log에는 아무것도 없다
상황
- 사용자는 502를 보고, app log에는 해당 request id가 없다.
- LB target health가 흔들리거나 특정 target group만 실패한다.
- proxy access log에는 upstream 관련 값이 남는다.
관찰할 증거 또는 확인할 단서
- LB access log의 status, target status, target response time을 본다.
- NGINX
upstream_status,upstream_connect_time,upstream_response_time을 확인한다. - target health reason, readiness, security group, path rewrite를 같이 본다.
먼저 생각해보기
- 502는 app이 만든 응답인가, LB/proxy가 만든 응답인가?
- 요청이 target까지 갔는가, target 선택 전 실패했는가?
- 최근 배포, health check 변경, upstream path rewrite 변경이 있었는가?
찾아볼 문서
- Proxy Reverse Proxy Gateway 압축 정리
- Proxy와 Reverse Proxy 역할 상세
- Path Rewrite와 Upstream 상세
- Load Balancer Health Check Traffic Routing 압축 정리
- Health Check와 Readiness 상세
- Cloud LB 디버깅 상세
- HTTP 상태코드별 병목 구간 상세
- 실제 502 사례와 장애 보고 상세
실전 행동
- response header와 access log로 응답 주체를 먼저 찾는다.
- target health와 readiness 전환 시각을 배포 timeline에 겹친다.
- app log가 없다는 사실을 “앱 문제가 아님”이 아니라 “앱 전 단계 증거 필요”로 다룬다.
정리
- 502는 한 단어가 아니라 proxy/LB가 본 upstream 실패의 여러 얼굴이다.
가져갈 한 문장
- app log가 없을 때는 마지막으로 요청을 본 계층의 log가 출발점이다.
Case 9. 이벤트 트래픽 전에 capacity가 충분한지 말해야 한다
상황
- 마케팅 이벤트 전 예상 traffic이 공유된다.
- “서버 몇 대 더 늘리면 되죠?”라는 질문을 받는다.
- DB, cache, NAT, DNS, external API quota는 아직 확인되지 않았다.
관찰할 증거 또는 확인할 단서
- peak RPS, burst, payload 크기, fan-out, retry 정책을 모은다.
- p95/p99, error rate, queue length, pool pending, external quota를 본다.
- load test의 traffic mix와 client generator 병목을 확인한다.
먼저 생각해보기
- app instance 증가가 shared resource 부하를 얼마나 늘리는가?
- SLO를 깨는 saturation point는 어디인가?
- overload 때 거절할 요청과 보호할 요청은 무엇인가?
찾아볼 문서
- 대용량 트래픽과 네트워크 병목 압축 정리
- Capacity Planning 상세
- 병목 구분 상세
- 부하 테스트와 관측 상세
- Backpressure와 Rate Limit 상세
- LB 알고리즘과 Routing 상세
- Health Check와 Readiness 상세
실전 행동
- capacity inventory를 먼저 만들고, app/DB/cache/NAT/external API 한계를 나란히 적는다.
- 부하 테스트는 평균 RPS보다 실패 직전 metric snapshot을 남긴다.
- rate limit, queue limit, traffic shedding 기준을 이벤트 전 합의한다.
정리
- capacity planning은 서버 대수 계산이 아니라 SLO를 지키는 traffic 범위를 아는 일이다.
가져갈 한 문장
- scale out 전에 shared resource와 backpressure부터 계산한다.
Case 10. scale out 후에도 장애가 더 빨리 난다
상황
- app instance를 늘렸는데 DB connection, NAT, DNS, external API timeout이 늘었다.
- CPU는 넉넉한데 outbound connect timeout과 socket 상태가 이상하다.
- “서버를 늘렸는데 왜 더 나빠졌지?”라는 질문이 나온다.
관찰할 증거 또는 확인할 단서
- app instance 수와 pool size 합계를 계산한다.
ss -s, file descriptor, TIME_WAIT, conntrack, NAT metric을 본다.- DNS resolver QPS, external API quota, DB max connection을 확인한다.
먼저 생각해보기
- 늘린 것은 app capacity인가, 전체 system capacity인가?
- shared resource가 scale out의 새 병목이 되었는가?
- rare limit이 평소에는 숨어 있다가 traffic에서 드러난 것인가?
찾아볼 문서
- IP TCP UDP 기본 압축 정리
- IP와 포트 라우팅 상세
- TCP Handshake와 상태 상세
- OS 네트워크 관찰 상세
- 서버 Socket Thread Backlog 상세
- Pool 고갈 장애 상세
- 희귀하지만 중요한 한계 상세
실전 행동
- instance 수 증가 전후의 connection 총량을 계산한다.
- OS/cloud network 한계를 runbook에 있는 명령과 provider metric으로 확인한다.
- DB/cache/external API owner와 quota 증설 또는 pool 조정을 협의한다.
정리
- app을 늘리는 일은 downstream과 네트워크 공유 테이블에 더 많은 일을 보내는 일이기도 하다.
가져갈 한 문장
- scale out은 병목을 없애기보다 다음 병목을 더 잘 보이게 만든다.
Case 11. 새 도메인과 관리자 경계를 설계한다
상황
www,api,admin,static도메인을 어떻게 나눌지 정해야 한다.- cookie scope, CORS, TLS 인증서, OAuth callback, WAF 정책이 함께 얽힌다.
- 개인 프로젝트라도 운영 서비스처럼 보이고 싶다.
관찰할 증거 또는 확인할 단서
- URL의 scheme/host/path/query가 어느 계층에서 쓰이는지 본다.
- DNS record, CNAME, CAA, wildcard 인증서 범위를 확인한다.
- admin 도메인의 cookie, CORS, IP allowlist, auth policy를 분리한다.
먼저 생각해보기
- 도메인 경계가 인증 경계와 cache 경계를 같이 표현하는가?
- wildcard나 shared cookie domain이 편하지만 위험하지 않은가?
- redirect URL과 callback URL은 allowlist로 관리되는가?
찾아볼 문서
실전 행동
- 도메인별 역할과 인증/캐시/CORS 정책을 한 표로 만든다.
- admin은 public API와 도메인, cookie, WAF 정책을 분리한다.
- DNS와 인증서 변경은 rollback record와 검증 명령까지 같이 적는다.
정리
- 도메인은 예쁜 주소가 아니라 브라우저와 인프라가 공유하는 보안 경계다.
가져갈 한 문장
- 도메인 설계는 URL, cookie, CORS, TLS, WAF를 함께 결정한다.
Case 12. 결제 요청 재시도와 중복 결제를 막아야 한다
상황
- 결제 API에서 client timeout이 발생했다.
- 사용자는 다시 시도했고, 서버는 첫 요청을 이미 처리했을 수도 있다.
- gateway retry와 client retry가 동시에 켜져 있다.
관찰할 증거 또는 확인할 단서
- HTTP method와 idempotency key 유무를 확인한다.
- timeout 후 서버 작업이 계속됐는지 transaction log를 본다.
- error response에 retry 가능 여부와
Retry-After가 있는지 본다.
먼저 생각해보기
- 이 요청은 자동 retry해도 안전한가?
- idempotency key 저장소가 processing/succeeded/failed 상태를 구분하는가?
- status code와 응답 body가 client 행동을 안내하는가?
찾아볼 문서
- HTTP Method Status Code Header 압축 정리
- Method와 멱등성 상세
- API 응답 계약 상세
- Retry와 장애 증폭 상세
- Idempotency Key 상세
- HTTP Client Connection Pool 상세
- 요청과 응답 메시지 상세
실전 행동
- POST retry는 idempotency key와 결과 재조회 API를 함께 설계한다.
- 409, 202, 429, 503 같은 응답이 client의 다음 행동을 분명히 하게 한다.
- gateway retry와 app retry가 곱해지지 않도록 소유권을 정한다.
정리
- 결제 같은 상태 변경 API에서 네트워크 timeout은 성공/실패가 아니라 “결과를 모르는 상태”다.
가져갈 한 문장
- 자동 retry보다 먼저 중복 처리 계약을 설계한다.
Case 13. 파트너 API가 WAF나 Gateway에서 막힌다
상황
- 특정 파트너사 요청만 403, 429, 413으로 실패한다.
- app log에는 요청이 없거나, gateway log에 rule id가 남는다.
- 파트너사는 “어제까지 됐다”고 말한다.
관찰할 증거 또는 확인할 단서
- gateway/WAF rule id, rate limit key, request id, client IP, header size를 본다.
X-Forwarded-Forchain과 trusted proxy 정책을 확인한다.- 차단 응답의 body와 header가 파트너가 이해할 수 있는지 본다.
먼저 생각해보기
- 차단은 보안 정책인가, quota 초과인가, 잘못된 header/path rewrite인가?
- IP 기준 제한이 NAT나 proxy 때문에 과도하게 적용됐는가?
- CORS 문제와 gateway 차단 문제를 섞어 보고 있지 않은가?
찾아볼 문서
- Forwarded Header와 Client IP 상세
- API Gateway와 WAF 상세
- Header 설계와 관찰 상세
- API 응답 계약 상세
- CORS와 Preflight 상세
- Backpressure와 Rate Limit 상세
- 인프라 팀과 소통하는 방법 상세
실전 행동
- 차단된 요청의 raw method/path/header/body size와 rule id를 확보한다.
- gateway에서 처리할 정책과 app에서 처리할 정책을 분리한다.
- 파트너에게는 재현 가능한 request id와 다음 행동을 주는 응답 계약을 제공한다.
정리
- gateway/WAF 장애는 앱 코드보다 정책, 신뢰 경계, 관측 위치를 먼저 맞춰야 한다.
가져갈 한 문장
- 403과 429는 “안 됨”이 아니라 어떤 정책이 어떤 key에 적용됐는지 묻는 신호다.
Case 14. DNS 전환과 Blue-Green 배포를 함께 진행한다
상황
- 새 인프라로 traffic을 옮기기 위해 DNS, LB target, CDN cache를 함께 바꿔야 한다.
- 일부 사용자는 old로, 일부 사용자는 new로 들어올 수 있다.
- rollback도 가능해야 한다.
관찰할 증거 또는 확인할 단서
- authoritative DNS와 public resolver cache를 비교한다.
- old/new endpoint health, TLS certificate, CDN cache status를 모두 확인한다.
- weighted routing, canary, draining, TTL 복구 시점을 기록한다.
먼저 생각해보기
- old와 new가 동시에 살아 있어도 API와 asset이 호환되는가?
- DNS TTL을 낮추는 시점과 실제 전환 시점이 분리되어 있는가?
- LB target draining과 DNS rollback이 충돌하지 않는가?
찾아볼 문서
- DNS TTL과 배포 전파 상세
- CDN Origin과 Purge 상세
- Load Balancer Health Check Traffic Routing 압축 정리
- LB 알고리즘과 Routing 상세
- 배포와 Draining 상세
- 기업 운영 환경에서 챙길 네트워크 기준 상세
실전 행동
- lower TTL, dual-run, switch, observe, restore 단계를 나눈다.
- old/new 둘 다 smoke test하고 request id와 version header를 남긴다.
- rollback은 DNS만 되돌리는지, LB target과 CDN cache도 같이 되돌리는지 정한다.
정리
- 전환 작업은 한 번에 바꾸는 일이 아니라 old와 new가 동시에 맞는 시간을 운영하는 일이다.
가져갈 한 문장
- DNS 전환은 record 변경보다 dual-run과 rollback 증거가 중요하다.
Case 15. gRPC나 HTTP/2가 운영에서만 이상하게 느리다
상황
- 로컬에서는 gRPC가 빠른데 운영에서는 HTTP/1.1처럼 동작하거나 연결이 불안정하다.
- proxy를 지나면 protocol이 바뀌거나 ALPN 협상이 다르게 나온다.
- HTTP/3를 켰더니 일부 네트워크에서만 실패한다.
관찰할 증거 또는 확인할 단서
curl --http2,curl --http3,openssl s_client -alpn결과를 본다.- CDN/LB/proxy/origin 사이 protocol을 각각 확인한다.
- UDP 443 차단, h3 fallback, gRPC timeout/idle timeout을 본다.
먼저 생각해보기
- client-edge, edge-origin, origin-app 구간 protocol이 같은가?
- HTTP/2 multiplexing이나 flow control이 proxy에서 깨지는가?
- UDP/QUIC은 fallback이 정상인가?
찾아볼 문서
실전 행동
- protocol 협상 결과를 구간별로 나눈다.
- gRPC는 h2, ALPN, proxy timeout, max stream 설정을 함께 본다.
- HTTP/3는 UDP 경로와 h2 fallback을 운영 smoke test에 넣는다.
정리
- HTTP 버전 문제는 기능 차이보다 연결 모델과 proxy 변환 차이로 나타난다.
가져갈 한 문장
- “HTTPS 성공”은 HTTP/2, gRPC, HTTP/3 성공을 보장하지 않는다.
Case 16. 장애 첫 10분에 무엇을 모아야 할지 막막하다
상황
- Slack에 “네트워크 문제 같습니다”라는 말이 올라온다.
- 상태코드, request id, 영향 범위, 최근 변경이 아직 없다.
- 여러 팀이 각자 다른 dashboard를 보고 있다.
관찰할 증거 또는 확인할 단서
- 영향 범위, 첫 발생 시각, request id, status code, response header, 마지막 log 위치를 모은다.
- DNS/TCP/TLS/HTTP/proxy/app/DB 계층 중 어디까지 도달했는지 표시한다.
- 최근 배포, DNS/TLS/LB/WAF/CDN 변경을 확인한다.
먼저 생각해보기
- “왜”보다 “어디까지 갔는가”를 먼저 말할 수 있는가?
- 응답을 만든 계층과 요청을 마지막으로 본 계층이 같은가?
- 지금 필요한 것은 원인 단정인가, 완화인가, 영향 범위 축소인가?
찾아볼 문서
- 네트워크 장애 대응과 트러블슈팅 압축 정리
- 장애를 계층별로 의심하는 방법 상세
- 타임아웃과 지연 장애 분석 상세
- HTTP 상태코드별 병목 구간 상세
- 실제 502 사례와 장애 보고 상세
- 로그와 Trace ID로 따라가기 상세
- 장애 가설 세우기 상세
- 팀 서비스 운영에서 챙길 네트워크 기준 상세
실전 행동
- incident message를 “증상, 영향, 증거, 다음 확인” 네 줄로 바꾼다.
- request id로 LB/proxy/app log를 연결한다.
- 원인 후보를 줄이면서 동시에 완화 가능한 경로를 찾는다.
정리
- 장애 초반에는 정답보다 모두가 같은 증거를 보게 만드는 것이 빠르다.
가져갈 한 문장
- 네트워크 장애 대응은 추측을 계층별 증거로 바꾸는 작업이다.
Case 17. 개인 프로젝트를 운영 서비스처럼 보이게 만들고 싶다
상황
- 개인 프로젝트를 공개했고, 이제 포트 하나 연 서버가 아니라 운영 가능한 백엔드처럼 만들고 싶다.
- 도메인, HTTPS, reverse proxy, health check, access log, 배포 smoke test가 필요하다.
- 비용은 작게 유지하고 싶다.
관찰할 증거 또는 확인할 단서
- public URL, DNS record, TLS certificate, NGINX access log, app health endpoint를 확인한다.
- app port가 인터넷에 직접 열려 있는지 본다.
- 배포 후 smoke test script가 있는지 확인한다.
먼저 생각해보기
- 사용자가 들어오는 실제 request path를 설명할 수 있는가?
- 장애가 났을 때 최소한 request id, status, response time을 볼 수 있는가?
- 직접 운영과 managed service 사이의 비용/학습 trade-off는 무엇인가?
찾아볼 문서
- 백엔드 개발자와 인프라 협업 압축 정리
- 개인 프로젝트에서 챙길 네트워크 기준 상세
- Proxy와 Reverse Proxy 역할 상세
- Forwarded Header와 Client IP 상세
- 배포와 Draining 상세
- TLS Termination과 mTLS 상세
- IP와 포트 라우팅 상세
실전 행동
- domain, HTTPS, reverse proxy,
/healthz, access log, smoke test를 먼저 갖춘다. - app port는 private으로 두고 proxy만 public entry로 둔다.
- 장애 노트와 간단한 post-deploy check를 남긴다.
정리
- 개인 프로젝트의 수준은 기능 수보다 장애를 좁힐 수 있는 증거에서 드러난다.
가져갈 한 문장
- 작은 서비스도 request path와 운영 증거를 갖추면 갑자기 단단해진다.
Case 18. 캐시를 붙였더니 다른 사용자 데이터가 보일까 걱정된다
상황
- CDN을 붙이고 나니 응답이 빨라졌다.
- 하지만 사용자별 API, CORS 응답, 압축 응답이 섞일 가능성이 걱정된다.
- 보안 리뷰에서 cache policy를 설명해야 한다.
관찰할 증거 또는 확인할 단서
Cache-Control,Vary,Authorization, cookie, CDN cache key를 확인한다.- 개인화 endpoint가
public으로 저장되는지 본다. - web cache poisoning/deception 가능성이 있는 path와 extension rule을 확인한다.
먼저 생각해보기
- 이 응답은 공유 cache에 저장되어도 되는가?
- 같은 URL이라도 origin, user, language, encoding에 따라 응답이 달라지는가?
- cache HIT율보다 정보 노출 위험이 더 중요한 endpoint는 무엇인가?
찾아볼 문서
- Cache 성능과 보안 상세
- HTTP Cache 기본 상세
- Content Negotiation과 Encoding 상세
- Header 설계와 관찰 상세
- Cookie Session SameSite CORS 압축 정리
실전 행동
/assets/*와/api/*cache 정책을 분리한다.- 인증 응답은
private/no-store기준으로 보수적으로 시작한다. - CDN rule 변경은 보안 리뷰와 smoke test를 함께 둔다.
정리
- 캐시 성능은 좋은데, 공유 cache에 무엇을 저장할지 정하지 않으면 보안 문제가 된다.
가져갈 한 문장
- cache key는 성능 키이면서 데이터 격리 키다.
Case 19. 권한을 뺐는데 사용자는 여전히 화면을 본다
상황
- 관리자가 멤버십이나 권한을 회수했다.
- DB에는 반영됐지만 사용자 화면은 몇 분 동안 그대로다.
- CDN, 브라우저 cache, application cache, search index 중 어디가 늦는지 모른다.
관찰할 증거 또는 확인할 단서
- 권한 변경 DB commit, event 발행, cache purge, edge 반영 시각을 timeline으로 만든다.
- 같은 URL을 사용자 token으로, cache bypass header와 함께 비교한다.
- 304, ETag, private/no-store 정책을 확인한다.
먼저 생각해보기
- 권한 데이터는 stale을 몇 초까지 허용할 수 있는가?
- cache key가 user/tenant/role 차이를 반영하는가?
- 권한 회수는 purge로 충분한가, 아예 저장 금지가 맞는가?
찾아볼 문서
- Cache 정합성 장애 상세
- ETag와 Conditional Request 상세
- Status Code 운영 해석 상세
- Session과 인증 상태 상세
- Cache CDN Conditional Request 압축 정리
실전 행동
- 권한 변경 데이터는 cache 허용 시간을 제품/보안과 합의한다.
- 공유 cache 저장 여부와 cache key를 먼저 확인한다.
- cache 문제를 DB 문제와 분리하기 위해 origin 직접 응답과 edge 응답을 비교한다.
정리
- 권한 정합성은 성능 최적화보다 사용자 데이터 보호 쪽으로 판단해야 한다.
가져갈 한 문장
- 권한 데이터의 cache는 HIT율보다 회수 지연 위험을 먼저 본다.
Case 20. 장애가 끝났고, 다음에는 더 빨라지고 싶다
상황
- 502/504 장애는 완화됐다.
- 회고에서 “다음에는 더 빨리 알자”가 반복된다.
- 하지만 action item이 사람의 주의에만 의존한다.
관찰할 증거 또는 확인할 단서
- timeline, detection time, mitigation time, customer impact, owner를 정리한다.
- 누락된 log, metric, request id, runbook, alert를 찾는다.
- 같은 유형이 반복되지 않도록 action item의 완료 조건을 정의한다.
먼저 생각해보기
- 원인보다 늦어진 이유가 무엇인가?
- 어떤 증거가 없어서 팀 간 추측이 길어졌는가?
- action item은 알람, 자동화, runbook, 테스트 중 무엇으로 남길 것인가?
찾아볼 문서
- 장애 회고에서 네트워크를 다루는 방법 상세
- 인프라 팀과 소통하는 방법 상세
- 백엔드 개발자와 인프라 협업 압축 정리
- 실제 502 사례와 장애 보고 상세
- 네트워크 장애 대응과 트러블슈팅 압축 정리
- 장애 가설 세우기 상세
실전 행동
- 회고 문서에는 “없어서 늦어진 증거”를 반드시 적는다.
- action item은 owner, 검증 방법, 완료 기준을 가진다.
- 다음 장애 때 첫 10분에 볼 dashboard와 log query를 runbook으로 남긴다.
정리
- 좋은 회고는 비난 없이도 다음 장애의 시간을 줄이는 시스템 변경으로 끝난다.
가져갈 한 문장
- 장애 회고의 성과는 멋진 원인 분석이 아니라 다음 대응 시간을 줄이는 증거 개선이다.
보충 실전 Case
기본 Case 1~20은 전체 문서를 한 번씩 실전 상황으로 다시 찾아가게 만드는 지도다. 보충 Case는 그중에서도 백엔드 개발자가 운영 중 자주 놓치거나, 인프라 팀과 맞추지 않으면 나중에 크게 터질 수 있는 세부 판단을 따로 훈련하기 위한 섹션이다.
보충 Case 1. Accept와 Content-Type은 맞아 보이는데 415/406이 난다
상황
- 파트너는 “JSON으로 보냈다”고 말하지만 API는
415 Unsupported Media Type을 낸다. - 또는 서버는 정상 응답을 만들었는데 client가
406 Not Acceptable을 받는다. - local curl은 성공하지만 gateway를 지나면 header가 달라진다.
관찰할 증거 또는 확인할 단서
- 실제 wire에 나간
Content-Type,Accept,Content-Encoding,Accept-Encoding을 본다. - Spring MVC의
consumes,produces,HttpMessageConverter, gateway header rewrite 여부를 나눈다. - 실패 요청과 성공 요청의 raw header를 HAR, access log, request dump로 비교한다.
먼저 생각해보기
Content-Type문제인가,Accept문제인가?- body는 JSON처럼 보여도 charset, boundary, compression, vendor media type이 다른가?
- Spring controller가 좁은 media type만 받도록 선언되어 있는가?
찾아볼 문서
실전 행동
- controller의 media type 계약을 코드에 명시하고, 문서와 테스트가 같은 값을 쓰게 한다.
@PostMapping(
value = "/orders",
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE
)
public ResponseEntity<OrderResponse> create(@RequestBody @Valid OrderRequest request) {
Order order = orderService.create(request);
return ResponseEntity.ok(OrderResponse.from(order));
}- 실패 요청은 client SDK가 아니라
curl로 다시 만들어 header 차이를 줄인다.
curl -i 'https://api.example.com/orders' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
--data '{"sku":"BOOK-1","quantity":1}'- gateway나 WAF가
Content-Type을 제거하거나 normalize하는지 access log와 config를 함께 확인한다.
정리
415는 “내가 보낸 body를 서버가 해석할 수 없음”이고,406은 “client가 받을 수 있다고 한 표현으로 서버가 응답할 수 없음”이다.
가져갈 한 문장
- media type 장애는 JSON 여부가 아니라 요청과 응답 표현 계약이 실제 경로에서 보존됐는지의 문제다.
보충 Case 2. ETag와 If-Match로 동시 수정 충돌을 막아야 한다
상황
- 관리자 화면에서 두 사람이 같은 상품 가격을 수정한다.
- 마지막 저장이 이기면서 앞선 사용자의 변경이 조용히 사라진다.
- DB optimistic lock은 있지만 HTTP API 계약에는 충돌 표현이 없다.
관찰할 증거 또는 확인할 단서
- 조회 응답에
ETag가 있는지 확인한다. - 수정 요청에
If-Match가 들어오는지 확인한다. - 충돌 시
409 Conflict와412 Precondition Failed중 어떤 의미가 맞는지 나눈다.
먼저 생각해보기
- 이 API는 “마지막 쓰기 승리”를 허용해도 되는가?
- client가 보고 있던 버전과 서버의 현재 버전이 다를 때 어떤 상태코드와 body를 줄 것인가?
- CDN/cache와 API 조건부 요청을 같은 용어로 설명하고 있는가?
찾아볼 문서
실전 행동
- 조회 응답은 현재 버전을
ETag로 돌려주고, 수정 요청은If-Match를 요구한다.
@GetMapping("/products/{id}")
public ResponseEntity<ProductResponse> get(@PathVariable long id) {
Product product = productService.get(id);
return ResponseEntity.ok()
.eTag("\"" + product.version() + "\"")
.body(ProductResponse.from(product));
}
@PutMapping("/products/{id}")
public ResponseEntity<ProductResponse> update(
@PathVariable long id,
@RequestHeader("If-Match") String ifMatch,
@RequestBody ProductUpdateRequest request
) {
Product updated = productService.updateIfVersionMatches(id, ifMatch, request);
return ResponseEntity.ok()
.eTag("\"" + updated.version() + "\"")
.body(ProductResponse.from(updated));
}- 버전 불일치는 조용한 overwrite가 아니라
412 Precondition Failed와 재조회 안내로 표현한다. ETag가 cache 최적화용인지, write precondition용인지 API 문서에서 분리해 설명한다.
정리
- 조건부 요청은 cache 절약 기능으로만 볼 수 없고, 쓰기 API의 동시성 계약으로도 쓸 수 있다.
가져갈 한 문장
- 동시 수정 충돌은 DB만의 문제가 아니라 HTTP 요청 조건을 client와 공유해야 줄어든다.
보충 Case 3. HTTP/3를 켰는데 일부 회사망과 모바일망에서만 느리다
상황
- CDN에서 HTTP/3를 활성화했다.
- 대부분은 빨라졌지만 일부 회사망, VPN, 구형 단말, 특정 통신사에서만 접속이 느리거나 간헐 실패한다.
- 서버 지표만 보면 오류가 거의 없다.
관찰할 증거 또는 확인할 단서
- ALPN 결과가
h3,h2,http/1.1중 무엇인지 확인한다. - UDP/443 차단, middlebox, QUIC fallback 지연을 의심한다.
- 같은 endpoint를 HTTP/3, HTTP/2로 각각 호출해 차이를 비교한다.
먼저 생각해보기
- 문제는 HTTP/3 자체인가, HTTP/3 실패 뒤 fallback 경로가 느린 것인가?
- CDN, LB, origin 중 어디까지 HTTP/3가 적용되는가?
- 장애 알림은 protocol별로 분리되어 있는가?
찾아볼 문서
실전 행동
- 같은 URL을 protocol별로 확인한다.
curl -I --http3 https://api.example.com/health
curl -I --http2 https://api.example.com/health
curl -w 'namelookup=%{time_namelookup} connect=%{time_connect} appconnect=%{time_appconnect} starttransfer=%{time_starttransfer} total=%{time_total}\n' \
-o /dev/null -s https://api.example.com/health- CDN log에서 protocol, region, ASN, user agent, error reason을 나눠 본다.
- HTTP/3 rollout은 전체 on/off보다 비율, region, host 단위로 되돌릴 수 있게 둔다.
정리
- HTTP/3는 더 빠른 길을 열어주지만, UDP 차단 환경에서는 fallback 품질이 사용자 경험을 결정한다.
가져갈 한 문장
- protocol upgrade는 평균 속도보다 fallback 실패와 특정 네트워크 구간의 꼬리 지연을 같이 봐야 한다.
보충 Case 4. 내부 API에 mTLS를 도입할지 결정해야 한다
상황
- 사내 서비스 간 호출에 mTLS를 도입하자는 제안이 나왔다.
- 보안팀은 강한 인증을 원하고, 개발팀은 인증서 운영 부담과 장애 가능성을 걱정한다.
- 일부 legacy client는 인증서 배포와 갱신 자동화가 준비되어 있지 않다.
관찰할 증거 또는 확인할 단서
- TLS termination 위치와 app이 실제 client identity를 어디서 얻는지 확인한다.
- 인증서 발급, 배포, rotation, 폐기, 만료 알림 owner가 정해져 있는지 본다.
- mesh, gateway, NGINX, app 중 어느 계층에서 mTLS를 끝낼지 결정한다.
먼저 생각해보기
- mTLS가 필요한 경계는 internet edge인가, service-to-service인가, 관리자 API인가?
- app은 인증서를 직접 검증해야 하는가, trusted proxy가 검증한 결과만 받아도 되는가?
- header로 client identity를 넘긴다면 그 header를 누가 만들고 누가 지울 수 있는가?
찾아볼 문서
실전 행동
- proxy에서 client certificate를 검증한다면 app으로 전달되는 identity header의 신뢰 경계를 문서화한다.
server {
listen 443 ssl;
ssl_certificate /etc/nginx/tls/server.crt;
ssl_certificate_key /etc/nginx/tls/server.key;
ssl_client_certificate /etc/nginx/pki/client-ca.pem;
ssl_verify_client on;
proxy_set_header X-Client-Verify $ssl_client_verify;
proxy_set_header X-Client-DN $ssl_client_s_dn;
proxy_pass http://internal-api;
}- app은 public internet에서 들어온 동일 header를 신뢰하지 않도록 trusted proxy 경계를 둔다.
- 도입 전에는 certificate rotation drill과 만료 알림을 smoke test 수준으로 검증한다.
정리
- mTLS는 “보안을 켠다”가 아니라 인증서 수명주기와 신뢰 경계를 운영 계약으로 만드는 일이다.
가져갈 한 문장
- mTLS의 난이도는 handshake가 아니라 인증서 배포, 갱신, 폐기, 신뢰 header 통제에 있다.
보충 Case 5. Spring WebClient timeout과 retry를 실제 장애 기준으로 조정한다
상황
- 외부 결제 API가 가끔 느려진다.
- 개발자는
WebClienttimeout을 늘리자고 하고, 운영자는 thread와 connection pool 고갈을 걱정한다. - retry를 넣었더니 장애 때 외부 API 호출량이 더 늘었다.
관찰할 증거 또는 확인할 단서
- connect timeout, response timeout, read/write timeout, pool acquire timeout을 분리한다.
- retry 횟수와 backoff가 전체 timeout budget 안에 들어오는지 계산한다.
- idempotency key와 retry 가능한 method/status가 정의되어 있는지 확인한다.
먼저 생각해보기
- timeout을 늘리면 사용자가 기다릴 가치가 있는 요청인가?
- retry는 사용자 성공률을 높이는가, downstream을 더 때리는가?
- breaker와 bulkhead가 없으면 장애가 어떤 pool까지 번지는가?
찾아볼 문서
실전 행동
- client 설정은 한 곳에서 만들고, API별 timeout budget을 명시한다.
@Bean
WebClient paymentWebClient(WebClient.Builder builder) {
HttpClient httpClient = HttpClient.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1_000)
.responseTimeout(Duration.ofSeconds(2));
return builder
.clientConnector(new ReactorClientHttpConnector(httpClient))
.baseUrl("https://payment.example.com")
.build();
}- retry는 “몇 번 더”가 아니라 전체 예산 안에서 backoff와 함께 제한한다.
resilience4j:
retry:
instances:
payment:
max-attempts: 2
wait-duration: 200ms
retry-exceptions:
- java.io.IOException
timelimiter:
instances:
payment:
timeout-duration: 2500ms- payment처럼 side effect가 있는 요청은 idempotency key 없이 자동 retry하지 않는다.
정리
- timeout과 retry는 안정성 기능이지만, budget 없이 켜면 장애 증폭 장치가 된다.
가져갈 한 문장
- Spring client 설정은 “느리면 더 기다리기”가 아니라 제한된 시간 안에서 실패를 격리하는 계약이다.
보충 Case 6. WAF, LB, DNS 변경 요청서를 써야 한다
상황
- 신규 관리자 API를 열기 위해 WAF rule, LB listener, DNS record 변경이 필요하다.
- 백엔드 팀은 “이 경로만 열어주세요”라고 말하고 싶지만, 인프라 팀은 impact, rollback, 검증 방법이 필요하다.
- 개인 프로젝트에서는 클릭 몇 번이면 끝났던 변경이 회사에서는 change window와 승인 절차를 거친다.
관찰할 증거 또는 확인할 단서
- 변경 대상 host, path, method, source, target, expected status, rollback 방법을 적는다.
- WAF allow rule이 필요한지, rate limit과 body size limit도 함께 바뀌는지 확인한다.
- DNS TTL, LB health check, certificate, logging, alert owner를 같이 본다.
먼저 생각해보기
- 이 변경은 외부 노출면을 넓히는가?
- 실패하면 사용자는 어떤 오류를 보고, 어느 지표가 먼저 움직이는가?
- rollback은 DNS 되돌리기인가, LB target 제외인가, WAF rule disable인가?
찾아볼 문서
- DNS TTL과 배포 전파 상세
- API Gateway와 WAF 상세
- LB 알고리즘과 Routing 상세
- 기업 운영 환경에서 챙길 네트워크 기준 상세
- 인프라 팀과 소통하는 방법 상세
실전 행동
- 변경 요청은 설정값 나열보다 검증 가능한 기대 결과를 중심으로 쓴다.
change_request:
service: admin-api
host: admin.example.com
path: /v1/reports/*
methods: [GET, POST]
source: office-vpn
target: admin-api-prod-8080
expected:
success_status: 200
blocked_status_from_public: 403
health_check: /actuator/health/readiness
risks:
- WAF false positive on large report filter body
- DNS propagation delay during rollback
validation:
- curl from office VPN
- curl from public network must be blocked
- LB target health all healthy
rollback:
- disable WAF allow rule
- detach new target group- 인프라 팀에는 “무엇을 바꿔주세요”와 함께 “어떻게 성공을 확인할지”를 준다.
- 개인 프로젝트에서도 이 템플릿을 줄여서 쓰면 배포 사고를 훨씬 빨리 되돌릴 수 있다.
정리
- 좋은 변경 요청은 인프라 담당자가 추측하지 않아도 되는 요청이다.
가져갈 한 문장
- 인프라 협업의 품질은 요청 문장보다 검증 조건과 rollback 조건에서 드러난다.
보충 Case 7. Header가 너무 크거나 민감정보가 로그에 남을 위험이 있다
상황
- 인증 관련 header와 cookie가 늘어나면서 일부 요청이
431 Request Header Fields Too Large를 낸다. - gateway access log에
Authorization,Cookie,Set-Cookie,X-Api-Key가 그대로 남을 수 있다. - observability를 위해 header를 더 남기자는 요구와 보안 요구가 충돌한다.
관찰할 증거 또는 확인할 단서
- client가 보내는 header 총 크기와 cookie 개수를 본다.
- proxy, LB, app server의 header size limit을 확인한다.
- log pipeline에서 민감 header가 redaction되는지 샘플 로그로 검증한다.
먼저 생각해보기
- 이 header는 routing, auth, tracing, debugging 중 무엇을 위해 필요한가?
- request id와 trace id만으로 충분한데 전체 header를 남기고 있지는 않은가?
- cookie에 넣은 상태가 session store나 token introspection으로 옮겨갈 수 있는가?
찾아볼 문서
실전 행동
- 애플리케이션 로그에서는 allowlist 방식으로 남길 header를 고른다.
private static final Set<String> SAFE_HEADERS = Set.of(
"x-request-id",
"traceparent",
"user-agent",
"x-forwarded-for"
);
String printableHeader(String name, String value) {
if (!SAFE_HEADERS.contains(name.toLowerCase(Locale.ROOT))) {
return "[redacted]";
}
return value;
}Authorization,Cookie,Set-Cookie, API key류는 기본적으로 남기지 않는다.- header size 문제는 limit을 키우기 전에 cookie scope, token 크기, 중복 header, proxy 추가 header를 줄인다.
정리
- header는 관측에도 필요하지만 인증 상태와 개인정보가 지나가는 통로이기도 하다.
가져갈 한 문장
- header 로그는 많이 남길수록 좋은 것이 아니라, 장애 판단에 필요한 것만 안전하게 남겨야 한다.
보충 Case 8. NAT, DNS, TLS 희귀 한계를 장애 전 runbook에 넣는다
상황
- 지금은 잘 동작하지만 이벤트, 대량 배치, 트래픽 급증 때 희귀한 한계가 터질까 걱정된다.
- ephemeral port, NAT table, conntrack, DNS resolver quota, file descriptor, certificate expiry 같은 항목은 평소 알림에서 잘 보이지 않는다.
- 장애가 나면 백엔드와 인프라가 서로 “우리 쪽은 정상”이라고 말할 가능성이 있다.
관찰할 증거 또는 확인할 단서
- outbound 연결 수와 destination 분포를 본다.
- NAT gateway, firewall, node conntrack, DNS resolver, TLS certificate 만료 알림을 확인한다.
- 장애 전후에 바로 실행할 명령과 cloud metric 이름을 runbook에 적는다.
먼저 생각해보기
- 이 서비스는 inbound보다 outbound가 병목이 될 수 있는가?
- 같은 destination으로 짧은 연결을 너무 많이 만들고 있지는 않은가?
- DNS cache, connection pool, keep-alive가 실제로 효과를 내고 있는가?
찾아볼 문서
실전 행동
- runbook에는 “나중에 보면 됨”이 아니라 장애 첫 10분에 볼 명령을 넣는다.
ss -s
ss -tan state time-wait | wc -l
cat /proc/sys/net/ipv4/ip_local_port_range
cat /proc/sys/net/netfilter/nf_conntrack_max
dig api.partner.example.com
openssl s_client -connect api.partner.example.com:443 -servername api.partner.example.com </dev/null- cloud 환경에서는 NAT gateway port allocation, connection count, DNS resolver error, LB rejected connection, TLS certificate expiry metric을 dashboard에 올린다.
- 개인 프로젝트에서도 최소한 certificate expiry, uptime check, DNS record, reverse proxy access log는 확인 가능하게 둔다.
정리
- 희귀 한계는 자주 일어나지 않아서 희귀한 것이 아니라, 터지기 전까지 보통 dashboard에 없어서 희귀해 보인다.
가져갈 한 문장
- 고급 운영 역량은 자주 보이는 오류보다 평소 보이지 않는 한계를 미리 관측 가능하게 만드는 데서 나온다.
개발 단계별 활용법
| 단계 | 이때 볼 Case | 활용 방식 |
|---|---|---|
| 설계 전 | Case 9, Case 11, Case 12, Case 17, 보충 Case 4, 보충 Case 6, 보충 Case 8 | 도메인, 인증, retry, capacity, 운영 증거를 설계 입력으로 넣는다. |
| 구현 중 | Case 3, Case 5, Case 6, Case 12, Case 18, 보충 Case 1, 보충 Case 2, 보충 Case 5, 보충 Case 7 | header, body, timeout, idempotency, cache policy를 코드 계약으로 명시한다. |
| 배포 전 | Case 2, Case 4, Case 7, Case 14, Case 15, 보충 Case 3, 보충 Case 4, 보충 Case 6 | TLS, DNS, CDN, LB, draining, protocol fallback을 smoke test에 넣는다. |
| 장애 대응 중 | Case 1, Case 8, Case 10, Case 13, Case 16, 보충 Case 1, 보충 Case 3, 보충 Case 5, 보충 Case 7, 보충 Case 8 | 응답 주체, 마지막 관측 계층, queue 위치, 정책 차단 여부를 빠르게 나눈다. |
| 회고/개선 시 | Case 17, Case 18, Case 19, Case 20, 보충 Case 6, 보충 Case 8 | 누락된 log/metric/runbook/action item을 다음 운영 기준으로 바꾼다. |
커버리지 지도
| 기존 문서 | 연결된 Case | 이 문서가 필요한 이유 |
|---|---|---|
| 웹 요청 흐름 전체 지도 압축 정리 | 16 | 전체 장애 대응의 첫 지도 역할 |
| 전체 요청 경로 상세 | 1, 16 | 요청이 어느 계층까지 갔는지 분리 |
| 계층별 관찰 지점 상세 | 1, 16 | 계층별 log/metric 관찰 포인트 |
| 브라우저와 서버 경계 상세 | 3 | 브라우저 보안 정책과 서버 응답 분리 |
| 로그와 Trace ID로 따라가기 상세 | 1, 16, 보충 7 | request id로 계층별 로그 연결과 header redaction 판단 |
| 장애 가설 세우기 상세 | 16, 20 | 추측을 검증 가능한 가설로 전환 |
| URL URI DNS 압축 정리 | 11, 14 | URL/DNS/도메인 변경의 빠른 지도 |
| URI와 URL 구조 상세 | 11 | redirect, path, query, origin 판단 |
| DNS 조회와 레코드 상세 | 11, 14 | DNS record와 resolver 증거 확인 |
| DNS TTL과 배포 전파 상세 | 2, 14, 보충 6 | DNS 전환, 변경 요청, rollback 판단 |
| 도메인 설계와 보안 상세 | 11 | cookie/CORS/TLS/OAuth 보안 경계 설계 |
| IP TCP UDP 기본 압축 정리 | 10, 17 | IP/port/TCP/UDP 운영 비용의 빠른 지도 |
| IP와 포트 라우팅 상세 | 10, 17 | bind address, firewall, target port 판단 |
| TCP Handshake와 상태 상세 | 8, 10 | TCP 상태와 연결 실패 증거 확인 |
| UDP와 QUIC 기본 상세 | 15, 보충 3 | HTTP/3, QUIC, UDP fallback 판단 |
| OS 네트워크 관찰 상세 | 10, 보충 8 | socket, FD, port, conntrack 관찰 |
| TCP 연결 Keep-Alive Connection Pool 압축 정리 | 5, 7, 10 | 연결 재사용과 pool 장애의 빠른 지도 |
| Keep-Alive 동작 상세 | 7, 15 | 연결 재사용, idle socket, protocol 영향 |
| HTTP Client Connection Pool 상세 | 1, 5, 12, 보충 5 | external call pool pending과 timeout 판단 |
| 서버 Socket Thread Backlog 상세 | 10 | backlog, worker thread, accept queue 판단 |
| Idle Timeout 불일치 상세 | 7 | stale connection과 장기 연결 끊김 판단 |
| Pool 고갈 장애 상세 | 5, 10 | DB/HTTP/thread pool 고갈 판단 |
| HTTP 기본 구조 압축 정리 | 6, 12 | HTTP 메시지 계약의 빠른 지도 |
| 요청과 응답 메시지 상세 | 12, 16, 보충 1, 보충 7 | request/response 구조와 request id 판단 |
| Message Framing과 Body 상세 | 6 | upload/body/chunked/framing 판단 |
| HTTP 버전별 차이 상세 | 15, 보충 3 | HTTP/1.1, HTTP/2, HTTP/3 차이 판단 |
| Content Negotiation과 Encoding 상세 | 18, 보충 1 | Vary, compression, content negotiation 판단 |
| HTTP Method Status Code Header 압축 정리 | 12, 16 | method/status/header 운영 해석의 빠른 지도 |
| Method와 멱등성 상세 | 12, 보충 2 | retry 가능성과 method 의미 판단 |
| Status Code 운영 해석 상세 | 6, 8, 19, 보충 2 | status code를 응답 주체와 다음 확인으로 연결 |
| Header 설계와 관찰 상세 | 13, 18, 보충 1, 보충 7 | header 신뢰 경계와 관측 기준 |
| API 응답 계약 상세 | 12, 13, 보충 1 | client 행동을 안내하는 response contract |
| HTTPS TLS 인증서 압축 정리 | 4, 15 | TLS/인증서 전체 빠른 지도 |
| TLS Handshake 상세 | 4, 15, 보충 3 | handshake timing, ALPN, TLS policy 판단 |
| 인증서 Chain과 SNI 상세 | 4, 11, 보충 4 | chain, SAN, SNI, truststore 판단 |
| TLS Termination과 mTLS 상세 | 4, 17, 보충 4 | termination 위치, mTLS, forwarded proto 판단 |
| TLS 디버깅 상세 | 4, 16, 보충 8 | TLS 장애 재현 명령과 report evidence |
| Cookie Session SameSite CORS 압축 정리 | 3, 18 | 브라우저 인증 경계의 빠른 지도 |
| Cookie 속성 상세 | 3, 11 | Set-Cookie, Domain, Path, Secure 판단 |
| Session과 인증 상태 상세 | 3, 19 | session scale out과 인증 상태 판단 |
| SameSite와 CSRF 상세 | 3 | SameSite, CSRF, OAuth redirect 판단 |
| CORS와 Preflight 상세 | 3, 13 | preflight, credential CORS, gateway 소유권 |
| 브라우저 보안 디버깅 상세 | 3 | DevTools, HAR, browser-only failure 판단 |
| Cache CDN Conditional Request 압축 정리 | 2, 18, 19 | cache/CDN/조건부 요청 빠른 지도 |
| HTTP Cache 기본 상세 | 2, 18 | Cache-Control, Vary, shared cache 판단 |
| ETag와 Conditional Request 상세 | 2, 19, 보충 2 | ETag, 304, conditional request 판단 |
| CDN Origin과 Purge 상세 | 2, 14 | CDN cache key, purge, origin 비교 |
| Cache 정합성 장애 상세 | 2, 19, 보충 2 | stale data, purge event, 권한/가격 정합성 |
| Cache 성능과 보안 상세 | 18 | cache poisoning, private data, safe headers |
| Proxy Reverse Proxy Gateway 압축 정리 | 8, 13 | proxy/gateway/WAF 빠른 지도 |
| Proxy와 Reverse Proxy 역할 상세 | 8, 17, 보충 7 | 응답 주체와 reverse proxy 역할 판단 |
| NGINX Timeout과 Buffer 상세 | 6, 7, 15, 보충 3 | timeout, buffer, upload, long connection 판단 |
| Forwarded Header와 Client IP 상세 | 4, 13, 17 | client IP, trusted proxy, forwarded proto 판단 |
| API Gateway와 WAF 상세 | 13, 보충 6 | WAF, rate limit, gateway policy 판단 |
| Path Rewrite와 Upstream 상세 | 8 | path rewrite, upstream DNS, normalization 판단 |
| Load Balancer Health Check Traffic Routing 압축 정리 | 8, 14 | LB/health/routing 빠른 지도 |
| LB 알고리즘과 Routing 상세 | 9, 14, 보충 6 | canary, weighted routing, target group 판단 |
| Health Check와 Readiness 상세 | 8, 9 | liveness/readiness/probe 판단 |
| Idle Timeout과 장기 연결 상세 | 7 | LB idle timeout과 장기 연결 판단 |
| 배포와 Draining 상세 | 14, 17 | draining, graceful shutdown, rollback 판단 |
| Cloud LB 디버깅 상세 | 8 | cloud LB access log와 target health 판단 |
| Timeout Retry Idempotency Circuit Breaker 압축 정리 | 5, 12 | timeout/retry/idempotency 빠른 지도 |
| Timeout 종류와 정렬 상세 | 1, 5, 보충 5 | timeout chain과 정렬 판단 |
| Retry와 장애 증폭 상세 | 5, 12, 13, 보충 5 | retry storm, Retry-After, budget 판단 |
| Idempotency Key 상세 | 12 | 중복 결제/중복 처리 방지 |
| Circuit Breaker Bulkhead Fallback 상세 | 5 | 장애 격리, fallback, breaker 판단 |
| Spring과 Resilience 설정 상세 | 5, 보충 5 | Spring client timeout과 Resilience4j 설정 |
| 대용량 트래픽과 네트워크 병목 압축 정리 | 9, 10 | 대용량 병목 빠른 지도 |
| Capacity Planning 상세 | 9, 보충 8 | SLO, headroom, shared resource 계산 |
| 병목 구분 상세 | 1, 9, 10 | queue 위치와 metric 기반 병목 분리 |
| 부하 테스트와 관측 상세 | 9 | load/stress/spike 테스트와 관측 |
| Backpressure와 Rate Limit 상세 | 9, 13 | rate limit, load shedding, retry storm 방지 |
| 희귀하지만 중요한 한계 상세 | 10, 보충 8 | ephemeral port, NAT, DNS, FD, conntrack 한계 |
| 네트워크 장애 대응과 트러블슈팅 압축 정리 | 16, 20 | 장애 대응 전체 빠른 지도 |
| 장애를 계층별로 의심하는 방법 상세 | 16 | 장애 초반 계층별 분리 |
| 타임아웃과 지연 장애 분석 상세 | 1, 16 | tail latency와 timeout 분석 |
| HTTP 상태코드별 병목 구간 상세 | 8, 16 | 4xx/5xx/status별 다음 확인 |
| 요청 유형별 네트워크 판단 상세 | 6, 7 | 업로드, 장기 연결, 모바일 요청 판단 |
| 실제 502 사례와 장애 보고 상세 | 8, 16, 20 | 502 보고와 장애 증거 전달 |
| 백엔드 개발자와 인프라 협업 압축 정리 | 17, 20 | 협업과 운영 기준 빠른 지도 |
| 개인 프로젝트에서 챙길 네트워크 기준 상세 | 17 | 개인 프로젝트 운영 품질 기준 |
| 팀 서비스 운영에서 챙길 네트워크 기준 상세 | 16, 17, 보충 8 | 팀 공통 운영 계약과 runbook |
| 기업 운영 환경에서 챙길 네트워크 기준 상세 | 14, 17, 보충 4, 보충 6 | 변경 관리, SLO, 보안, multi-AZ 판단 |
| 인프라 팀과 소통하는 방법 상세 | 13, 16, 20, 보충 4, 보충 6 | 인프라 요청 정보와 증거 전달 |
| 장애 회고에서 네트워크를 다루는 방법 상세 | 20 | postmortem과 action item 설계 |
가져갈 판단 기준
- 상태코드는 결론이 아니라 응답 주체와 다음 확인 계층을 좁히는 단서다.
- app log가 없다는 말은 app 이전 계층의 증거가 더 필요하다는 뜻일 수 있다.
- timeout을 늘리기 전에 queue, pool, retry, downstream quota를 본다.
- cache는 성능 기능이 아니라 데이터 정합성과 보안 경계를 바꾸는 응답 계약이다.
- 브라우저 문제는 서버 응답, 브라우저 저장, 브라우저 전송, JavaScript 노출을 나눠야 보인다.
- TLS와 DNS 변경은 “설정 완료”보다 실제 endpoint 검증과 rollback 가능성이 중요하다.
- scale out은 app capacity만 늘리는 것이 아니라 shared resource 부하도 함께 늘린다.
- 인프라 협업은 요청을 던지는 일이 아니라 증거, 기대 결과, owner, rollback을 맞추는 일이다.