RSS
웹 인프라

Vultr 네트워크 장애 티켓: 양방향 MTR로 transit 변경을 받아낸 기록

작성자
듀오랩스 대표·12분 읽기

Vultr 인스턴스와 다른 ISP 회선에 있는 서버 사이에서 패킷이 하루에 몇 번씩 사라졌습니다. 한 번 시작되면 1분에서 15분 동안 40~80%가 손실됐고, 손대지 않아도 다시 멀쩡해졌습니다. 원인은 두 회사 망이 만나는 중간 구간에 있었고, 그 구간은 제 손이 닿지 않는 곳이었습니다.

이 글은 그 문제를 Vultr 지원 티켓으로 넘긴 과정입니다. 무엇을 모아서 어떻게 썼는지, 티켓이 어떤 순서로 처리됐는지, 그리고 아직 무엇이 남았는지를 적었습니다.

글에 나오는 주소와 회선 구성은 예시로 바꿨습니다. 인스턴스는 198.51.100.10, 상대 서버는 203.0.113.20, 그 사이 transit 라우터는 192.0.2.x로 적습니다. 손실 비율, 장애가 이어진 시간, 티켓이 오간 순서는 실제 그대로입니다.

처음 문의처로 잡았던 ISP

장애가 처음 보였을 때 제 계획은 상대 서버 쪽 ISP에 문의하는 것이었습니다. 회선이 끊기는 것처럼 보였고, 회선이라면 ISP 일이라고 생각했습니다. 그래서 MTR 기록에서 끊기는 구간이 나오면 회선 번호와 장애 시각 목록을 붙여 ISP에 보내기로 했습니다.

기록이 쌓이고 보니 손실은 ISP 망 안에서 시작되지 않았습니다. ISP 내부 hop도, Vultr 내부 hop도 0%였고, 손실은 두 망을 잇는 transit 구간에서 시작됐습니다. 그 구간은 Vultr가 쓰는 상위 회선입니다. 저는 Vultr의 고객이고, 상위 회선을 바꾸거나 따질 수 있는 쪽도 Vultr입니다. 그래서 1차 문의처를 Vultr로 바꾸고, Vultr가 ISP 쪽 문제라고 답하면 같은 자료를 들고 ISP로 가기로 했습니다.

그 사이 끊겼을 때 다른 길로 돌아가는 우회 경로도 따로 만들어 두었습니다. 다만 우회는 증상만 가립니다. 끊김 자체는 우회와 상관없이 계속되기 때문에 티켓은 따로 보내야 했습니다.

티켓 전에 지워 둔 용의자들

지원 티켓의 첫 답장이 "서버 쪽 설정을 확인해 주세요"로 오면 하루가 그냥 갑니다. 그래서 상대가 먼저 물어볼 만한 것들은 미리 지워 두었습니다.

장애 시간에도 인스턴스가 다른 목적지와 하는 통신에는 문제가 없었습니다. 인스턴스나 방화벽이 원인이었다면 상대를 가리지 않고 나빠졌을 겁니다. 상대 서버 쪽에서도 같은 시간대에 GitHub 같은 다른 목적지로 나가는 통신에는 오류가 없었습니다. 그러면 남는 것은 그 두 지점 사이의 경로뿐입니다.

이 두 문장은 티켓 본문 첫 단락에 그대로 들어갔습니다.

1분 간격 양방향 MTR로 남긴 증거

간헐적 장애는 터진 뒤에 traceroute를 돌리면 이미 정상으로 돌아와 있습니다. 그래서 양쪽 서버에서 서로를 향해 MTR을 1분마다 돌리고 기록을 쌓았습니다.

방향을 둘 다 잡은 데는 이유가 있습니다. 인터넷 경로는 가는 길과 오는 길이 다른 라우터를 지나는 경우가 흔해서, 한쪽 기록만으로는 손실이 어느 길에서 생겼는지 가를 수 없습니다. 같은 시각에 양쪽을 찍어 두면 두 기록이 겹치는 구간이 보입니다.

장애가 가장 길게 이어진 밤의 기록입니다. 인스턴스에서 상대 서버로 가는 방향이고, 정상일 때와 6분 뒤 손실 중일 때를 나란히 붙였습니다.

[정상]                         Loss%
  3. 10.0.1.1 (Vultr 내부)      0.0%
  4. 10.0.2.1 (Vultr 내부)      0.0%
  5. 10.0.2.5 (Vultr 내부)      0.0%
  6. 192.0.2.1 (transit)        0.0%
  7. 192.0.2.9 (transit)        0.0%
 10. 203.0.113.1 (ISP)          0.0%
 12. 203.0.113.5 (ISP)          0.0%

