TT Lab
시작하기
배우기 러닝패스 코스

네트워크 기초

MTU 와 경로 — 크기 때문에만 실패하는 통신

TT Lab 에서 이어서 보기

한 줄 요약

TCP 는 자기 인터페이스의 MTU 만 보고 세그먼트 크기를 정하므로 경로 중간의 좁은 구간을 알지 못하며, 그 사실을 알려 주는 ICMP 를 막으면 큰 패킷만 조용히 사라지는 블랙홀이 생긴다.

왜 이게 필요했나

증상이 유난히 특이한 장애가 있다.

이 조합이면 다른 것을 볼 필요가 없다. 경로 MTU 문제다. 그리고 대개 VPN, 터널, 오버레이 네트워크를 새로 붙였거나 경로가 바뀐 직후에 나타난다.

큰 세그먼트가 좁은 구간을 만났을 때

양 끝은 MTU 1500 으로 MSS 1460 을 합의했고, 가운데에 MTU 1420 인 터널이 있다고 하자. 경로 MTU 탐색이 설계대로 돌 때의 순서다.

  1. 분할 금지를 세운 큰 패킷송신자가 1500바이트 패킷에 DF 비트를 세워 보낸다. 세그먼트 하나로 끝나는 작은 응답은 이 크기에 닿지 않아 무사히 지나간다.
  2. 터널 입구의 라우터다음 홉 MTU 1420 보다 크므로 패킷을 버리고, ICMP 타입 3 코드 4 에 다음 홉 MTU 를 실어 송신자에게 돌려보낸다.
  3. 송신자가 줄여 다시 보낸다경로 MTU 1420 을 기억하고 세그먼트를 작게 잘라 재전송한다. 앞 단계의 ICMP 가 도착해야만 이 단계가 있다.

여기서 구분할 것 가운데 단계의 ICMP 를 방화벽이 막으면 송신자는 아무것도 모른 채 같은 크기로 재전송만 되풀이한다. 연결은 ESTABLISHED 로 남고 오류도 나지 않는다. 이것이 블랙홀이다.

잠깐, 예측해 보세요 ssh 접속은 되는데 큰 디렉터리에서 ls -la 를 치면 화면이 멈춘다. 먼저 무엇을 의심하겠는가?

설명 확인 · 채점 없는 자가 점검

경로 MTU 다. 접속과 짧은 명령은 작은 패킷이라 지나가고 긴 출력만 최대 크기 세그먼트가 되어 버려진다. 크기에 따라 증상이 갈리면 크기부터 본다.

근거 문서직접 움직여 보기

어떻게 동작하나

MTU 는 한 인터페이스가 한 번에 내보낼 수 있는 IP 패킷의 최대 크기다. 이더넷 기본값은 1500바이트다. TCP 는 여기서 IPv4 헤더 20바이트와 TCP 헤더 20바이트를 빼 1460바이트를 MSS 로 정하고, 핸드셰이크의 SYN 패킷에 옵션으로 실어 상대에게 알린다.

결정적인 사실은 이것이다. 양쪽 모두 자기 인터페이스의 MTU 만 보고 MSS 를 정한다. 경로 중간에 더 좁은 구간이 있는지는 아무도 모른다. 두 호스트가 1460바이트를 주고받기로 합의해도, 중간에 1420바이트짜리 터널이 있으면 그 합의는 지켜질 수 없다.

작은 요청이 성공하는 이유가 여기 있다. 헬스 체크 응답은 세그먼트 하나로 끝나 좁은 구간을 무사히 통과한다. 임계값을 넘는 패킷만 사라지므로 증상이 크기에 따라 갈린다. TLS 핸드셰이크에서 멈추는 것도 같은 이유다. ClientHello 는 작지만 서버가 보내는 인증서 체인은 수천 바이트라 곧바로 최대 크기 세그먼트가 된다.

원래 TCP 에는 이 문제를 푸는 장치가 있다. 경로 MTU 탐색(PMTUD) 이다. 리눅스는 TCP 패킷에 DF(분할 금지) 비트를 세우고, 중간 라우터가 자기 다음 홉 MTU 보다 큰 DF 패킷을 받으면 버리면서 ICMP 타입 3 코드 4(Fragmentation Needed) 로 다음 홉 MTU 를 알려 준다. 송신자는 그 값을 캐시하고 세그먼트를 작게 잘라 다시 보낸다.

