AWS Lambda를 시작하기 전 알았으면 좋았을것들

Harry The Great
해리의 유목코딩
13 min readJun 11, 2018

제가 처음 Serverlesss를 접했을때 생각했습니다. 정말 힙하고 쿨하다. 앞으로 로직에만 집중하고 서버따위는 생각조차 하지않고 뭐든 이렇게 개발하면 정말 좋겠다. 그러다 토이프로젝트를 만들어보고 프로덕션 레벨에 도입을 해보면 깨닫게됩니다.

(경험한걸 한짤로 표현하자면…)

AWS Lambda를 도입하면서 겪게 되는 문제들과 어떻게 해결할 수 있는지 그리고 어떤 경우가 적합한지에대해 겪은 문제들을 공유하고자 글을 작성하였습니다.

Warm Vs Cold

우리가 다큐에서 머신건을보면 처음부터 마구 발사되지는 않습니다. 맨처음 앞부분이 천천회 회전하더니 엄청난 양의 총알을 퍼붇습니다. 비슷하게 람다에는 Warm Start와 Cold Start가 있어 미리 예열된 상태라면 이전보다 훨씬 빠른속도로 함수들을 처리합니다. Warm/Cold가 사실 단어가 상당히 영어적인 표현입니다. 우리말로 바꾸자면 람다가 바로 준비 된 상태 그리고 람다가 바로 준비되지 않은 상태가 제일 적절할 것 같습니다.

람다는 처음 호출한다면 Cold Start를 하게됩니다. 이 경우 초기 지연시간이 발생합니다. 그리고 Warm 상태를 유지하며 이때의 경우는 람다를 다시 호출해도 지연시간이 발생하지 않고 빠르게 응답하게됩니다. 그러다 약 5분여 이상 호출이 되지 않는다면 Cold상태로 바뀌고 다시 호출될 경우 지연시간을 가지고 Cold Start를 하게됩니다.

언어마다 다른 Cold Start

출처: https://theburningmonk.com/2017/06/aws-lambda-compare-coldstart-time-with-different-languages-memory-and-code-sizes/

위 이미지에서 확인할 수 있듯이 파이썬과 노드의 경우 상당히 빠른 Cold Star Time을 가지게되고 그에반해 자바와 C#은 느린 시작을 확인할 수 있습니다. 위 이미지에는 나오지 않지만 Go 언어 역시 파이썬과 같은 아주 빠른 속도의 Cold Start를 하게됩니다.

메모리마다 다른 Cold Start

출처: https://theburningmonk.com/2017/06/aws-lambda-compare-coldstart-time-with-different-languages-memory-and-code-sizes/

설정한 메모리에 따라서도 Cold Start Time이 다르며 1024로 하였을 경우가 가장 최적의 퍼포먼스가 나오게됩니다.

그 이외 람다 퍼포먼스에 영향을 주는 것들

위 요소뿐만 아니라 람다가 VPC 네트워크 내부에 속하는지 그리고 Cognito나 IAM을 사용하여 인증을 하는지에 따라서도 지연시간이 발생하며 같은 언어 같은 메모리를 사용하더라도 언어별 버전에따라서도 지연시간은 차이가 납니다.

Cold Start 얼마나 문제가 될까?

저의 경우 서울리전에서 Node8 버전으로 Cold Start 테스팅을 하는경우 안드로이드 클라이언트에서 지연시간이 약 1000ms 초 정도의 추가적인 지연시간을 보이고있어 사용자가 겪는 문제는 미미하다고 판단하였습니다. 물론 지역에 따라선 다르겠지만 안드로이드 클라이언트에서 Crashlistic을 통해 확인한 결과로는 5초 이상 지연될 경우 발생하도록 한 Timeout에러는 거의 발생하지 않았습니다.

Cold Start를 해결하는 방법