[손실 중, 6분 뒤]              Loss%
  3. 10.0.1.1 (Vultr 내부)      0.0%
  4. 10.0.2.1 (Vultr 내부)      0.0%
  5. 10.0.2.5 (Vultr 내부)      0.0%
  6. ???                      100.0
  7. 192.0.2.9 (transit)       80.0%
 10. 203.0.113.1 (ISP)         80.0%
 12. 203.0.113.5 (ISP)         60.0%

반대 방향도 같은 모양이었습니다. ISP 내부 hop은 0%였고, transit에 들어서는 192.0.2.13에서 80%, 그 짝인 192.0.2.2에서 60%가 나왔고, 마지막 줄인 인스턴스 자신에서도 60%였습니다.

192.0.2.1과 192.0.2.2처럼 두 방향 기록에 한 쌍의 주소가 나눠 나타났습니다. 한 /30에 들어가는 짝이라 같은 링크의 양 끝일 가능성이 높습니다. 두 방향이 같은 구간을 반대로 건너다 함께 패킷을 잃은 것으로 읽힙니다.

ICMP rate limiting 반론을 미리 막은 문단

MTR 기록을 지원팀에 보내면 흔히 돌아오는 답이 있습니다. 중간 라우터가 ICMP 응답에 속도 제한을 걸어서 손실처럼 보일 뿐이라는 설명입니다. 실제로 대부분은 그렇습니다. 라우터는 지나가는 패킷을 하드웨어로 넘기지만 자기 앞으로 온 ICMP에 답하는 일은 CPU가 맡아서, 응답을 일부러 줄이는 경우가 많습니다.

그런 경우에는 손실이 그 hop에서만 보이고 다음 hop부터는 0%로 돌아옵니다. 이번 기록은 손실이 시작된 hop부터 마지막 목적지까지 끊기지 않고 이어졌고, 목적지는 제 서버였습니다. 끝에서 사라진 패킷은 실제로 도착하지 못한 패킷입니다.

그래서 이 판단을 본문에 한 문장으로 넣었습니다. 제가 보기에 이 문장이 티켓이 첫 단계에서 걸러지지 않고 네트워크 팀까지 간 이유 중 하나입니다. 상대가 할 법한 첫 반론에 기록으로 먼저 답해 두면 그 왕복 한 번이 줄어듭니다.

실제로 보낸 티켓 본문

제목에 증상, 손실 비율, 구간을 다 넣었습니다. 본문은 범위, 증거, 판단, 시각 목록, 요청 순서입니다. 주소만 바꾼 형태로 옮깁니다.

Subject: Intermittent packet loss (40-80%) at transit between Vultr and ISP-B

Our instance 198.51.100.10 has been losing connectivity to one of our sites on ISP-B
(203.0.113.20) several times a day, for 1 to 15 minutes at a time. During these windows,
40-80% of packets are lost in both directions. The instance's traffic to other networks is
unaffected at the same times, and the site's connection to other destinations (e.g. GitHub)
showed no errors during the windows.

We now run mtr every minute in both directions. In every window, the loss starts at the
transit hops and continues to the destination, while the hops before it are clean.

Since every hop after that point also loses packets, this looks like real loss rather than
ICMP rate limiting.

Affected windows: ...

Could you check the upstream / peering toward ISP-B for these times?
We are happy to provide the full per-minute mtr logs.

(정상·손실 중 mtr 원본, 두 방향)

마지막 줄의 질문은 "확인해 주세요"가 아니라 "이 시각들에 이 구간의 상위 회선을 봐 달라"로 썼습니다. 무엇을 어디서 볼지 정해 주면 받는 쪽은 바로 일을 시작할 수 있습니다.

1차 지원에서 네트워크 팀으로 넘어간 순서

답은 세 통이 왔습니다.

첫 통은 티켓이 접수됐다는 자동 메일입니다. 제가 쓴 본문이 그대로 붙어 있었습니다.

두 번째는 System Admins 팀의 지원 엔지니어였습니다. 네트워크 팀으로 넘겼으니 검토할 시간을 더 달라는 내용이었습니다. 서버 설정을 되묻는 질문은 없었습니다.

