의아한 점이 생겼다.
우선 원인을 알 수가 없는데... 분명 그저께까지 오류가 나던 'zappa update dev' 명령어에서 오류가 안 난다. 왜인지를 몰라서 답답하긴 한데 암튼 그렇다. 기본 URL 엔드포인트를 입력하면 404 에러가 뜨는데, 이건 말 그대로 해당 URL에 매핑된 view가 없어서 나는 에러였다. 토큰이나 개별 권한이 필요 없는 단순 조회 API를 검색해 봤더니 바로 잘 뜨더라.
이제 문제는 프론트 앱에서 이 엔드포인트를 사용하게 하는 것이다. 어떻게 가능하게 할 수 있을까? 내가 걱정되는 부분은 다음과 같았다.
- AWS lambda는 stable한가? 즉 갑자기 서버가 죽는 일이 없을까? 있다면 얼마나 빈번하게 일어날까?
- AWS lambda의 과금은 괜찮은가? 사용자가 없는 상태에서는 당연히 괜찮을 것 같긴 한데, 한 달에 어느 정도의 요금을 예상해볼 수 있을까?
- 응답 시간은 괜찮을까? lambda와 일반 ecs-ec2 서비스의 동작 방법의 차이를 아직 잘 몰라서, 너무 느리지는 않을까 걱정이다.
이 정도의 문제가 있었다. 여기에 대한 내 예상 답변은 다음과 같았다.
- '절대로' 죽지 않는 서버나 서비스는 아마도 없을 것이다. 중요한 것은 멘토님도 언급하셨던 graceful shutdown이 아닐까. 갑자기 처리하던 요청을 다 뱉고 그냥 죽어버리는 게 아니라, 그 유예기간 안에 notification을 받을 수 있고 그 안에 들어온 요청을 deny하거나 최대한 처리할 수 있도록 하는 것이 바람직하겠다.
- 내가 예상할 수 없다. 이 경우 대략적인 수치를 예상한 다음에 GPT에게 계산을 부탁하는 것이 낫겠다.
- 우선 '너무'의 기준을 정해야 하겠다. 그리고 GPT에게 동작 방법의 차이를 물어보자.
질의를 통해서도 한번 알아보았다. 우선은 1번 질문처럼 AWS lambda의 동작 방식이 기존의 ECS-EC2 동작 방식에 비해 더 안정된 것인지(서버가 갑자기 죽는 일이 덜한지)가 궁금했다. 마치 내가 면접관이 된 것처럼 GPT에게 꼬리 질문들을 통해 나름의 답을 구해 보았다.
AWS의 배포 방식 중 ECS, EC2를 같이 사용하는 방법과 AWS lambda를 사용해서 서버리스로 배포하는 방법 중 어떤 것이 더 서버가 죽는 일이 덜하고 안정적인지가 궁금해
여기서는 aws lambda와 aws ecs-ec2 배포의 차이(장단점)를 다음과 같이 언급했다.
- aws lambda는 서버리스인 반면(실제로 서버라는 개념이 아예 없는 것은 아니고, 서버 리소스 등의 관리를 aws에게 위임하는 방식으로 이해했다), aws ecs-ec2는 서버 내부에 사용자가 접근해서 구체적인 대응과 모니터링이 가능하다.
- aws lambda는 ecs로 배포했을 때처럼 장애에 직접적으로 대응해야 한다는 단점이 없는 반면, 오랫동안 리소스가 사용되지 않는 경우 발생하는 cold start 문제(일정 시간 이상 aws lambda가 호출되지 않으면 나중에 호출되었을 때 새로운 컨테이너가 초기화되는데, 그 과정에서 시간이 지연되는 문제)가 있다. 그리고 이 문제를 완화하기 위해서는 주기적으로 ping을 보내거나, provisioned concurrency라는 것을 사용하면 지정된 수의 컨테이너를 항상 활성화 상태로 유지할 수 있다고 한다. 다만 후자의 경우 비용은 추가될 수 있다.
나는 주기적으로 ping을 보내는 것도 괜찮지만 굳이 얼마인지 정확하게 알 수 없는 유휴 시간을 위해 ping을 보내서 불필요한 트래픽을 만드는 것보다는 provisioned concurrency를 통해서 컨테이너를 항상 활성화 상태로 유지하는 방법이 더 낫다고 생각했다. 다만 비용이 추가된다고 하니 얼마인지는 대략이나마 알고 싶었다.
cold start 문제를 완화하는 방법들 중 provisioned concurrency 방법을 사용하고 싶어. 내가 배포하려는 서비스는 트래픽이 많지는 않아서 cold start가 많이 발생할 것이라고 판단했기 때문이야. 만약 이 방법을 사용한다면 추가 비용이 어느 정도 발생할지도 궁금해
여기서는 lambda의 기본 요금 + provisioned concurrency의 추가 요금을 합해서 총 요금을 계산했다고 이해했다. 다만 lambda의 경우 매월 백만 건의 요청과 40만GB/초의 실행 시간이 무료라고 한다(사실 뒤의 부분은 잘 이해를 못 하고 넘어갔다). 어쨌든 하루에 최대 500개의 요청을 가정해도 한 달에 3만 건이기 때문에 lambda에서 발생하는 기본 비용은 일단은 0으로 가정하고 넘어갔다.
provisioned concurrency의 경우, 자세한 건 실행 후의 요금을 봐야 하겠지만 대략 '최소한의 동시 실행 환경 수 * 시간 * 리전 별로 다르게 적용되는 요금(GB/초)'이 최종 가격이라고 한다. GPT는 다음과 같은 상황을 가정해서 총 금액을 계산했다.
- 하루 평균 요청 수: 500개
- Lambda 함수의 평균 실행 시간: 100ms
- 메모리: 512MB (메모리의 크기와 Lambda 함수의 평균 실행 시간이 반비례하는 것으로 보였다)
- 총 금액: 약 12달러 이내 (약 18,000원 이내)
한 달에 서버비 2만원 이내면 나름 괜찮은 환경이라고 생각했다. 위 질문들을 통해 기존의 2번과 3번 질문에 대해서도 답을 얻었다. 결국 몇 개의 컨테이너(provisioned concurrency)를 사용하고, 메모리의 크기를 얼마로 설정하는지 등에 따라서 달라지는 값이었다. 그리고 사용자가 초기에 당연히 많지는 않을 것이므로, 이 상황에서 월 2만원 이내의 비용은 합리적이라고 생각했다.
그럼 이제 provisioned concurrency를 통해 aws lambda를 cold start 문제 없이 사용해 보자.
콘솔과 CLI 모두 가능했는데, 콘솔이 더 간단해 보여서 콘솔로 설정해보려고 했다. 우선 기존 버전에는 provisioned concurrency가 적용되지 않았으므로 새 버전을 배포해야 한다고 해서, 버전을 배포해 주었다.... 그랬는데 안 된다. 콘솔에서는 다음과 같은 에러가 나왔다.
그래서 CLI로 실행해 보았더니 맥락상 비슷한 에러가 나왔다.
맥락 상 추측해보면 '예약되지 않은 최소 계정 동시성'은 당장 사용할 수 없는 값이라고 이해했고, 사용하려면 이 값을 10이 아닌 8(2개의 동시성을 사용하고자 하는 경우라면) 등으로 줄여 줘야 한다고 이해했다. 그래서 아래와 같은 명령어도 입력해 보았다.
aws lambda delete-function-concurrency --function-name backend-dev
이후 다시 실행해 봤지만 똑같았다. 여기서 다시 고민했다. 여기서 에러를 계속 디버깅해 볼 수도 있겠지만, 저번에도 그러다가 4시간의 삽질을 한 것이 생각났다.
만약 provisioned concurrency 방법의 대안이었던 ping을 쏘는 방법도 비용적으로 괜찮은 선택지라면 그 방법을 써도 되지 않을까? 바로 물어봤다.
아까 위에서 네가 'cold start 문제를 완화하는 방법'들에 대해서 알려줬잖아. 여기서 두 가지 방법(provisioned concurrency, ping) 중 하나를 사용하고 싶어. 만약 1일간 호출이 500개가 되지 않는 서비스라면 비용 면에서 어떤 방법이 더 나을지 설명해줘
놀랍게도 1분 간격으로 ping을 쏜다고 가정했을 때 ping을 쏘는 방법이 더 저렴했다. 그렇다면 굳이 provisioned concurrency를 사용할 이유가 없었다. 녀석(GPT)은 만약 운영 중 트래픽이 늘거나, ping을 사용했음에도 cold start가 지속적으로 발생한다면 그때는 provisioned concurrency를 사용할 것을 추천해줬다.
그렇다면 그래도 cold start 발생 가능성을 더 줄여봐야 하지 않나 싶어서 다시 질의해봤다.
ping 방식을 사용했을 때 cold start 문제가 최대한 발생하지 않도록 하고 싶어. 하지만 cold start 문제의 경우 최대 몇 초/분간 요청이 없어야지만 cold start 현상이 나타나는지를 정확히 알 수 없다는 문제가 있는 걸로 알고 있어. 이 경우 ping 방식을 사용할 때 어느 정도의 간격으로 ping을 보내야 cold start 문제가 발생할 확률을 1% 이내로 줄일 수 있을지 알려줘
GPT가 제시하는 1%의 cold start 확률 이내의 ping 간격은 2분이었다. 즉 아까보다 ping을 덜 쏘아도 provisioned concurrency를 선택했을 때보다 현재 상황에서는 비용이 저렴하다고 이해했다. 그래서 provisioned concurrency 대신에 ping을 쏴 보기로 결정했다.
그런데 aws lambda에게 ping을 쏘는 주체는 누구일지도 궁금했다. 질의를 통해 알아보니 cloudwatch event에서 쏜다고 했다. cloudwatch는 모니터링 툴이라고만 알고 있었는데 여기서 ping을 쏜다니 의아했다. 이것도 물어보니 cloudwatch 서비스의 하위 기능들 중 cloudwatch event를 제공해서, 이벤트를 직접 발생시키거나, 특정 이벤트가 발생했을 때 이를 기반으로 다른 작업을 수행할 수 있도록 해 준다고 했다. 여기서 ping을 쏘는 것은 이벤트를 직접 발생시키는 경우에 속할 것이다.
그러면 cold start를 방지하기 위해서 aws lambda에게 ping을 주기적으로 쏘도록 cloudwatch event를 설정해 보자. 'cloudwatch' 서비스를 입력해서 들어간 뒤, 왼쪽 메뉴에서 이벤트>규칙을 눌러봤다. 신기하게도 이미 warm callback이라고 된, 즉 방금 얘기한 것과 같이 cold start를 방지하기 위한 콜백용 이벤트를 발생시키고 있었다.
다만 간격이 2분이 아닌 4분이라서, 확률 상 cold start가 발생할 수도 있다고 판단했다. 그래서 해당 시간 간격만 2분으로 줄여 주었다.
이제 cloudwatch에서 2분마다 이벤트를 발생시켜서 aws lambda 함수를 호출한다. 이 warm callback을 통해서 cold start를 방지할 수 있을 것이다.
✅ 궁금한 점
- aws lambda가 aws ecs-ec2였다면 직접 대응을 해야 하는 상황이지만 서버리스라서 직접 대응을 안 해도 되는 경우가 있을 것이다. 구체적으로 어떤 경우들이 있을지 궁금하다.
'개발 일기장 > SWM Onestep' 카테고리의 다른 글
20241227 TIL: aws lambda 실행 오류 해결하기 [진행중] (2) | 2024.12.27 |
---|---|
20241223 TIL: api gateway에서 custom domain을 사용해서 porkbun 도메인과 연결하기 [진행중] (0) | 2024.12.23 |
20241219 TIL: zappa로 lambda에서 django 서버 배포하기 [진행중] (4) | 2024.12.19 |
20241216 TIL: subnet 안에 lambda 배치하기 [진행중] (1) | 2024.12.16 |
20241215 TIL: terraform으로 aws vpc 세팅하기는 핑계고 (1) | 2024.12.15 |