AWS 청구서가 갑자기 치솟는 이유 — 흔한 7가지 원인
예상치 못한 AWS 비용 증가가 띠는 일곱 가지 형태, 각각이 Cost Explorer에서 어떻게 보이는지, 그리고 재발하기 전에 추적해 내는 방법을 정리합니다.
전월 대비 30% 청구서 증가에는 보통 그 안에 숨은 단 하나의 원인이 있습니다. 어려운 점은 AWS가 데이터를 나눠 볼 차원을 열두 가지나 준다는 것입니다. 서비스, 사용 유형, 리전, 계정, 태그. 그리고 급증은 처음 시도하는 차원에서 깔끔하게 드러나는 경우가 드뭅니다. 이 글은 우리가 본 청구 급증 사건의 대부분을 차지하는 일곱 가지 원인, 각각이 Cost Explorer에 남기는 특징, 그리고 가장 먼저 나눠 봐야 할 차원을 훑습니다.
1. NAT 게이트웨이 데이터 처리
NAT 게이트웨이는 고정 시간당 요금에 더해 GB당 데이터 처리 요금을 부과합니다. 시간당 요금은 작고 안정적이지만, 새 워크로드가 VPC 바깥에서 이미지, 모델, 백업을 당겨오기 시작하면 데이터 처리 요금이 소리 없이 10배가 될 수 있습니다. 흔한 패턴은 이렇습니다. 쿠버네티스 노드 풀이 확장되고, 새 파드마다 500MB짜리 컨테이너 이미지를 NAT 게이트웨이를 거쳐 당겨오면서 청구서가 조용히 불어납니다.
Cost Explorer 특징 — EC2-Other 사용 유형이고, 세부 내역에
NatGateway-Bytes가 있습니다. Service 열에는 VPC가 아니라 EC2라고
적힙니다.
해결 경로 — VPC 엔드포인트(S3와 DynamoDB는 Gateway, 나머지는 Interface)는 NAT을 통째로 우회합니다. 컨테이너 레지스트리(ECR)에는 전용 Interface 엔드포인트가 있는데, 어느 정도 규모로 이미지를 당겨온다면 며칠 안에 본전을 뽑습니다.
2. AZ 간 데이터 전송
같은 리전 안에서 가용 영역(AZ) 사이로 1GB를 옮기는 가격은 많은 경우 완전히 다른 리전으로 옮기는 것과 같습니다. 방향마다 GB당 $0.01입니다. 다중 AZ 복원력을 염두에 두고 설계하는 엔지니어는 AZ 경계를 넘는 모든 요청이 양방향으로 과금된다는 점을 자주 놓칩니다. 영역 인식 라우팅(zone-aware routing) 없이 수다스러운 마이크로서비스 메시는 단일 리전 안에서도 네 자릿수 월 전송 요금을 만들어 낼 수 있습니다.
Cost Explorer 특징 — EC2-Other이거나 특정 서비스 요금이고, 사용
유형에 DataTransfer-Regional-Bytes 또는 InterZone-Out이 있습니다.
해결 경로 — 서비스 메시(Istio, Linkerd, App Mesh)에서 토폴로지 인식 라우팅을 켜거나, 읽기가 로컬 AZ 복제본에 닿도록 클라이언트 인식 파티셔닝을 설정하세요. 하루 단위 AZ 간 바이트를 그래프로 그려 확인하세요.
3. CloudWatch Logs 수집
CloudWatch Logs는 저장된 GB가 아니라 수집된 GB당 과금하며, 수집 가격($0.50/GB)은 저장 가격($0.03/GB)의 열 배가 넘습니다. 부하 상황에서 추가된 디버그 수준 로그 한 줄이 시간당 수 기가바이트를 만들어 낼 수 있고, 비용이 빠르게 올라갑니다.
Cost Explorer 특징 — AmazonCloudWatch이고 DataProcessing-Bytes
또는 Storage-ByteHrs가 있습니다. 사용 열은 리소스 수준 그룹화를 켠
경우에만 로그 그룹 이름을 보여 줍니다.
해결 경로 — 디버그 로그 줄을 없애거나 샘플링 필터를 거치게 하세요. 대용량 구조화 로그라면, 같은 보존 기간에 대해 Kinesis Firehose로 S3에 바로 쓰는 편이 흔히 90% 더 쌉니다.
4. 종료된 인스턴스에서 분리된 EBS 볼륨
EC2 인스턴스를 종료하면 부팅 볼륨은 기본적으로 함께 사라지지만, 추가로 연결한 볼륨은 그렇지 않습니다. 시간이 지나면 분리된 볼륨이 쌓입니다. 개별로는 쌉니다(gp3는 GB-월당 $0.08). 하지만 개수가 단조롭게 늘어나고 정리를 책임지는 사람은 아무도 없습니다.
Cost Explorer 특징 — EC2-Other이고 EBS:VolumeUsage.gp3(또는
gp2)이며, 인스턴스 시간을 따라가지 않으면서 일별 비용이 꾸준히
오릅니다.
해결 경로 — AWS Config 규칙 ebs-snapshot-public-restorable-check에
더해, 30일 넘게 분리된 볼륨을 자동 삭제하는 Lambda를 둡니다. 수동으로는
EBS 볼륨 콘솔을 상태 = available로 정렬하고 가장 최근 연결 시점을
확인하세요.
5. CloudFront 캐시 미스
CloudFront 가격은 두 가지 구성 요소로 이뤄집니다. 사용자로 나가는 대역폭과 HTTP 요청입니다. 캐시 적중은 엣지에서 응답하므로 대역폭만 냅니다. 캐시 미스는 오리진에서 응답하므로 대역폭에 더해 오리진 egress까지 냅니다. 잘못 설정된 캐시(24시간이어야 할 TTL이 60초이거나, 정규화해야 할 쿼리 문자열 민감 캐시 키)는 최종 사용자 경험을 바꾸지 않고도 10배의 비용 차이를 만들 수 있습니다.
Cost Explorer 특징 — Amazon CloudFront 비용이 오리진(S3, ALB, 또는 EC2)의 DataTransfer-Out과 발맞춰 오릅니다. 두 수치는 함께 움직이면 안 됩니다. 함께 움직인다면 캐시가 거의 작동하지 않는 것입니다.
해결 경로 — 배포의 보고서 탭에서 CloudFront 캐시 적중률을 확인하세요. 80% 미만이면 문제이고, 50% 미만이면 캐시가 망가진 것입니다. 캐시 키를 보세요. 쿼리 문자열, 헤더, 쿠키가 흔히 과도하게 포함됩니다.
6. 리전 간 API Gateway / Lambda 잘못된 설정
대상 리소스와 다른 리전에서 호출되는 Lambda는 Lambda 호출 비용에 더해 리전 데이터 전송을 냅니다. 흔한 형태는 이렇습니다. us-east-1에 배포된 함수가 eu-west-1의 DynamoDB 테이블을 호출하는데, 마이그레이션 중 누군가 테이블 ARN 갱신을 잊었기 때문입니다. 호출마다 요청과 응답 바이트가 대서양을 건넙니다.
Cost Explorer 특징 — 한 리전만 활성이어야 하는데도, DataTransfer-Out-Bytes가 두 리전에 대략 비슷한 양으로 나타납니다.
해결 경로 — 스택에 리전 태그를 붙이고 주기적으로 감사하세요. 리전을 넘어 통신하는 것은 무엇이든 명시적이고 의도적이어야 합니다(글로벌 복제, 재해 복구 테스트). 결코 우연이어서는 안 됩니다.
7. 체험 기간 또는 마켓플레이스 만료
AWS Marketplace 구독과 예약 인스턴스 할인은 둘 다 달력상의 경계, 보통 월말에 만료됩니다. 그 다음 날, 기반 리소스에 온디맨드 요율이 적용됩니다. 인스턴스 개수와 사용 프로파일은 전월과 똑같아 보입니다. 바뀐 것은 요율뿐입니다.
Cost Explorer 특징 — 같은 서비스, 같은 인스턴스 유형, 같은
시간인데 Pricing의 단위당 비용이 뜁니다. 비용과 사용량 열에 두
항목을 나란히 놓고 보면 알아채기 더 쉽습니다.
해결 경로 — 단순 절대 지출이 아니라 단위당 비용 편차에 알림을 주는 Cost Explorer 예산을 설정하세요. RI라면 Trusted Advisor의 예약 만료 점검이 2주 앞서 이를 잡아냅니다.
종합하기
특정 급증을 진단할 때 가장 자주 통하는 순서는 이렇습니다. 먼저 서비스로 그룹화하고, 그다음 최상위 기여 요인 안에서 사용 유형으로, 그다음 연결 계정이나 태그로 그룹화합니다. 급증 대부분은 사용 유형 수준에서 해결됩니다. 그렇지 않다면 문제는 보통 #6(리전 간)이나 #5(캐시 설정)이며, 비용 데이터가 아니라 요청 수준 데이터를 봐야 합니다.
이 작업을 정기적으로 한다면, AWS Billing Analyzer가 Cost Explorer CSV 내보내기를 받아 위의 일곱 가지 패턴과 각각의 최악 요인을 바로 드러냅니다. 전적으로 브라우저 안에서 돌아갑니다. CSV는 기기를 떠나지 않습니다. 파일에는 보통 외부 사이트에 올리고 싶지 않은 계정 ID와 리소스 ARN이 들어 있으니 중요한 부분입니다.