"처음 접속할 때만 왜 이렇게 느리죠?"
서버 관리의 부담을 없애고 사용한 만큼만 비용을 내는 서버리스(Serverless) 컴퓨팅은 현대 클라우드 아키텍처의 혁명과도 같습니다. 하지만 많은 개발자가 서버리스를 처음 도입했을 때 당혹스러운 경험을 합니다. 바로 간헐적으로 발생하는 '응답 지연(Latency)' 문제입니다.
평소에는 0.1초 만에 응답하던 API가 어떨 때는 3초, 심하면 5초 이상 걸리기도 합니다. 마치 자고 있는 직원을 깨워서 일을 시키는 것과 같은 이 현상, 바로 '콜드 스타트(Cold Start)'입니다. 오늘은 서버리스의 숙명과도 같은 콜드 스타트의 원인을 파헤치고, 이를 극복하는 실전 전략 3가지를 소개합니다.
콜드 스타트(Cold Start)란 무엇인가?
서버리스(FaaS, Function as a Service)의 핵심은 '이벤트 기반 실행'입니다. 요청이 들어올 때만 컴퓨터 자원을 할당하고, 요청이 없으면 자원을 회수하여 비용을 절감합니다.
- Warm Start: 이미 실행된 컨테이너가 살아있어, 코드를 즉시 실행하는 상태 (빠름)
- Cold Start: 실행 가능한 컨테이너가 없어서, 클라우드 제공자가 새로운 실행 환경을 처음부터 만드는 상태 (느림)
콜드 스타트가 발생하면 클라우드 제공자(AWS, Azure, GCP 등)는 다음과 같은 준비 과정을 거칩니다.
- 실행 가능한 컨테이너 공간 확보
- 함수 코드 다운로드
- 런타임(Runtime) 환경 구동 (Node.js, Python, Java 등 실행)
- 초기화 코드 실행
- 비로소 실제 비즈니스 로직 실행
이 준비 과정(1~4번)에 걸리는 시간이 사용자에게는 답답한 지연 시간으로 느껴지는 것입니다.
왜 발생하는가? 원인 분석
원인은 간단합니다. 비용 효율성 때문입니다. 클라우드 제공자는 수백만 명의 사용자가 올린 함수를 24시간 내내 메모리에 올려둘 수 없습니다. 따라서 일정 시간(보통 5~15분) 동안 요청이 없는 함수는 컨테이너를 종료(Spin down)시켜 유휴 자원을 회수합니다. 이후 다시 요청이 들어오면 그때 부랴부랴 서버를 띄우느라 지연이 발생합니다.
영향을 미치는 변수들
- 프로그래밍 언어: Python이나 Node.js 같은 인터프리터 언어는 시동이 빠르지만, Java나 C# 같은 컴파일 언어는 JVM 등을 띄워야 하므로 콜드 스타트 시간이 훨씬 깁니다.
- 코드 패키지 크기: 코드와 라이브러리 용량이 클수록 다운로드 및 압축 해제 시간이 오래 걸립니다.
- VPC 설정: 과거에는 함수가 VPC 내부 리소스(RDS 등)에 접근하려면 네트워크 인터페이스(ENI)를 생성하느라 엄청나게 느렸습니다. (현재는 AWS Hyperplane 등으로 많이 개선되었으나 여전히 영향은 있습니다.)
해결책 1: 프로비저닝된 동시성 (Provisioned Concurrency)
가장 확실하고 공식적인 해결책입니다. AWS Lambda를 기준으로 설명하면, '돈을 더 내고 미리 켜두는' 옵션입니다.
이 기능을 켜두면 설정한 개수만큼의 실행 환경(컨테이너)이 항상 초기화된 상태로 대기합니다. 요청이 들어오면 준비 운동 없이 바로 로직을 수행하므로 콜드 스타트가 아예 발생하지 않습니다.
- 장점: 확실한 성능 보장, 엔터프라이즈급 서비스에 필수
- 단점: 추가 비용 발생 (서버리스의 장점인 '0원' 구간이 사라짐)
해결책 2: 웜업(Warm-up) 핑 보내기
비용을 들이지 않고 해결하고 싶다면 일명 '지속적인 핑(Ping)' 전략을 사용할 수 있습니다.
CloudWatch Events(EventBridge) 등을 사용하여 5분이나 10분마다 주기적으로 내 함수를 호출해 주는 스케줄러를 만듭니다. 이렇게 하면 서버가 "아, 이 함수는 계속 쓰이는구나"라고 착각하여 컨테이너를 종료하지 않고 유지(Warm)하게 됩니다.
- 장점: 추가 비용이 거의 없음 (호출 비용은 미미함)
- 단점: 완벽하지 않음. 트래픽이 급격히 몰려(Scale-out) 동시에 여러 컨테이너가 새로 뜰 때는 막을 수 없음
해결책 3: 코드 최적화 및 경량화
근본적인 체질 개선입니다. 콜드 스타트가 발생하더라도 그 시간을 최소한으로 줄이는 방법입니다.
- 언어 변경 고려: 빠른 응답 속도가 생명인 API라면 Java보다는 Go, Python, Node.js 등을 사용하는 것이 유리합니다.
- 의존성(Dependency) 줄이기: 꼭 필요한 라이브러리만 포함하세요. aws-sdk 전체를 불러오는 대신 필요한 모듈만 import 하는 것이 좋습니다.
- Lazy Loading 적용: 함수 밖(Global Scope)에서 모든 변수를 초기화하면 시작 시간이 길어집니다. DB 연결 같은 무거운 작업은 함수 내부에서 필요할 때 연결하도록 로직을 변경합니다.
서버리스는 마법이 아닙니다
서버리스는 인프라 관리를 없애주지만, 성능 최적화의 책임까지 없애주지는 않습니다. 서비스의 성격에 따라 전략을 선택해야 합니다.
- 돈으로 해결: 응답 속도가 매출과 직결되는 핵심 서비스라면 Provisioned Concurrency를 사용하세요.
- 꼼수로 해결: 트래픽이 적은 토이 프로젝트나 사내 도구라면 Warm-up Ping으로 충분합니다.
- 기술로 해결: 불필요한 라이브러리를 걷어내고 코드를 경량화하는 것은 모든 경우에 필수입니다.