세 번째는 Network Team의 시니어 엔지니어에게서 왔습니다. 이 답장은 처음과 다른 번호의 티켓으로 왔습니다. 네트워크 팀의 대기열로 옮겨지면서 새 티켓이 열린 것으로 보입니다. 본문은 이게 전부였습니다.

Change the transit being used for this traffic, could you please verify now?

원인이 무엇이었는지, 어느 장비였는지는 한 줄도 없었습니다. 그 트래픽이 지나는 transit을 다른 것으로 바꿨으니 확인해 달라는 말뿐이었습니다. 원인 설명이 없는 답이지만 고객 입장에서 필요한 것은 그 한 줄이 맞다고 봅니다. 상위 회선 사업자와 무슨 일이 있었는지는 그쪽 사정이고, 제가 확인할 수 있는 것은 경로가 바뀌었는지와 손실이 멈췄는지입니다.

바뀐 것은 나가는 길 하나뿐

답장을 받고 1분 간격 기록을 다시 열었습니다. 인스턴스에서 나가는 쪽은 10월 1일 오전 11시 9분 기록부터 경로가 달라져 있었습니다. 문제의 transit 라우터가 사라지고, 다른 사업자의 라우터 두 개를 거쳐 ISP로 들어갔습니다. 그 뒤 7시간 동안 쌓인 기록 421건에서 손실은 한 번도 나오지 않았습니다.

반대 방향 기록은 달랐습니다. 상대 서버에서 인스턴스로 오는 길은 여전히 예전 transit을 지나고 있었습니다.

이건 인터넷 라우팅의 기본 성질입니다. 패킷이 어느 길로 나갈지는 보내는 쪽 망이 고릅니다. Vultr가 바꿀 수 있는 것은 자기 망에서 나가는 경로이고, 돌아오는 패킷이 어느 transit을 탈지는 상대 ISP가 정합니다. Vultr가 손댈 수 있는 것은 BGP로 자기 주소를 어떻게 알리느냐 정도이고, 그걸 받아서 고르는 것은 여전히 상대 쪽입니다.

한쪽 방향 MTR만 돌리고 있었다면 저는 "경로가 바뀌었고 손실도 없다"고 답하고 티켓을 닫았을 겁니다. 처음에 양방향을 고집한 이유가 확인 단계에서 한 번 더 쓰였습니다.

돌아오는 길의 중간 hop에서는 지금도 20~60% 손실이 찍힙니다. 그런데 목적지인 인스턴스에서 잰 손실은 같은 7시간 동안 420건 중 20%짜리 두 번뿐입니다. 손실이 중간에서 생기고 끝까지 이어지지 않는, 앞에서 말한 ICMP 응답 제한의 모양입니다.

이 구분을 제 집계에서는 한 번 놓쳤습니다. 처음 기록을 셀 때 중간 hop 손실까지 같이 세는 바람에, 경로가 바뀌기 전인 그날 오전에도 손실이 73번 있었던 것처럼 숫자가 나왔습니다. 목적지와 마지막으로 응답하는 hop만 기준으로 다시 세니 0이었습니다. 티켓에서는 상대에게 요구한 기준을 제 집계에는 적용하지 않았던 셈입니다.

"지금은 괜찮다"로 닫지 않을 이유

다시 센 숫자에서 하나가 더 보였습니다. 실제 장애가 마지막으로 난 것은 9월 30일 밤입니다. 10월 1일에는 경로가 바뀌기 전인 0시부터 11시까지도 장애가 없었습니다. 바뀐 뒤 7시간이 깨끗한 것을 경로 변경의 효과라고 말할 근거가 아직 없다는 뜻입니다.

간헐적 장애에서 "지금은 괜찮다"는 아무것도 증명하지 않습니다. 원래도 대부분의 시간은 괜찮았습니다. 그래서 티켓에는 세 가지를 적어 답할 생각입니다. 나가는 경로가 바뀐 것을 확인했다는 것, 돌아오는 경로는 아직 같은 transit을 지난다는 것, 그리고 1~2주 기록을 더 지켜본 뒤 다시 알리겠다는 것입니다.

다시 생기면 같은 티켓에 같은 형식의 기록을 붙여 답할 겁니다. 손실이 돌아오는 길에서만 난다면 그때는 상대 ISP에도 같은 자료를 들고 갑니다. 그래도 계속되면 남는 방법은 그 transit을 지나지 않는 상위 회선을 쓰는 위치로 인스턴스를 옮기는 것입니다.

마지막 수정:

공유하실 때는 출처(Duolabs)와 원문 주소를 표시해 주세요.