AWS Lambda 콜드 스타트 해결 과정

Intro

람다는 AWS에서 제공하는 서버리스 컴퓨팅이다.
서버를 직접 구축할 필요가 없고 가볍고 구축하기도 쉬운 여러 장점덕에 많은 곳에서 사용하는 것 같다.
트래픽이 엄청 많은 서비스가 아니라면 비용도 저렴한 장점이 있다.

이번 주제인 콜드 스타트가 생기는 이유는 서버리스라는 특성에서 발생한다.


서버리스

서버리스도 사실은 서버다.

편의점으로 비교하면 일반 서버에는 직원이 24시간 항상 대기한다면 서버리스는 손님이 왔을 때만 직원이 잠깐 와서 대응하는 방식이다.
여기서 직원이 잠깐 와야할 때 드는 시간이 콜드 스타트이다.
즉 람다 실행을 위한 런타임 환경을 로드하는 시간이다.

이런 서버리스의 특징 때문에 콜드 스타트가 발생하게 된다.


콜드 스타트는 어떤식으로 발생되는가

처음엔 콜드 스타트가 최초 1회 발생하면 일정 시간동안은 발생하지 않는다고 생각했다.
하지만 콜드 스타트는 이렇게 단순한 방식으로 작동되지 않는다.
콜드 스타트는 서서히 감소되고 람다 호출 시간에 따라서도 워밍업되는 속도도 차이가 난다.

아래는 람다 2개가 결합된 api를 테스트 했던 속도이다. (람다 2개를 사용했기에 2번의 콜드 스타트가 발생한다.)

  • 1초 간격으로 람다 실행: 2.72s -> 1.21s -> 0.75s -> 0.1s
  • 10초 간격으로 람다 실행: 2.75s -> 1.81s -> 1.6s -> 0.9s -> 0.4s -> 0.1s

0.1s 일때가 콜드 스타트가 완전히 없고 오로지 람다 코드만 실행된 상태이다.
그러니 최고 속도로 도달하기 위해선 여러번 빠른 호출이 필요하다.

이는 서버 운영에 생각보다 큰 문제점이었다. 🧐


콜드 스타트 해결하기

먼저 콜드 스타트 해결 방법에 대해 잘 정리된 글을 찾았다.
https://medium.com/postnl-engineering/the-5-ways-we-reduce-lambda-cold-starts-at-postnl-915e62401457

정리하면 아래와 같다.

1. provisioned concurrency (동시성 구성)
    람다를 계속해서 워밍업을 시켜주는 서비스이다. 추가비용이 많이 들기에 사용하지 않았다.
2. language choice (개발 언어 선택)
    언어에 따라 람다 속도차이가 있는데 추천 언어인 Typescript를 사용했다.
3. improve performance to reduce
    람다에 설정한 메모리 값에 따라 람다의 컴퓨팅 CPU 값이 정해진다. 비용을 고려해 최대로 scale-up 했다.
4. initialization code (초기화 코드 최적화)
    리팩토링을 진행하며 초기화를 위한 로직은 핸들러 외부인 초기화 코드로 적용했다.
5. package size (람다 용량)
    모든 람다를 inline으로 작성되었고 용량은 충분히 작았다.

5가지 사항 중 2~5번은 모두 충분한 수준으로 반영했지만… 결과는 크게 나아지지 않았다.



실제로 효과가 있었던 3가지 방법

여전히 콜드 스타트 때문에 애를 먹고 있었기에 자체적으로 다른 방법을 찾아야했다.
아래는 실제로 효과적적이었던 3가지 방법이다.

1. 아키텍쳐 최적화 (Lambda수 줄이기)

콜드 스타트 발생 원인에는 아키텍처 구조가 가장 큰 문제였다!
서비스에 필요한 api가 50개라면 처음엔 50개 람다를 만들었다.
그러다보니 각각의 모든 람다에 콜드 스타트가 발생했고 이는 큰 시너지가 되어 성능저하로 이어졌다.
아키텍처 최적화를 위해 여러개로 분리된 람다를 최대한 하나로 통합했다.

10개의 람다를 하나의 람다로 통합하면 콜드스타트 발생수는 1/10로 줄어든다.
실제로도 굉장히 효과가 좋았다.
(그리고 이땐 몰랐지만 AWS Cloud Formation의 Stack당 Max Resource수(500개) 제한 이슈도 해결하는 방법이 되었다.)

람다를 통합할 때 우려됐던 부분

  1. 람다 용량이 커지며 성능 저하
    합쳐도 여전히 3MB(람다 Inline Max Size) 내로 문제되지 않았다.

  2. 라우팅 시스템 구축 필요
    기존에는 모든 api를 gateway에서 라우팅을 해줬는데 람다를 통합하며 라우팅 시스템을 구축해야 했다.
    이벤트의 resource와 method를 이용해서 직접 라우팅 코드를 구현했다.

2. Auth용 Lambda 사용 중지

Auth를 별도의 람다로 구현하면서 문제가 생겼다.
Api를 호출하면 Auth 람다 + Api 람다 총 2번의 람다가 호출이 되고 이는 2번의 콜드 스타트가 발생하는 것이다.
Auth를 별도의 람다가 아닌 공통 모듈 Layer로 이동시키며 해결했다.

3. Event Bridge로 람다 워밍업

Event Bridge Rules의 Scheduler를 통해 주기적으로 람다를 계속 워밍업 시키는 방법이다.
provisioned concurrency을 대체하는 방법으로 볼 수 있으며 비용을 상당히 절약할 수 있다.
모든 람다에 스케쥴러를 붙이진 않았고 주요 람다에만 설정해줬다.

위 3가지 방법을 통해 콜드 스타트 문제는 1/10 수준으로 해결이 됐다! 😇


결론

어느 기술이나 장점이 있다면 단점도 같이 존재하는 법이다.
장점은 잘 취하고 단점은 해결해 나가는게 중요하다.
해결책은 있기 마련이다!

지금은 콜드 스타트가 많이 해결되긴 했지만 아예 없어진 수준은 아니다.
여기서 더 할 수 있는게 있다면 람다를 아예 1개로 통합하는 것이다.

콜드 스타트로 고생을 했지만 이 경험을 토대로 다음 프로젝트는 더 개선된 아키텍쳐를 구현할 수 있었다.

댓글남기기