대규모 동시 접속에서 “느림”은 코드보다 커널 네트워킹 경계에서 먼저 옵니다. TCP 핸드셰이크, Time-Wait 폭증, 임시 포트 고갈은 FD·메모리·큐를 잡아먹고 p95/p99 지연과 타임아웃을 끌어올립니다. 아래는 앞서 정리한 내용을 같은 소제목 그대로 더 깊게 풀어쓴 확장판입니다. 현장에서 바로 적용할 수 있는 값, 절차, 함정을 함께 담았습니다.
1) TCP 핸드셰이크 비용 줄이기: SYN 큐와 백로그
- 백로그 용량 산정: 피크 rps × 평균 핸드셰이크 시간(초) × 여유 1.5배.
예) 피크 8k rps, 평균 12ms라면 8,000×0.012×1.5 ≈ 144 → tcp_max_syn_backlog/somaxconn은 4096 이상으로 시작. - listen(backlog) 일치: 앱의 listen(backlog)가 작으면 커널 상향이 무의미합니다. 프레임워크/런타임(nginx, Node, Go, Java NIO)의 기본값을 확인하세요.
- SYN 재전송과 타임아웃: tcp_synack_retries(서버), tcp_syn_retries(클라이언트 역할 서버)를 과격히 낮추면 불안정 망에서 접속 실패가 늘어납니다. 살짝만 줄이고 관측으로 확인하세요.
- NIC·IRQ 튜닝: netdev_max_backlog 상향과 함께 RSS/멀티큐, IRQ 바인딩을 맞추면 급격한 합류 트래픽에서도 패킷 드롭이 줄어듭니다.
- SYN cookies 운용: 공격/캠페인 시 급히 켜되, 상시 ON은 지양(옵션 협상 제한). WAF/LB 계층 방어와 병행이 바람직합니다.
- TCP Fast Open(TFO): tcp_fastopen=3(클라/서버)로 실험하되, 중간 장비 호환성을 체크. 세션 ID 캐시 사이즈, 만료 정책도 함께 관리하세요.
2) Time-Wait 폭증 다루기: “새 연결 남발”을 먼저 멈추기
- 유휴 연결 재사용률: “Time-Wait 개수” 자체보다 새 연결/초(new conn/s) 가 핵심. Keep-Alive, HTTP/2 멀티플렉싱, HTTP/3로 연결 생성률을 낮추면 Time-Wait가 자연 감소합니다.
- 애플리케이션 에이전트 설정:
- Node/undici: keepAlive: true, connections: N, pipelining/h2 활용
- Java/OkHttp: ConnectionPool(maxIdle, keepAlive)
- Nginx 업스트림: keepalive N
프록시—오리진—앱 전 구간에 일관되게 적용해야 효과가 납니다.
- FIN/ACK 경계: tcp_fin_timeout을 무턱대고 낮추면 재전송 세그먼트 처리가 미흡해지고, NAT 환경에서 이상 종료가 늘 수 있습니다. 30초 안팎에서 출발해 지표 기반 조정.
- 금지 옵션 리마인드: 과거 tcp_tw_recycle 은 NAT 환경에서 오탐 종료를 초래해 제거됐습니다. 대체재 없습니다. 재사용률 향상이 정석입니다.
3) 임시 포트 고갈 해결: 범위·재사용·패턴
- 포트 범위 모델: 동시 아웃바운드 연결 수 ≈ (아웃바운드 rps × 평균 요청 시간) × 여유 20%. 이 수가 ip_local_port_range 크기보다 크면 고갈 위험.
예) 12k rps × 80ms ≈ 960 동시 + 여유 → 최소 수천 포트 필요. - NAT/LB 고려: 소스포트가 NAT에서 재사용되면 5-튜플 충돌. LB 해시 정책(소스포트 포함 여부)과 서버 포트 범위를 함께 설계해야 합니다.
- tw_reuse?: 현대 커널에서 의미 제한적이고 리스크 큽니다. Keep-Alive 비율을 올리는 것이 항상 우선입니다.
- 포트 소모 패턴 점검: 특정 도메인/리전에 과도 집중 시, DNS RR/가중 라우팅을 재분배. 동일 오리진으로의 동시 연결 상한을 풀별로 제한하세요.
4) 소켓 버퍼·큐·FD의 균형
- 윈도우/버퍼 상·하한:고대역-고지연(BDP↑) 구간은 상한을 키워야 스루풋이 나옵니다. 반대로 메모리 압박 시 OOM과 컨텍스트 스위치가 증가—관측과 함께 단계 상향.
-
tcp_rmem = 4k 87k 128M tcp_wmem = 4k 64k 128M rmem_max/wmem_max = 128M
- FD 한도와 커널 전역: ulimit -n(프로세스), fs.file-max(전역)를 모두 올리고, 컨테이너라면 pod securityContext/sysctls 또는 DaemonSet 기반 OS 레벨 조정이 필요합니다.
- 큐 백프레셔: 앱/프록시에서 큐 길이와 대기 타임아웃을 정의하고 초과분은 즉시 실패(429/503)로 상류 폭주를 차단. 큐에 “쌓아서 버티기”는 전체 반응성을 무너뜨립니다.
- IRQ/소켓 분배: NUMA 환경에서 NIC 큐—IRQ—워커 스레드—소켓을 같은 NUMA 노드로 핀핑하면 L3 캐시 미스와 크로스-노드 메모리 접근이 줄어듭니다.
5) 안전한 기본값 세트(시작점)
- 롤아웃 절차: (1) 동일 요일/시간대 베이스라인 24–72시간 → (2) 한 번에 한 항목만 변경 → (3) 전/후 p95/p99·drop·재전송률 비교 → (4) 롤백 플랜 명시.
- 클라우드 주의: 매니지드 LB/방화벽이 상위 타임아웃을 강제할 수 있습니다. 커널만 바꾸고 좋아지지 않는 이유의 절반은 경계 장비 불일치입니다.
6) 애플리케이션·프록시와의 맞물림
- Keep-Alive/HTTP-2/3: 커널 튜닝보다 먼저 할 일. 새 연결/초를 낮춰 Time-Wait·포트 고갈을 원천 완화합니다.
- 엔드포인트별 풀 분리: 무거운 리포트와 가벼운 조회를 같은 풀에 섞지 마세요. 풀 분리 또는 가중치로 공정성 확보.
- TLS 최적화: 세션 재개/OCSP 스테이플링/ECDSA 인증서로 핸드셰이크 지연·CPU를 동시에 절감. 커널 손대기 전 큰 효과가 납니다.
- 헤더/쿠키 다이어트: 거대한 쿠키/헤더는 동일 연결 처리량을 깎습니다. 불필요 항목 제거, 압축 임계치 설정으로 throughput/conn을 끌어올리세요.
- 컨테이너/K8s: sysctl 은 노드/파드 레벨 모두 고려. DaemonSet으로 커널 파라미터를 표준화하고, PodDisruptionBudget으로 롤링 중 용량 하락을 방지.
7) 관측 대시보드: “느림”을 숫자로 보기
- 지연/성공률: TTFB, 전체 응답, p95/p99, 4xx/5xx/타임아웃 분리
- 연결: 새 연결/초, 활성/유휴, ESTABLISHED/TIME_WAIT 카운트, 재사용률(Keep-Alive hit)
- 소켓/포트: 사용 FD, ip_local_port_range 사용률, listen 큐 드롭, accept 오류
- 네트워크 품질: 인터페이스 드롭, 재전송률, CPU sys%, NIC 큐 드롭
- 경계 지표: LB 4xx/5xx, 아이들 타임아웃 종료 수, NAT 포트 사용률
모든 지표를 릴리스/캠페인/스케일 이벤트 타임라인과 한 화면에 겹치면 인과관계가 선명해집니다.
8) 체크리스트(바로 적용)
- somaxconn·tcp_max_syn_backlog·netdev_max_backlog 상향
- ip_local_port_range 확대, new conn/s 모니터
- Time-Wait는 Keep-Alive/HTTP-2/3 로 해결(옵션 삭제 아님)
- tcp_fin_timeout 완만 조정(과도 단축 금지)
- SYN Flood 대비 tcp_syncookies=1(상황별)
- FD/메모리 한도 상향, NUMA/IRQ 핀핑
- LB/NAT 타임아웃·해시 정책과 정렬
- 롤아웃은 한 번에 하나 + 전/후 A/B 지표 비교
9) 자주 묻는 질문
Q. Time-Wait를 “없애는” 방법 있나요?
안전하게 없습니다. 프로토콜 보호 장치입니다. 새 연결 생성률을 낮추고 재사용률을 올리는 것이 정답입니다.
Q. 포트 범위를 크게 잡으면 끝인가요?
응급 처치일 뿐. 새 연결이 계속 많으면 언젠가 다시 고갈됩니다. Keep-Alive·멀티플렉싱·풀 설계가 근본 해결입니다.
Q. SYN cookies를 항상 켜둘까요?
공격·피크 방어에는 유용하지만 옵션 협상 제한이 있어 상황별로. WAF/LB와 병행하세요.
Q. 커널만 바꾸면 개선되나요?
절반은 경계 장비(LB/NAT/CDN) 타임아웃·해시 정책 불일치 문제입니다. 엔드-투-엔드로 보세요.
Q. 컨테이너에서도 동일하게 적용되나요?
노드 레벨 sysctl 권한, CNI/호스트 네트워크 스택 제약을 확인해야 합니다. DaemonSet·PSP/SA 권한으로 표준화하세요.
마무리
핸드셰이크·Time-Wait·포트 고갈은 서로 얽힌 한 묶음입니다.
1) SYN/수신 큐를 넉넉히, 2) 연결 재사용률을 끌어올리고, 3) 포트 범위·FD·버퍼를 균형 있게 키우면 같은 인프라로 더 많은 동시성을 안전하게 소화합니다. 오늘은 somaxconn/tcp_max_syn_backlog/ip_local_port_range부터 정렬하고, 내일은 Keep-Alive/HTTP-2/3 전환과 풀 분리를 마저 적용하세요. 대시보드에서 p95/p99·new conn/s·TIME-WAIT가 함께 내려가는 걸 확인하게 될 것입니다.