pingが成功してもサービスは駄目なことがある
한국어 원문으로 표시합니다.
한 줄 요약
ping 은 IP 계층까지의 도달성만 증명한다. 그 위의 포트도, 그 위의 애플리케이션도, 심지어 큰 패킷이 지나갈 수 있는지도 증명하지 않는다.
왜 이게 필요했나
"ping 은 되는데 접속이 안 돼요" 는 모순이 아니라 정상적인 상태다. ping 은 ICMP echo 를 주고받을 뿐이다. TCP 8080 이 열려 있는지는 전혀 다른 질문이고, 그 포트가 열려 있어도 애플리케이션이 5xx 를 뱉을 수 있다.
반대 방향도 중요하다. ping 이 실패해도 서비스는 멀쩡할 수 있다. 많은 조직이 ICMP echo 를 차단하기 때문이다. 그러니 "ping 이 안 되니 서버가 죽었다" 는 판단은 위험하다.
어떻게 동작하나
세 도구의 역할이 다르다.
| 도구 | 무엇을 보나 | 이 환경에서의 주의 |
|---|---|---|
ping |
목적지까지 IP 왕복이 되는가 | 동작함 (ping_group_range 허용) |
traceroute |
어느 홉까지 가는가 | UDP 모드만 동작 (ICMP 모드는 raw socket 필요) |
mtr |
홉별 손실률과 지연을 지속 관찰 | --udp 필요 |
traceroute 의 원리는 TTL 을 1부터 올려 가며 보내는 것이다. TTL 이 0이 된 지점의 라우터가 ICMP time exceeded 를 돌려주고, 그 출발지 주소가 곧 그 홉의 정체다. 그래서 traceroute 는 "경로를 조회하는" 것이 아니라 "일부러 실패시켜 응답을 모으는" 도구다.
* * * 는 장애가 아니다. 그 홉의 라우터가 ICMP 응답을 제한하거나 만들지 않는 것뿐이다. 판정 규칙은 이렇다.
- 중간 홉에서만 손실이 보이고 최종 목적지에서 손실이 없다면 ICMP rate limiting 일 가능성이 높다
- 특정 홉부터 지연이 급증한다면 그 구간이 병목이다
- 마지막 몇 홉에서 손실이 증가한다면 실제 문제일 가능성이 높다
ping 이 놓치는 것: 경로 MTU
가장 고약한 사례가 MTU 블랙홀이다. ping 은 기본 페이로드가 56바이트라 항상 통과한다. 그런데 응답이 조금만 커지는 API 는 그대로 멈춘다. 오류도 아니고 그냥 멈춘다. 크기가 임계값을 넘는 패킷만 사라지기 때문에 증상이 크기에 따라 갈린다.
확인은 조각화 금지 비트를 세운 ping 으로 한다.
ping -M do -s 1472 -c 1 10.20.0.5
# From 10.0.1.1 icmp_seq=1 Frag needed and DF set (mtu = 1420)
-s 값에 28(ICMP 8 + IP 20)을 더한 것이 실제 MTU 다. 이분 탐색으로 통과 최대치를 찾으면 경로 MTU 가 나온다.
터널을 쓰면 오버헤드만큼 실효 MTU 가 줄어든다.
| 캡슐화 | 추가 헤더 | 실효 MTU | 권장 MSS 클램프 |
|---|---|---|---|
| PPPoE | 8 | 1492 | 1452 |
| GRE | 24 | 1476 | 1436 |
| VXLAN (IPv4) | 50 | 1450 | 1410 |
| WireGuard (IPv4) | 60 | 1440 | 1400 |
| IPsec ESP + NAT-T | 약 81 | 1419 | 1379 |
현장에서 만나는 모습
"VPN 을 켜면 특정 사이트만 안 열립니다." 터널 오버헤드로 실효 MTU 가 줄었는데 MSS 클램핑이 없는 전형적인 상황이다. 작은 페이지는 열리고 큰 페이지는 멈춘다. ping 은 100% 성공한다.
클라우드에서 ICMP 를 다 막아 놓고 traceroute 를 돌리는 경우. 전부 * * * 로 나와 "경로가 끊겼다" 고 결론 내리기 쉽다. 이때는 TCP 모드 traceroute(-T -p 443)나 nc -zv 로 목적 포트를 직접 두드리는 편이 정확하다.
어디서 재느냐가 답을 바꾼다
같은 도구로 같은 대상을 재도 어디서 쟀는지에 따라 결론이 달라진다. 이것을 의식하지 않으면 서로 다른 곳에서 잰 값을 놓고 논쟁하게 된다.
내 노트북에서 잰 값은 우리 서비스의 값이 아니다. 사무실 회선, VPN, 집 공유기가 전부 경로에 끼어 있다. 사용자가 겪는 것과도 다르고 서버들 사이의 통신과도 다르다. 그래서 문제가 난 자리와 같은 위치에서 재는 것이 첫 원칙이고, 그러지 못할 때는 잰 위치를 결과에 함께 적는다.
한쪽에서만 재면 절반이다. 앞 코스에서 본 대로 가는 길은 있는데 돌아오는
길이 없는 경우가 흔하고, 그때 한쪽에서 본 traceroute 는 정상으로 보인다.
양쪽에서 서로를 향해 재 보면 비대칭이 바로 드러난다.
경로가 매번 같지 않다. 여러 경로가 있는 구간에서는 흐름마다 다른 길로
가고, 그래서 traceroute 를 두 번 돌리면 홉이 다르게 나온다. 손실이 특정
흐름에서만 나타나는 문제는 한 번의 측정으로는 잡히지 않는다.
측정 자체가 부하를 만든다. 이미 포화된 링크에 mtr 을 붙이면 그것이
손실을 더한다. 그리고 앞 코스에서 말한 대로 이미 아픈 시스템에서 진단 명령이
장애를 키우는 일은 실제로 일어난다.
마지막으로 언제 쟀는지 적는다. 네트워크 문제는 시간에 따라 나타났다 사라지므로, 시각 없는 측정값은 며칠 뒤에 아무 근거가 되지 못한다. 정상일 때의 값을 미리 재 두는 것도 같은 이유에서 값이 크다. 비교할 것이 없으면 지금 값이 나쁜지 아닌지 판정할 수 없다.
다음 실습에서 할 것
인터페이스와 라우팅을 확인하고, ping 통계에서 손실률과 RTT 를 읽고, UDP 모드 traceroute 와 mtr 을 돌린다. 마지막에는 ICMP 는 되는데 TCP 는 어떤가 를 직접 비교해 표로 만든다.