이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.
- 평소에는 안 보이다가 대량 트래픽에서 터지는 OS/cloud/network 한계는 무엇인가?
- ephemeral port, NAT gateway, DNS resolver, file descriptor, conntrack, TLS handshake 한계를 어떤 증상과 명령으로 확인하는가?
- 희귀 장애를 인프라 팀과 소통 가능한 runbook으로 어떻게 남기는가?
개요
트래픽이 커지면 평소에는 보이지 않던 하한선이 드러난다. 코드는 바뀌지 않았는데 outbound timeout이 늘고, DNS가 가끔 실패하고, connection refused와 timeout이 섞이고, 특정 AZ만 실패한다. 이런 문제는 앱 로그만 보면 원인이 흐릿하다. OS와 cloud network 한계를 알고 있어야 빠르게 분리할 수 있다.
- ephemeral port exhaustion은 outbound connection을 만들 local port가 부족한 상황이다.
- NAT gateway port exhaustion은 private subnet의 많은 outbound 연결이 NAT 한계를 넘는 상황이다.
- DNS resolver throttling은 많은 lookup이 지연/실패하는 상황이다.
- file descriptor limit은 socket/file을 더 열 수 없는 상황이다.
- conntrack table full은 커널이 연결 추적 정보를 더 유지하지 못하는 상황이다.
- TLS handshake spike는 CPU와 latency를 동시에 올릴 수 있다.
원리
희귀 한계는 대부분 “공유 테이블”이 찬다.
process fd table
kernel socket table
ephemeral port range
conntrack table
NAT translation table
DNS resolver quota
LB connection/LCU quota공유 테이블은 app instance를 늘리면 함께 더 빨리 찰 수 있다. 그래서 scale out이 완화가 아니라 증폭이 되는 경우가 있다.
증상별 후보
| 증상 | 후보 |
|---|---|
| outbound connect timeout 증가 | NAT port, firewall, external API, SYN backlog |
Cannot assign requested address | ephemeral port exhaustion |
Too many open files | file descriptor limit |
| DNS lookup timeout | resolver QPS/throttling, search domain 폭증 |
| 간헐적 502/504 | LB target reset, port exhaustion, conntrack |
| TLS handshake latency 증가 | CPU, cert verification, no session reuse |
| 특정 AZ만 실패 | subnet route, NAT, target health, zonal imbalance |
코드와 명령으로 확인하기
socket 요약을 본다.
ss -s
ss -tan state time-wait | wc -l
ss -tan state established | wc -lephemeral port 범위와 사용량을 본다.
cat /proc/sys/net/ipv4/ip_local_port_range
cat /proc/sys/net/ipv4/tcp_tw_reusefile descriptor 한계를 본다.
ulimit -n
pid=$(pgrep -f 'java.*app' | head -1)
lsof -p "$pid" | wc -lconntrack을 쓰는 환경에서는 테이블 사용량을 확인한다.
cat /proc/sys/net/netfilter/nf_conntrack_count
cat /proc/sys/net/netfilter/nf_conntrack_max명령은 Linux 기준이다. container, managed platform, macOS에서는 접근 방식이 다르므로 운영 환경별 대체 명령을 runbook에 남긴다.
NAT와 DNS 한계
Private subnet에서 외부 API를 많이 호출하면 NAT gateway가 병목이 될 수 있다. 증상은 외부 API timeout처럼 보이지만 실제로는 우리 VPC outbound path가 막힌 것이다.
DNS도 마찬가지다. 짧은 TTL, connection pool 미사용, service discovery polling, 잘못된 DNS cache 설정이 겹치면 resolver QPS가 튄다.
확인할 질문은 다음과 같다.
- outbound 대상 host별 connection 수는 얼마인가?
- HTTP keep-alive와 connection pool이 동작하는가?
- DNS cache TTL과 JVM DNS cache 설정은 무엇인가?
- NAT gateway metric에서 port allocation error가 있는가?
- 특정 AZ/NAT만 실패하는가?
TLS Handshake Spike
트래픽 spike 때 connection reuse가 안 되면 TLS handshake가 급증한다. CPU 사용률과 time_appconnect가 같이 오른다.
curl -w 'tcp=%{time_connect} tls=%{time_appconnect} first_byte=%{time_starttransfer} total=%{time_total}\n' \
-o /dev/null -s https://api.example.com/health완화는 keep-alive, connection pool, TLS session resumption, CDN/LB offload, autoscaling warm-up을 함께 본다.
인프라 협업 포인트
- 앱 팀은 outbound 대상, connection pool 설정, retry 정책, DNS cache 설정을 제공한다.
- 인프라 팀은 NAT gateway metric, subnet/AZ, security group/NACL, conntrack, resolver metric, LB quota를 제공한다.
- cloud quota는 장애 전에 올려야 한다. 한도 증액은 장애 중 즉시 되지 않을 수 있다.
- runbook에는 “증상 → 확인 metric → 완화”를 표로 남긴다.
실전 팁
- outbound HTTP client는 keep-alive와 pool을 기본으로 쓴다. 매 요청 새 connection은 port/TLS/DNS 비용을 키운다.
- retry는 port와 connection을 더 소모한다. timeout 증가와 retry 증가는 NAT/port 장애를 악화시킬 수 있다.
- DNS cache를 무한으로 두면 전환이 늦고, 너무 짧게 두면 resolver가 병목이 된다.
- file descriptor limit은 container와 host 양쪽을 확인한다.
- 개인 프로젝트는 이런 한계를 다 겪지 않더라도
ulimit,ss,curl -w, provider quota 페이지를 알아 두면 갑자기 수준이 올라간다.
위험 신호!
- 외부 API timeout이 늘었는데 NAT/DNS/port metric을 보지 않는다.
- HTTP client connection pool 없이 매 요청 새 client를 만든다.
- retry를 늘려 장애를 완화하려 한다.
- cloud quota와 NAT/AZ 구성을 아무도 모른다.
확인 질문
확인 질문
- scale out이 ephemeral port/NAT 문제를 악화할 수 있는 이유는 무엇인가?
- instance가 늘면서 outbound connection 시도와 NAT translation 사용량이 같이 증가할 수 있기 때문이다.
Cannot assign requested address가 outbound 호출에서 보이면 무엇을 의심해야 하는가?
- local ephemeral port exhaustion이나 socket 자원 고갈을 의심해야 한다.
- 희귀 한계 runbook에 반드시 들어가야 할 것은 무엇인가?
- 증상, 확인 명령/metric, 관련 owner, 즉시 완화, 장기 개선, 재발 알람 기준이다.