Cloudflare를 붙였는데 한국에서 오히려 느려진 이유

한국 사용자를 대상으로 운영 중인 데모 사이트에서 응답 지연을 점검했습니다. 도메인은 Cloudflare 프록시를 거치게 해뒀고, 원본 IP와 오리진을 보호하기 위해 켜둔 상태였습니다. 그러다 사이트를 손보는 중에 "버튼이 한 박자 늦게 눌리는 것 같다"는 얘기가 나왔고, 확인해 보니 앱 코드가 아니라 이 프록시 경로가 지연의 가장 큰 덩어리였습니다.

먼저 curl로 페이지별 응답 시간을 재봤습니다.

/dashboard TTFB 1.52s
/orders TTFB 1.03s
/tickets TTFB 1.03s
/leads TTFB 0.82s

대시보드가 1.5초인 건 이해가 갔습니다. DB 질의가 40번 나가는 무거운 화면이라 그러려니 했습니다. 이상한 건 가벼운 페이지들이었습니다. 질의가 몇 개 안 되는 화면도 1초 안팎이 나왔습니다. 페이지마다 편차가 있다기보다, 모든 페이지에 0.8초쯤 되는 바닥값이 깔려 있는 모양새였습니다.

처음에는 오리진 서버의 성능을 의심했습니다. 전에 콜드 스타트로 502를 겪은 적이 있어서 그쪽부터 봤는데, 서버가 힘들면 무거운 페이지일수록 더 느려져야지 이렇게 균일한 상수가 붙는 건 설명이 안 됐습니다. 이런 모양의 지연은 대개 코드가 아니라 경로에 있습니다.

cf-ray 세 글자로 끝난 확인

응답 헤더를 열어봤습니다.

$ curl -s -o /dev/null -D - https://cp.duolabs.co.kr/tickets
server: cloudflare
cf-cache-status: DYNAMIC
cf-ray: ........-LAX

cf-ray 헤더 끝의 세 글자가 그 요청을 처리한 Cloudflare 엣지의 공항 코드입니다. LAX, 로스앤젤레스였습니다. 한국 사용자의 요청이 LA 엣지를 경유한 뒤 오리진으로 전달되고, 응답도 같은 경로를 거쳤습니다. 태평양을 두 번 건너면 왕복으로 수백 ms가 그냥 사라집니다. 모든 페이지에 붙어 있던 0.8초의 정체가 대충 맞아떨어졌습니다.

Cloudflare는 서울에도 엣지가 있는데 왜 LAX로 갔는지는 확인하지 못했습니다. 무료 플랜 트래픽은 가까운 PoP 대신 먼 PoP로 배정되는 경우가 있다고 알려져 있지만, 배정 기준이 공개돼 있지 않아서 어디까지나 추정입니다. 다만 cf-ray가 LAX를 가리키는 동안에는 앱을 아무리 다듬어도 이 몫은 줄지 않는다는 것만은 분명했습니다.

선택지 정리

세 가지쯤으로 정리했습니다. 프록시를 끄고 DNS만 쓰면 경로 문제는 사라지지만 오리진 서버의 원본 IP가 그대로 노출됩니다. Argo 같은 유료 라우팅을 쓰는 방법도 있습니다. 아니면 경로는 그대로 두고 앱 쪽에서 체감을 줄이는 방법이 있습니다.

저는 일단 세 번째부터 했습니다. 스켈레톤과 클릭 피드백을 정리하는 쪽인데, 이 얘기는 글이 따로 있습니다. 프록시를 어떻게 할지는 아직 결정하지 못했습니다. 운영 중인 오리진의 IP 노출은 피해야 했습니다.

같은 증상을 만나면 앱 코드를 열기 전에 curl 한 줄부터 쳐보는 게 순서인 것 같습니다. 모든 페이지에 비슷한 크기로 붙는 지연은 코드보다 경로를 먼저 의심하라는 신호이고, cf-ray 세 글자면 확인이 끝납니다.

같은 작업에서 겪은 다른 문제:

Next.js 앱에서 클릭이 한 박자 느리게 느껴질 때 살펴본 것들