람다를 5분마다 실행하면 Cold Start를 해결할 수 있습니다. ColudWatch를 통해 람다를 5분마다 한번씩 지속적으로 호출을 하거나 Route 53에서 Health Check를 람다 함수 API Gateway Endpoint 로 설정해둘수도 있습니다. 한가지 주의할점은 호출이 많을때도 Cold Start가 발생합니다. 확인해보지는 못했지만 요청이 많아져 Lambda가 스케일링이 될 경우 지연시간이 존재한다고합니다.

5분마다 함수를 실행하는경우 비용이 어느정도 늘어날 수 있습니다. Warmup Plugin의 Document에 의하면 프리티어를 고려하지 않고 메모리 1024로 람다가 약 10초간 실행되는 함수를 10개 Warm 상태를 유지하는경우 대략적인 비용은 아래와 같습니다.

  • 함수 호출 비용 = 0.18$
  • 함수에 사용한 컴퓨팅 비용= 14.4$
  • 합계 14.58$

퍼블릭 VPC로 인터넷에 엑세스 할 수 없다.

VPC를 구성하여 람다를 사용할경우 Private VPC를 구성해주어야합니다. 다르게 생각해보면 맞는말인것이 람다는 공통으로 사용할 수 있는 컴퓨팅 자원이기때문에 하나의 VPC에 IP대역을 다 줄수는 없습니다. VPC구성은 보안에 있어 가장 중요한 설정들이기때문에 혹시 프라이빗 VPC와 퍼블릿 VPC에 대해 잘 모르신다면 꼭 이 링크를 참조해주세요. 프라이빗 VPC를 구성할경우에는 NAT Gateway를 이용할경우 월 50불 정도의 요금을 내야하지만 비용이 부담되신다면 NAT Instance를 구성하여 프리티어로도 커버할 수 있습니다.

개발 프레임워크

Serverless.js

흔히 Lambda에 대해 찾아본다면 가장 많이 볼 수 있는 내용이 Serverless.js입니다. 서버리스를 쉽게 만들어주는 툴로 cloudformation이나 API 연결 디비생성등을 자동화해줍니다. 물론 단점도 있습니다. serverless.js는 구글 클라우드 마소 에저등 다양한 서버리스 플랫폼을 지원하고 있는데다 AWS에 특화되어 서비스하지 않기때문에 X-RAY같은 새로운 기능들이 추가되어도 사용할 수 없는 경우가 많습니다. 이럴 경우 Serverless.js의 플러그인을 통해 오픈소스로 플러그인들이 나오기는 하지만 대부분이 개인들이 만든 오픈소스여서 aws-cli나 serverless.js가 버전업될때마다 기술부채로 남을 수 있습니다.

SAM

aws labs에서 직접 관리하는 서버리스 개발 프레임워크입니다. 람다와 dynamodb를 도커환경에서 테스트해볼 수 있고 최신 기능들 역시 금방금방 지원이 됩니다. 단점은 아직은 베타라는 점 그리고 적은 사용자풀로 인해 참고할만한 레퍼런스가 많이 부족합니다.

AWS-CLI + CloudFormation

가장 좋은 방법이지만 난이도가 높습니다. 직접 CloudFormation을 다 관리하여야하지만 자유도가 제일 높고 실무에서 실제 서비스에 적합하기에 가장 좋은 방법입니다.

로깅 및 모니터링

Kibana

Lambda 로깅 및 모니터링을 검색하다보면 수 없이 많은 모니터링 도구들이 나옵니다. 물론 대부분이 비용을 요구하고있고 그리 좋지도 못합니다. AWS에서 제공하는 ElasticSearch와 Kibana를 사용하면 많은 시간을 들이지 않고 아주 손쉽게 람다 모니터링 환경을 구축할 수 있습니다.

(Lambda Kibana 모니터링 화면)

또한 람다의 상세 로그옵션을 활성화하면 람다에서 발생하는 모든 로그들을 CloudWatch와 Kibana로 확인할 수 있고 경보기능을 통해 람다에서 일정시간동안 일정개수 이상의 오류가 발생할 경우 슬랙이나 이메일로 알림이 오도록 설정하여 모니터링 할 수 있습니다.

X-RAY

