← 문제로

11. MTU·MSS·IP 단편화와 Path MTU Discovery, UDP 게임 패킷 크기 설계

난이도 중
내 답안
모범답안

모범답안 — MTU·MSS·IP 단편화와 Path MTU Discovery, UDP 게임 패킷 크기 설계

난이도: 중

1. MTU와 MSS

MTU(Maximum Transmission Unit) 는 링크 계층(L2)이 한 번에 실어 나를 수 있는 IP 패킷(헤더 포함)의 최대 바이트다. 이더넷의 전형적 MTU는 1500바이트. 인터페이스/링크마다 다르다(PPPoE 1492, 일부 터널 더 작음).

MSS(Maximum Segment Size) 는 TCP가 한 세그먼트에 담는 페이로드(데이터)의 최대 크기로, 전송 계층(L4) 개념이다. TCP 3-way handshake의 SYN에서 서로 광고한다.

이더넷에서 IPv4/TCP의 전형적 MSS = 1500 − 20(IP 헤더) − 20(TCP 헤더) = 1460바이트. 즉 MTU에서 IP·TCP 헤더를 뺀 값이다(옵션이 있으면 더 작아짐). UDP라면 1500 − 20 − 8(UDP 헤더) = 1472바이트가 단편화 없이 보낼 수 있는 페이로드 상한.

2. IP 단편화

IP 데이터그램이 다음 링크의 MTU보다 크면, 그 링크로 내보내는 라우터(또는 송신 호스트) 가 데이터그램을 MTU에 맞는 여러 단편(fragment) 으로 쪼갠다. 각 단편은 같은 IP ID와 오프셋을 갖고, 최종 목적지 호스트에서만 재조립된다(중간 라우터는 재조립하지 않음).

단편화가 나쁜 이유:

  • 전부-아니면-전무 유실: 단편 중 하나라도 유실되면 전체 데이터그램이 버려진다. UDP에는 재전송이 없으므로, 큰 UDP 스냅샷을 4조각으로 보내면 한 조각만 잃어도 스냅샷 전체가 사라진다(개별 패킷 손실률이 곱으로 커진 효과).
  • 재조립 비용·메모리: 수신 호스트가 단편을 모아 두는 버퍼·타이머가 필요하고, 타임아웃 시 폐기.
  • 방화벽/NAT가 비초기 단편(첫 단편 외)을 자주 드롭한다(포트 정보가 없어 필터링이 어려움) → 단편화된 트래픽이 통째로 막히기도.
  • 보안: 단편 중첩/타이밍 공격의 표면이 된다.

IPv6는 경로 중간 라우터가 단편화하지 않는다(송신자만 가능). MTU 미만이면 ICMPv6 Packet Too Big을 돌려준다.

3. Path MTU Discovery(PMTUD)

경로 전체에서 단편화 없이 보낼 수 있는 최소 MTU(=Path MTU)를 찾는 메커니즘.

  • 송신자는 IPv4 헤더의 DF(Don't Fragment) 비트를 1로 설정해 보낸다.
  • 경로 중간 라우터가 "다음 링크 MTU보다 큰데 DF=1이라 쪼갤 수 없음"을 만나면 패킷을 버리고 ICMP type 3 code 4 "fragmentation needed (and DF set)" 를 송신자에게 돌려주며, 그 안에 다음 홉 MTU를 담는다.
  • 송신자는 그 값으로 Path MTU를 낮추고 재전송. 이 과정을 반복해 수렴한다. (TCP는 자연스럽게 MSS를 줄이고, UDP 앱은 소켓 옵션/ICMP를 받아 처리.)

PMTUD 블랙홀: 방화벽이 ICMP를 일괄 차단하면, 라우터가 보낸 "fragmentation needed"가 송신자에게 도달하지 못한다. 송신자는 패킷이 왜 사라지는지 모른 채 같은 큰 크기로 계속 보내고 → 큰 패킷만 조용히 사라진다. 증상은 "작은 요청/핸드셰이크는 되는데, 큰 응답이나 특정 크기 이상에서 멈춤/타임아웃"(예: TLS 핸드셰이크는 되는데 큰 인증서·데이터 전송이 행). 진단이 까다롭다.

완화: ICMP "fragmentation needed"는 막지 말 것, MSS 클램핑(아래), TCP의 PMTUD 블랙홀 탐지(MTU를 점진적으로 낮춰 재시도), 보수적 패킷 크기.

4. 제보 진단과 UDP 패킷 크기 설계

제보의 가장 유력한 원인은 그 클라이언트 경로의 MTU가 1500보다 작은데(터널/VPN/PPPoE), 큰 UDP 스냅샷이 단편화되거나 DF로 드롭되고 ICMP가 막혀 블랙홀이 된 것이다.

설계 원칙:

  • 단편화를 피하도록 보수적으로 작게. 안전한 UDP 페이로드 상한으로 ~1200바이트를 쓴다(QUIC도 초기/기본을 ~1200으로 잡는 이유 — 거의 모든 경로가 1280 이상 보장, IPv6 최소 MTU가 1280). 1472에 딱 맞추면 작은 MTU 경로에서 깨진다.
  • 애플리케이션 레벨 분할/재조립: 스냅샷이 크면 IP 단편화에 맡기지 말고 앱에서 1200바이트 단위로 쪼개고 시퀀스/조각번호로 재조립, 손실 조각만 재전송(신뢰 UDP 설계와 연동). 그래야 한 조각 손실이 전체 손실로 번지지 않는다.
  • 델타/우선순위: 매번 풀 스냅샷 대신 델타 압축으로 패킷을 작게. 중요 데이터 우선.
  • TCP 경로엔 MSS 클램핑: 게이트웨이/터널 구간에서 SYN의 MSS를 경로 MTU에 맞게 낮춰(clamp) 단편화·블랙홀을 예방.
  • 측정: 클라이언트가 DF로 크기를 키워가며 Path MTU를 직접 탐색(PLPMTUD, ICMP에 의존하지 않는 방식)하거나, 보수값에서 시작해 안전하게 키운다.

정리

MTU는 링크가 나르는 최대 IP 패킷, MSS는 TCP 페이로드 상한(≈MTU−헤더). 경로 MTU를 넘으면 IP 단편화가 일어나고, UDP에선 단편 하나 손실이 전체 손실이라 치명적이다. PMTUD는 DF+ICMP로 경로 MTU를 찾지만 ICMP 차단 시 블랙홀이 된다. 그래서 실시간 UDP는 ~1200바이트 보수적 크기 + 앱 레벨 분할/재조립으로 설계하는 것이 정석이다.