문제는 이 ICMP 를 막았을 때다. 송신자는 아무것도 모른 채 계속 큰 패킷을 보내고, 그 패킷은 계속 버려진다. 재전송도 같은 크기라 또 버려진다. 오류는 나지 않는다. 연결은 ESTABLISHED 로 남아 있고 애플리케이션은 자기 타임아웃에 걸려서야 끝난다. 이것이 PMTUD 블랙홀이다.

여기서 널리 퍼진 오해를 정정해야 한다. "보안을 위해 ICMP 는 전부 막는다"는 정책은 그 자체로 장애 요인이다. 막아도 되는 것은 echo request/reply 정도이고 타입 3 코드 4 는 반드시 통과시켜야 한다. IPv6 에서는 선택의 여지조차 없다. IPv6 라우터는 패킷을 분할하지 않으므로 ICMPv6 Packet Too Big(타입 2)이 필수다.

캡슐화가 가져가는 바이트를 외워 두면 진단이 빨라진다. VXLAN 50바이트(실효 MTU 1450), WireGuard 60–80바이트(1440–1420), GRE 24바이트(1476), IPsec ESP 는 최대 약 73바이트다.

현장에서 만나는 모습

쿠버네티스에서 이 문제는 오버레이 네트워크 때문에 정기적으로 재발한다. 노드 인터페이스가 1500인데 VXLAN 인터페이스와 파드의 eth0 도 1500 으로 잡혀 있으면 즉시 블랙홀이다. VXLAN 은 50바이트를 가져가므로 1450 이어야 한다. 증상은 특징적이다. 파드끼리 작은 요청은 되는데 큰 본문의 POST 만 멈추고, kubectl exec 는 되는데 로그가 많은 파드의 kubectl logs 가 중간에 멈춘다.

현실적인 해법은 터널 진입점에서 MSS 클램핑을 거는 것이다. 지나가는 SYN 패킷의 MSS 옵션 값을 라우터가 직접 낮춰 쓰므로 ICMP 에 전혀 의존하지 않는다. 다만 TCP 에만 적용되며 QUIC 같은 UDP 기반 프로토콜은 스스로 크기를 조절해야 한다.

ICMP 를 살리는 길과 기대지 않는 길

터널이나 오버레이 뒤에서 블랙홀을 만났을 때 고를 수 있는 처방은 둘이다. 무엇에 기대는지가 다르다.

  • 타입 3 코드 4 를 통과시킨다경로 MTU 탐색이 설계대로 돈다. 다만 경로 위의 방화벽 하나라도 막으면 다시 무너진다. IPv6 는 라우터가 분할하지 않으므로 Packet Too Big 을 막을 선택지가 아예 없다.
  • 터널 입구에서 MSS 를 클램핑한다지나가는 SYN 의 MSS 값을 라우터가 직접 낮춰 쓴다. ICMP 에 전혀 기대지 않지만 TCP 에만 통하고, QUIC 같은 UDP 기반 프로토콜은 스스로 크기를 조절해야 한다.

여기서 구분할 것 보안을 위해 ICMP 를 전부 막는다는 정책은 그 자체로 장애 요인이다. 막아도 되는 것은 echo 정도이고, 크기를 알려 주는 메시지는 통신의 일부다.

잠깐, 예측해 보세요 VXLAN 을 쓰는 클러스터에서 노드 인터페이스와 파드 eth0 의 MTU 가 모두 1500 이다. 무엇을 바꿔야 할까?

설명 확인 · 채점 없는 자가 점검

파드 쪽을 1450 으로 낮춘다. VXLAN 이 50바이트를 가져가므로 1500 을 그대로 두면 큰 패킷이 즉시 블랙홀에 빠진다. 캡슐화가 가져가는 바이트만큼 안쪽 MTU 를 줄여야 한다.

근거 문서

이어지는 퀴즈에서 확인할 것

"작은 요청은 되는데 큰 응답만 멈춘다"는 증상에서 곧바로 MTU 를 떠올릴 수 있는지, 왜 오류 없이 멈추는지 설명할 수 있는지 확인한다.