위의 Kibana를 통해 개별적인 람다함수를 모니터링을 할수는 있지만 연결된 다른 함수까지와의 문제들과 유기적인 연결까지는 상세히 파악하기 어렵습니다. 이 경우 AWS X-RAY를 사용하면 손쉽게 확인할 수 있습니다. 각 Lambda, MongoDB, S3 등에서의 지연시간등을 다이어그램으로 확인할 수 있어 어느곳에서 병목현상이 일어나는지 어느곳에서 문제가 발생하고 있는지를 한눈에 파악할 수 있습니다.

테스트 자동화

서버리스를 위한 자동화같은경우 툴이 따로 존재하지않지만 기존의 테스트툴을 사용하여서도 손쉽게 테스트환경을 쉽게 구축할 수 있습니다.

람다만 테스트하는 경우

람다의 구조는 아주 간단합니다 Input이 들어오면 Output을 내뱉는 구조입니다. Node.js에서의 예를 들자면 Event인자 통해 Invoke, Post, Get등의 데이터가 들어오면 그 데이터를 처리하고 처리한 내용을 Callback함수로 응답값을 보내거나 다른 함수로 전달하는 방식입니다. 때문에 단위테스트를 손쉽게 작성할 수 있습니다.

(좋지 못한 코드의 예시)

위와 같이 코드를 작성하면 코드간의 관계가 너무 유기적이여서 테스트하기가 상당히 힘이듭니다.

(테스트 하기 좋은 예시)

위와같이 모듈단위로 함수를 작성한다면 User 클래스만 따로 import하여 테스트 코드를 쉽게 작성할 수 있습니다.

저의 경우는 코드를 작성한 후 푸시를 할경우 Codebuild를 통해 코드들을 땡겨온 후 작성된 테스트 코드들을 실행하고 테스트에 문제가 없을경우 deploy, 테스트에 문제가 있다면 원인을 Slack으로 알림이 오도록 하였습니다.

DyanmoDB가 함께 필요한 경우

SAM을 사용할경우 로컬환경에서 바로 DynamodbDB를 도커를통해 사용가능하지만 그렇지 않다면 로컬에 직접 DyanmoDB를 구축하여야합니다. 자세한 내용은 이 링크에서 확인할 수 있습니다. Serverless.js를 사용하신다면 플러그인을 통해 구축할 수 있습니다.

Lambda는 비싸다

컴퓨팅 자원으로만 본다면 람다는 EC2에 비해 월등히 비싸고 온디맨드로 한다면 차이는 배 이상으로 발생합니다. 그런데도 Lambda는 비용을 줄일 수 있습니다. 우리가 일반적으로 서비스를 운영할때 CPU 사용률나 메모리 사용량을 약 70%정도로 설정을 해두고 70%가 넘어갈경우 서버가 스케일링 되도록 구성을 하게됩니다. 그리고 다시 70~80% 이하로 유지하도록 하게됩니다. 하지만 Lambda를 사용한다면 항상 100%의사용량을 달성할 수 있고 사용을 하지 않는 동안에는 유휴상태로 금액을 지불하지 않기때문에 클라우드의 가장 큰 장점인 내가쓴만큼만 비용을 지불할 수 있습니다.

Step Function

람다는 기본적으로 상태값이 없습니다. 즉 어떤 작업을 처리하기 위해서는 DB에서 데이터를 확인하거나 하는 작업이 필요합니다. 쇼핑몰의 경우 데이터를 받아도 현재 사용자가 결제한 상태인지 장바구니에만 넣은 상태인지를 확인해야합니다. 이런 경우 Step Function 사용을 고려해볼 수 있습니다. Step Function이란 람다함수를 워크플로우 단위로 묶은 서비스입니다.

Step Function은 다음과 같을경우 사용할 수 있습니다. 위에 앞서 설명한 내용처럼 쇼핑몰을 구축했을경우 POST나 GET을 통해 주문번호등을 받고 그 주문번호와 일치하는 Step Function으로 데이터를 넘깁니다. 그럼 Step Function은 진행중이었던 단계에 맞게 그 데이터를 처리할 람다함수에 데이터를 보내줍니다. 위와 같이 구성한다면 상태 정보를 조회하기위한 DB에서의 병목현상을 줄이고 각각의 워크플로우들을 한눈에 관리할 수 있습니다.

