알고보니 별 것 아니었던 nextjs앱을 vercel 에 배포한 뒤 발생했던 응답시간 지연 문제를 파악했던 과정에 대해 기록했다.
nextjs
앱을 vercel
에 배포했는데 로컬 환경에 비해 요청에 대한 응답이 매우 느렸다!
정확히는 SSR
, Route API
등 next의 서버
에서 요청하는 자원들의 응답이 매우 느렸다.
배포환경과 개발환경 인스턴스 플랫폼이 다른데 백엔드 분이 배포 환경(Nxx) 네트워크 스펙이 개발 환경(Axx)보다 조금 더 안좋아서 지연이 있다고 하셨다.
서버사이드 요청에 대한 응답만 느린 걸로 보아 그럴듯한 이유일 수 있다고 생각했다.
하지만 다음과 같은 증거들로 해당 문제가 아닌 것을 알게 되었다.
(1) 로컬에서 프로덕션 서버 API를 사용할 때는 지연이 없음
SSR 페이지 하나를 탐색해보았다.
왼쪽이 vercel, 오른쪽이 로컬에서 빌드하고 실행했을 때 환경인데 말도안되게 차이가 난다.
로컬에서는 볼 수 없었던 이런 문제도 추가로 발생했다!
요청에 대해 첫 바이트를 응답하기까지 걸리는 시간인 TTFB에만 영향을 줘서 위에 성능 딱지는 좋아보이게 나오는 괴리감이 있다.
첫 응답까지의 시간이 오래걸리는 문제지만 백엔드 서버의 문제라면 이정도까지 차이가 나진 않을 것이라고 생각했다.
(2) Client Side에서 Api를 요청할 때 응답 속도가 개발환경과 큰 차이가 없음
브라우저에 렌더링 되고 난 뒤 클라이언트 측에서 서버에 요청을 하는, 즉 수정 삭제와 같은 Api를 호출해도 응답속도에 문제가 없었다.
(3) 서버 Api를 사용하지 않는 Route Api는 왜 지연이 발생함
서버사이드에서 특정 로직을 처리하기 위한 예: logout, revalidate
next Api들이 있었는데 이 Api에서 백엔드 자원을 따로 호출하지 않았으며 심지어 별다른 동작도 없었다.
하지만 SSR을 할 때 만큼이나 어마어마한 지연이 발생하고 있었다. 응답하는데 최소 800~900ms 이상의 시간이 걸렸다!
첫번째는 수정 Api이고 끝나면 revalidate하는데 내부에 별다른 동작이 없는데도 1.4초가 걸렸다!
로그아웃도 서버측에서 쿠키를 없애야해서 Route Api로 구성했는데 1초정도 걸렸다.
서버에서 만드는 페이지의 사이즈와는 별개로 서버측에서 처리하는 모든 것들에 문제가 있음을 알 수 있다.
물론 응답속도에 번들 사이즈가 당연히 영향이 있겠지만 사이즈가 크다면 콘텐츠 다운로드 속도에 영향을 줄 것 같다.
응답을 기다리는데 모든 시간을 쏟고 있으니 번들 사이즈 문제가 아니라고 생각했다.
백엔드 분이 vercel에는 리전 같은거 없냐고 해서 같이 서치해주셨는데 이미 이런 문제를 겪은 사례가 많이 있었다.
일단 vercel 서버 자체가 물리적으로 멀었다.
생각한 정확한 원인
정적 파일 및 정적 페이지는 CDN
에 캐싱되어 엣지 로케이션, 즉 우리집 가까운 어딘가에서 처리하게 때문에 응답속도에 지장이 없고 매우 빨랐던 것이다.
하지만 SSR
및 Api Route
등은 서버측에서 처리하기 때문에 따로 캐싱정책을 설정하지 않으면 매 요청마다 새로운 응답을 만들어낸다.
메인페이지는 빌드 시 페이지를 만들게 해두고 on-demand-revalidation
을 적용했다. 따라서 브라우저 상에서는 캐싱하지 않지만 Vercel의 CDN을 통해 캐싱된 컨텐츠가 제공된다.
아까 그 서버사이드 렌더링 페이지이다.
Cache-Control
헤더도 따로 설정해두지 않았고 CDN에도 캐싱되지 않기 때문에 미국 서버에서 직접 페이지를 만들어서 보내주는 것이라고 볼 수 있을 것 같다.
고작 이거 클릭 한번이 해결책이었다. 설정하기 전에 워싱턴으로 되어있었다
응답 헤더의 X-Vercel-id
를 확인해보면 이전에 icn1::iad1
로 되어있었던 것과 달리 지정한 Region
으로 식별되는 것을 확인할 수 있다.
서버측에서 처리해야되는 동적인 것들 외에는 알아서 엣지 로케이션에서 처리한다고 한다.
따라서 vercel 서버가 캘리포니아에 있더라도 서버사이드 처리 외의 요청/응답에는 큰 문제는 없을 것 같으리라 라고 믿었다.
Api Route
, SSR
등 nextjs 서버 측에서 처리해야 할 작업들을 수행해준다.
AWS Lambda처럼 요청이 발생할 때마다 동적으로 실행되며, 실행 후에는 더 이상 사용되지 않는 리소스를 해제하는 방식인 것 같다.
getServerSideProps
,Api route
등 nextjs앱의 서버측에서 처리해야하는 것들을 serverless function
으로 처리하는데 이 람다함수의 위치가 워싱턴이니 오래걸렸던 것이다.
우리집 근처로 함수 리전을 바꿔주니 응답 대기시간이 로컬 수준으로 개선되었고 Lighthouse에서도 더이상 TTFB 문제를 제기하지 않는다.
다만 AWS Lambda처럼 오래 안쓰면 휴동되는 것 같아 맨 처음에 갑작스럽게 요청하면 시간이 좀 걸리긴 하는 것 같다.
찾아보진 않았지만 유료 정책에는 성능 확실한 서비스가 있을 것 같다는 느낌같은 느낌이 들기도 하고
여건이 된다면 백엔드와 더 가까운 위치에 앱을 배포하고 CDN을 붙여서 직접 관리하는 것이 더 안정적이지 않을까라는 생각이 든다.
와... 정말 감사합니다! 느린 이유를 어디서부터 찾아야하나 난감한 상황이었는데,
이 글 읽자마자 의심되어서 보니까 저희도 워싱턴DC로 세팅돼있더라고요!