난 마스토돈 인스턴스를 하나 운영하고 있고 집에 있는 남는 컴퓨터에서 매일 백업을 받도록 자동화를 시켜 두었다. 근데 백업 과정에 비해 비정상적으로 작업이 오래 걸려서 문제를 파헤쳐 봤다.

삽질과 잡설

일단 백업 하는 파일들 중에서 좀 크다 싶은 건 DB 덤프와 미디어 파일인데 미디어는 그렇다 치고 DB 덤프는 현재 21메가바이트 정도밖에 안 하는데 5분 정도가 걸리고 있었다. 아무리 봐도 이 놈이 범인이다.
DB 백업 과정은 SSH로 서버에 접속해서 dokku의 postgres 플러그인이 제공하는 익스포트를 사용하는데 얘는 pgdump 포맷의 압축 된 파일을 표준 출력 스트림으로 출력하고 그걸 리디렉션 해서 로컬의 파일로 만드는데 처음엔 dokku가 느린 줄 알았다. 컨테이너 내부로 들어갈 때 파일 권한을 수정하는 스크립트가 돌아가는데 미디어 업로드 디렉터리가 포함 돼서 1~2분 정도 걸리는 작업이었는데 생각해 보니 postgres는 다른 컨테이너에서 돌아가기에 이것과는 전혀 상관이 없다. 실제로 서버 내부에서 DB를 익스포트 해 보니 음료수를 한 모금 마시면 다 백업이 될 정도의 속도였다. 그럼 범인은 네트워킹이다.

구체적인 원인을 찾아 떠나자

서버에서 만든 21메가바이트 가량의 DB 백업파일을 scp 명령을 통해 복사를 해 봤다. 속도가 50KBps가 나왔다. 역시 네트워크가 범인은 맞는데 이제 어느 구간이 문제인지 찾아보자. 용의자는 다음과 같다.

  • 내 노트북이 쓰는 와이파이
  • 집에서 쓰는 인터넷 회선
  • 서버가 쓰는 인터넷 회선

일단 내 노트북이 쓰고 있는 와이파이 문제인가 싶었는데 얘는 확실히 아니었다. 백업을 받는 컴퓨터는 유선인데다가 그 컴퓨터에서 실험해도 똑같은 속도가 나왔다. 그럼 이제 집 바깥쪽 회선의 문제다.

안타깝게도 난 원룸에 살기 때문에 기가비트급의 회선을 쓰지는 못 한다. 근데 그래도 50KBps는 너무한 속도다. 스피드테스트를 돌려 보았지만 거의 최대속도의 80% 가량 나오고 있었다. 사람들이 많이 몰리는 시간이라거나 그런 건 아니었다. 그럼 이제 ISP측에서 해외로 나가는 회선이 문제라는 얘긴가 싶어 테스트를 해 봤다.

예전에 난 네트워크 관련 분야에서 일 한 적이 있어서 iperf라는 툴을 이용한다. 정확히는 iperf3이라고 그 다음 버전인데 네트워크 대역폭을 측정하기 좋다.

Iperf screenshot

와이파이라서 좀 나쁜 속도(33.7MB/s)였지만 서버에서 고작 21메가바이트짜리 파일을 받는데 몇 분이나 걸릴 속도는 전혀 아니다. 그리고 여기서 의문이 들면서 힌트가 보이기 시작했다.
scp로 복사할 때는 속도가 처참했는데 iperf로 측정하면 빠른 이유가 뭘까? 심지어 HTTP(s)로 파일을 다운로드 받는 시간마저 느렸다. 208킬로바이트를 받는데 1~2초씩이나 걸리고 있었다. 난 이게 nginx쪽 문제나 뭐 그런 걸로 알았는데 전혀 아니었다.

ISP를 주깁시다 ISP는 나의 원쑤

SSH는 22번 포트를 사용하고 HTTP(s)는 80, 443 포트를 사용한다. 잘 알려진 포트라고도 한다. 그리고 iperf3은 5201번이라는 생소한 포트번호를 사용한다. VPS 업체나 ISP에서 포트별로 대역폭을 제한하거나 그에 준하는 행동을 하고 있었다는 얘기인데 상식적으로 생각해서 VPS 업체는 그런 짓을 할 리가 없다. 그런 짓을 하면 고객이 아무도 오지 않기 때문이다. 그래서 난 ISP를 의심했고 VPN을 사용해 보기로 했다.

아까 50KB/s가 뜨던 scp 명령이 VPN을 타니까 4.4MB/s가 뜬다…. 어??!?!

잡았다 요놈!

그렇다. ISP가 포트 번호를 보고 대역폭을 제한하고 있었다. VPN을 타면 VPN을 타고 나가는 패킷이 어느 포트를 향하는 지 알 수가 없으니1 제한이 풀리는 거다.

궁금해서 HTTPS도 테스트를 해 봤다.

w/o VPN w/ VPN
network timeline on KT network timeline on Amazon

VPN을 타면 TTFB까지 빨라지는 건 둘째 치고 네트워크 속도가 이렇게나 차이가 난다니 대체 인터넷이 이게 뭔가 싶다.

결론

결국 백업 받는 스크립트 앞뒤로 VPN에 연결하고 해제하는 명령을 한줄씩 써 넣어 줬다.

$ nmcli con up Amazon
$ nmcli con down Amazon

P.S

  • VPN은 아마존 라이트세일에 세웠고 한국 리전이다.
  • VPS는 아마존이 아닌 Vultr를 쓰고 있고 도쿄에 있다.
  • curl을 이용해 TTFB를 비롯한 네트워크 성능 측정을 할 수도 있다.
    alias ttfb='curl -o /dev/null -w "Remote IP: %{remote_ip} Connect: %{time_connect} TTFB: %{time_starttransfer} Total time: %{time_total} Download speed: %{speed_download} \n"'
    
  • 최근 생긴 TLS SNI를 이용한 검열과는 딱히 관계가 없을 것이다. 워닝을 띄우는 그것은 Out of Path로 동작하는데 와이어태핑을 해서 검사 후에 외부에서 RST 또는 FIN 패킷을 강제로 뿌려 줄 뿐 그것 때문에 레이턴시나 대역폭 제한이 생기지는 않는다. 중간에 끼워넣는 건 위험하기도 해서 ISP도 싫어한다.
  1. 물론 VPN 패킷 자체가 어디 서버의 어디 포트로 향하고 있는 지는 알 수 있다.