결제가 완료될 경우까지 진행했다면 판매자에게 결제가 되었음을 알려준다거나 배송완료가 된다면 사용자에게 알려주는이벤트를 붙일 수 있고 결제가 성공했을경우 배송준비로 실패했을경우 발생하는 람다함수가 몇번까지 재시도를 하고 실패상태로 바뀔지 또한 실패 상태가 되었을 경우에는 관리자에게 실패의 원인과 해당 주문번호를 알려줄 수 있습니다.

10분 ~ 1시간 이내의 작업들

람다는 최대 5분정도까지 사용할 수 있습니다. 게다가 메모리 사용량또한 제한이 있습니다. 이때문에 디비백업, 영상 인코딩 같이 많은 컴퓨팅용량이 단시간내에 많이 필요할경우 상당히 비효율적입니다. 그렇다고 EC2 인스턴스를 사용하기도 애매할때가 있습니다.

이럴때는 ECS Fargate를 사용하면 경제적으로 사용할 수 있습니다. ECS Fargate는 사용자가 만든 도커이미지를 별도의 EC2 인스턴스나 기타설정없이 실행하고 실행된 시간만큼만 금액을 지불합니다. 동영상 구간별 썸네일 추출같이 단시간 많은량의 메모리가 필요한 경우 아주 효율적으로 사용할 수 있습니다.

수시간 이상 걸리는 작업들

ECS Fargate를 소개해드렸지만 서울리전에서는 사용할 수 없는데다가 비용도 일반 EC2 인스턴스보다는 가격이 상당히 비쌉니다. 이렇게 장시간 컴퓨팅 작업이 필요한 경우에는 ECS 혹은 EC2 서비스를 사용하는편이 더 경제적으로 사용할 수 있습니다.

모든걸 AWS에서만 해야할까?

AWS는 일반적인 서버개발 그리고 웹관련 개발을 진행할때는 정말 훌륭합니다. 하지만 반대로 모바일쪽 SDK나 개발관련 레퍼런스는 상당히 부족합니다. 저의 경우 IOS와 Android에서의 데이터 연동을 위해 AWS APP Sync를 도입해보려고 고군분투 하였으나 너무나 빈약한 도큐먼트와 레퍼런스로 결국에는 사용하던 Google Firebase로 변경하였습니다. 애플역시 많은 아키텍쳐를 Cloud 환경에서 개발하는걸로 유명합니다. 애플은 구글, 애저, AWS등 다양한 플랫폼을 사용하고 있고 점점 많은 개발이 단일 Cloud 환경에서 Multi Clouds로 넘어가고있습니다. 한가지의 방법만 고집하기보다는 각각 직면하는 환경에 맞추어 개발하는것이 가장 좋은 개발 생산성을 낼 수 있는 것 같습니다.

마치며

하나의 단일한 개발환경에서 서버리스로 넘어가기 위해선 그만큼 많은 시행착오가 생기는것같습니다. 위에 언급한 서버리스의 문제점이 있더라도 서버리스가 가지는 장점은 많습니다. 예를들어 제가 Nodejs로 개발을 하더라도 파이썬만 지원하는 플러그인이 필요하다면 파이썬 Lambda 함수를 만든 후 결과값을 Nodejs 람다함수와 JSON형식으로 리턴하도록 할 수 있습니다. 더이상 하나의 플랫폼 하나의 단일한 환경에서 개발하는 시대가 아닌 다양한 플랫폼에서 다양한 환경으로의 개발이 대세가 되고있습니다. 이러한환경에서 개발을 하기에 AWS Lambda는 아주 훌륭한 환경이 될 수 있을 것 같습니다.

레퍼런스

--

--

Harry The Great
해리의 유목코딩

Android & IOS Developer 😀 미디움 이외에 스니펫이나 디버그노트로 활용하는 https://www.harrymikoshi.com/ 블로그도 운영하고있습니다.