본문 바로가기

Side Projects

Vercel 최적화 (Serverless Funtions / Edge Functions)

개요

next.js (vercel 로 배포) + supabase 로 구성한 사이드 프로젝트를 개발 중 문제가 하나 발생했다.

local 환경에서는 문제 없었지만, prod 환경에서만 하면 next의 api 응답 시간이 너무 오래걸리는 것이다.

vercel과 supabase 무료플랜을 사용하고 있었기 때문에 그런가 보다 했는데, 점점 prod 환경에서 테스트가 너무 불편해지자 유료 플랜으로 전환하지 않는 선에서 방법을 모색해보기로 했다.

문제

local 환경에서는 건당 100~200ms 정도 걸리는 api 요청이 prod 환경에서는 2s 가 걸린다.

원인

네트워크 통신 현황

프로젝트의 네트워크 통신을 다이어그램으로 표현하자면 다음과 같다.

 

따라서 문제가 될 수 있는 구간은 2가지이다.

웹브라우저와 next.js 서버 간 통신 혹은 next.js 서버와 supabase 서버 간 통신.

local과 prod 환경에서 supabase 서버를 분리하여 호출하진 않으므로, next.js 서버와 supabase 서버간 통신은 문제가 없음을 알 수 있었다.

그렇다면 vercel에 배포된 next.js api 가 어떤 방식으로 동작되는지 파악이 필요했다.

Vercel Functions

vercel로 배포된 next.js 프로젝트내 app/api 는 기본적으로 node.js 런타임의 serverless function으로 동작한다.

그리고 이 serverless function의 실행 위치는 기본적으로 Washington, D.C, USA region 으로 선택된다.

 

이 사실들로 api 가 느린 원인을 2가지 알 수 있었다.

 

첫째, serverless function 특성상 초기 실행속도가 느리다. serverless function 은 컨테이너 기반으로 실행된다. 즉, 요청이 들어올 때마다 새로운 실행 환경을 부팅해야한다. 이를 cold start 라고 부른다.

실제로 첫 시도시에만 api 응답이 2s정도 걸렸고, 짧은 시간 내 많이 호출하다보면 1s 대로 응답시간이 줄어들었다.

 

둘째, serverless function 이 실행되는 위치가 요청이 발생하는 곳과 물리적으로 많이 떨어져있다. 결국 네트워크 통신도 물리적인 거리로부터 자유로울 수 없다. 심지어 supabase 서버는 한국 서울 region 에 위치하였기 때문에 한번에 api 요청이 발생할 때마다, 서울 -> 미국 -> 서울 -> 미국 -> 서울 으로 아주 불합리한 순서로 통신이 발생하고 있었다.

 

해결

문제를 해결하기 위해선 위에서 기술한 2가지 문제를 해결해야 했다.

serverless function의 느린 초기 실행속도실행 region 의 물리적 거리가 그것이다.

이 2가지 문제는 다행히도 한가지 방법으로 쉽게 해결할 수 있었다.

Edge Functions

Vercel 은 next api 를 기본적으로 node.js 런타임에서 실행되는 serverless function으로 동작시키지만, 이를 edge network에서 실행하는 serverless function 으로 변경할 수 있다. 이를 edge functions 라고도 부른다.

장점

edge functions의 장점은 다음과 같다.

edge functions 는 일반적인 serverless functions와 다르게 V8 Isolate 기반 실행 환경을 사용한다.

V8 Isolate 는 크롬의 자바스크립트 엔진에서 직접 실행되는 초경량 실행 환경이고 즉시 코드 실행이 가능하기 때문에 cold start 가 발생하지 않는다.

또한 일반적인 serverless functions는 하나의 region에서만 실행되지만, edge functions는 전세계의 엣지 서버에 모두 배포되어 가장 가까운 엣지 서버에서 실행될 수 있도록 한다. (서울에서도 vercel edge network가 지원된다)

 

정말 놀랍게도 위에서 기술한 2가지 문제를 그대로 해결할 수 있는 솔루션이다!

단점

edge functions는 V8 엔진 기반의 실행환경에서 동작하기 때문에 매우 제한된 기능만을 제공한다. (javascript를 사용할 때, browser와 node.js 에서 제공하는 api가 다르듯)

예를 들어, 대부분의 데이터베이스는 지속적인 연결을 요구한다. 하지만 edge functions는 stateless 방식으로 실행되며, 요청이 끝나면 함수가 종료된다. 따라서 DB 연결을 유지할 수 없기 때문에 edge functions 에서는 직접적인 DB 연결이 어렵다.

 

다행히도, 위 프로젝트의 경우 supabase sdk를 사용하여 HTTP 기반의 데이터베이스 API를 사용하고 있었기 때문에 edge functions 실행 환경으로도 전혀 문제가 없었다. 👍

Usage

적용 방법도 매우 간단하다. app/api 디렉토리 내 route 파일에 export const runtime = 'edge'; 를 추가하면 된다.

매우 간단하다

 

 

결론

건당 2s 걸리던 api 응답이 1s 미만으로 감소했다!

 

참고

https://vercel.com/guides/how-can-i-improve-serverless-function-lambda-cold-start-performance-on-vercel

https://vercel.com/docs/functions/concepts

https://vercel.com/docs/functions/configuring-functions/runtime#node.js