Vercel, supabase 등 Serverless 기반 서비스에서 ColdStart 이슈 해결
서비스를 배포하고 사용률이 저조할 때 들어가면 로딩속도가 현저히 느려지는 이슈가 있었다.
영상에서는 30분동안 사용률이 없을 때 접속해보았고, 긴 검은화면 대기 시간과 각 지역에 표시되는 숫자 로딩시간이 길었다.
측정을 해본 결과 Time To First Byte(TTFB)가 1.38s, 각 지역에 등록된 게시물 개수를 불러오는 API 응답 속도가 약 8s가 나왔다.
반면, 사용률이 10분 이내에 있을 때는 응답 속도가 빨랐기에, 직감적으로 Cold Start 이슈임을 확신할 수 있었다.
Vercel에서도 자체적으로 ColdStart 이슈를 해결하는 방법을 제시한다.
여기서는 8가지 방법을 제시하는데, 그 중 과금을 안들이는 방법중 가장 현실적인 방법 3가지를 적용 시켜볼려고 한다.
- Use dynamic imports
- Choose smaller dependencies inside your functions
- Prewarm your functions using cron jobs
요약하자면, 번들 사이즈를 줄여 서버의 부팅시간을 줄여 주는 방법과 지속적으로 서버에 요청을 날려 warm 상태를 유지해주는 방법이다.
Use Dynamic Imports
실제 바로 로딩이 필요 없는 컴포넌트가 Modal 밖에 없었는데 Dynamic Import로 바꿔서 적용시켜봤으나, 이 때 사용하는 dynamic 패키지가 더 커서 그런지 번들 사이즈가 오히려 더 커졌다.
Choose smaller dependencies inside your functions
사용하지 않는 파일 import를 모두 제거해주었고 bundle-analyzer를 돌려본 결과
Lottie 패키지가 커서 이를 경량화 버전으로 교체해주었다.
Parsed Size 298kb와 Gzip 74kb에서 각각 168kb, 46kb로 미세한 개선이 이루어졌다.
Prewarm your functions using cron jobs
서버에 주기적으로 요청을 보내 warm 상태를 유지하는 방법이다.
Vercel에서 기본적으로 제공해주는 Cron 서비스는 일 1회만 기본 제공되며, 초과 요청시 Pro Plan이 요구된다.
먼저 NextJS에 Cron 관련 API를 증설 해주었다.
export const dynamic = "force-dynamic";
import { NextResponse } from "next/server";
import { InternalServerError } from "../error/server/InternalServer.error";
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
export async function GET() {
try {
await fetch(`https://a-spot-thur.app`);
await prisma.spot.count(); // supabase warming용
return new NextResponse(
JSON.stringify({ data: true, message: "Cron Successfully Prewarming." }),
{ status: 200, headers: { "content-type": "application/json" } }
);
} catch (e) {
return InternalServerError(e);
}
}
Line 1
해당 요청이 캐싱되지 않게 하기 위함.Line 11
TTFB용 APILine 12
Supabase (Serverless Database)에 요청을 날려 Warm 상태 유지
그 후, 아직 서비스가 Pro Plan을 필요로 하지 않는 점에서 AWS에서 제공하는 Event Bridge와 Lambda를 사용하였다.
Event Bridge가 3분 간격으로 AT에 요청을 보내는 역할을 수행하는 Lambda 함수를 호출하게 하여 구축하였다.
결과
위와 같은 작업을 거친 후 사용률이 없을 때 다시 성능 측정을 해보았다.
서버를 항상 Warm 상태로 유지하여 사용률이 없을 때에도 빠른 응답 속도를 유지할 수 있었으며, TTFB는 약 110ms, API 응답 시간은 약 400ms로 사용자 경험을 크게 개선할 수 있었다.