아키텍처 케이스 · 3
S3 비용이 매달 늘어난다
Amazon S3 요금이 늘어나는 이유는 대개 셋 중 하나입니다 — 지운 줄 알았던 이전 버전, 완료되지 않은 멀티파트 업로드, 접근하지 않는데도 S3 Standard에 남아 있는 객체. 셋은 원인도 처방도 다르므로, 먼저 무엇이 용량을 차지하는지 나누고 시작합니다.
학습 목표
- 버킷 저장 용량이 줄지 않는 원인을 이전 버전·미완료 업로드·클래스 방치로 나눠 진단할 수 있습니다.
- 스토리지 클래스별 최소 저장 기간과 최소 청구 크기가 수명 주기 설계를 어떻게 제약하는지 설명할 수 있습니다.
- 접근 패턴을 모르는 데이터에 S3 Intelligent-Tiering을 고르는 근거를 댈 수 있습니다.
- 완료되지 않은 멀티파트 업로드를 수명 주기 규칙으로 정리할 수 있습니다.
- 시험 문항에서 "접근 패턴을 예측할 수 없다"와 "거의 접근하지 않는다"를 구분해 다른 클래스를 고를 수 있습니다.
상황
미디어 서비스가 원본 영상과 변환 결과, 그리고 일일 로그를 하나의 S3 버킷에 저장합니다. 운영을 시작한 지 2년이 지났고, 저장 용량과 요금이 매달 단조 증가합니다. 팀은 "오래된 파일은 지우는 배치가 돌고 있다"고 알고 있었지만, 실제 버킷 크기는 줄어든 적이 없습니다.
조사해 보니 다음 네 가지가 겹쳐 있었습니다.
| 원인 | 무슨 일이 일어났는가 | 왜 눈에 띄지 않았는가 |
|---|---|---|
| 버전 관리 + 삭제 배치 | 버전 관리가 켜진 버킷에서 객체를 삭제하면 삭제 마커가 생기고 이전 버전은 남는다 | 목록 조회에서는 사라진 것처럼 보인다. 용량은 그대로다 |
| 완료되지 않은 멀티파트 업로드 | 대용량 업로드가 중간에 실패하면 이미 올라간 파트가 버킷에 남아 요금이 발생한다 | 객체 목록에 나타나지 않는다. 전용 API로만 보인다 |
| 클래스 방치 | 2년 전 로그가 아직 S3 Standard에 있다 | 동작에는 아무 문제가 없으므로 아무도 보지 않는다 |
| 접근 패턴 미상 데이터 | 변환 결과는 어떤 것은 매일 읽히고 어떤 것은 1년째 안 읽힌다 | 객체 단위로 판단할 방법이 없어 전부 Standard에 둔다 |
요구사항과 제약
| 구분 | 내용 | 설계에 주는 함의 |
|---|---|---|
| 요구 1 | 저장 용량 증가를 멈춘다 | 남아 있는 것을 지우는 일과, 앞으로 쌓이지 않게 하는 일을 나눈다 |
| 요구 2 | 원본 영상은 영구 보관한다 | 삭제가 아니라 저렴한 클래스로 옮기는 것이 답이다 |
| 요구 3 | 로그는 1년 보관 후 삭제한다 | 만료 규칙으로 자동화한다 |
| 제약 1 | 변환 결과의 접근 패턴을 예측할 수 없다 | 고정 클래스로는 최적화가 불가능하다 |
| 제약 2 | 원본 영상은 요청 시 수 시간 내 꺼낼 수 있으면 된다 | 즉시 검색이 필요 없으므로 아카이브 클래스가 가능하다 |
| 제약 3 | 실수로 지운 파일을 30일간 복구할 수 있어야 한다 | 버전 관리는 끄지 않는다. 대신 이전 버전에 만료 규칙을 건다 |
배경 개념은 8장 S3와 오브젝트 스토리지에 있습니다. 스토리지 클래스 전체 목록과 최소 저장 기간 표를 먼저 확인하면 아래 판단이 빨라집니다.
먼저 무엇이 용량을 차지하는지 나눈다
처방을 고르기 전에 원인을 분리합니다. 원인을 나누지 않으면 수명 주기 규칙을 붙여도 용량이 줄지 않고, "S3 수명 주기는 효과가 없다"는 잘못된 결론에 도달합니다.
# 1) 완료되지 않은 멀티파트 업로드 — 객체 목록에는 나타나지 않습니다.
aws s3api list-multipart-uploads \
--bucket example-media \
--query 'Uploads[].[Key,UploadId,Initiated]' \
--output table
# 2) 이전 버전과 삭제 마커 — 버전 관리가 켜진 버킷에서만 존재합니다.
aws s3api list-object-versions \
--bucket example-media \
--prefix logs/ \
--query 'length(Versions)'
aws s3api list-object-versions \
--bucket example-media \
--prefix logs/ \
--query 'length(DeleteMarkers)'
# 3) 버전 관리 상태 확인
aws s3api get-bucket-versioning --bucket example-media
후보 설계안 비교
데이터 종류가 셋(원본 영상 · 변환 결과 · 로그)이므로, 후보도 "전부 하나로 처리하는 안"과 "종류별로 다르게 처리하는 안"으로 갈립니다.
| 항목 | A · 버킷 전체를 One Zone-IA로 | B · 버킷 전체를 Intelligent-Tiering으로 | C · 접두사별로 다른 수명 주기 규칙 | D · 오래된 데이터를 직접 삭제 |
|---|---|---|---|---|
| 원본 영상 요구(영구 보관) | 위험 — 단일 가용 영역에만 저장된다 | 가능하지만 아카이브 티어 설정이 필요 | Deep Archive로 전환 | 요구 위반 |
| 변환 결과(패턴 미상) | 접근이 잦으면 검색 요금이 커진다 | 자동 계층화가 정확히 이 문제를 푼다 | 고정 규칙으로는 판단할 수 없다 | 해당 없음 |
| 로그(1년 후 삭제) | 삭제가 자동화되지 않는다 | 삭제가 자동화되지 않는다 | 만료 규칙으로 자동 삭제 | 사람이 계속 관리해야 한다 |
| 이전 버전·미완료 업로드 | 그대로 남는다 | 그대로 남는다 | 전용 규칙으로 정리 | 수작업 대상이 계속 늘어난다 |
| 운영 부담 | 낮음 | 가장 낮음 — 판단을 AWS가 한다 | 규칙 설계가 한 번 필요하다 | 가장 높음 — 계속 사람이 한다 |
| 판정 | 오답 — 내구성 요구와 충돌 | 변환 결과에 한해 채택 | 채택 — 전체 골격 | 오답 — 자동화 없이는 재발 |
One Zone-IA를 함부로 고르지 않는 이유
S3 One Zone-IA는 이름 그대로 가용 영역 하나에만 데이터를 둡니다. 저장 비용은 Standard-IA보다 낮지만, 그 가용 영역이 소실되면 데이터가 함께 사라집니다. 그래서 다시 만들 수 있는 데이터(썸네일, 재생성 가능한 변환 결과)에는 적합하고, 원본에는 적합하지 않습니다. 시험에서 "재생성할 수 있다", "2차 사본이다"라는 문장이 One Zone-IA의 신호입니다.
선택과 근거
C를 골격으로 삼고, 변환 결과 접두사에만 B(Intelligent-Tiering)를 적용합니다. 접두사별로 요구가 다르므로 규칙도 접두사별로 갈라지는 것이 자연스럽습니다.
| 접두사 | 요구 | 처방 |
|---|---|---|
originals/ |
영구 보관, 수 시간 내 검색 허용 | 일정 기간 후 Glacier Deep Archive로 전환. 만료 없음 |
derived/ |
접근 패턴 예측 불가 | Intelligent-Tiering으로 전환하고 자동 계층화에 맡긴다 |
logs/ |
1년 보관 후 삭제 | Standard-IA를 거쳐 Glacier로, 365일에 만료 |
| 버킷 전체 | 이전 버전 30일 보관, 미완료 업로드 정리 | 비현재 버전 만료 + 미완료 멀티파트 업로드 중단 규칙 |
클래스 선택을 제약하는 확정 수치
수명 주기 규칙의 일수는 마음대로 정할 수 없습니다. 클래스마다 최소 저장 기간이 있어서, 그 기간을 채우기 전에 옮기거나 지우면 남은 기간만큼 요금이 청구됩니다. 규칙을 설계하기 전에 아래 값을 먼저 확인합니다.
| 클래스 | 최소 저장 기간 | 최소 청구 크기 | 가용 영역 |
|---|---|---|---|
| S3 Standard | 없음 | 없음 | 3 이상 |
| S3 Standard-IA | 30일 | 128 KB | 3 이상 |
| S3 One Zone-IA | 30일 | 128 KB | 1 |
| S3 Glacier Instant Retrieval | 90일 | 128 KB | 3 이상 |
| S3 Glacier Flexible Retrieval | 90일 | 40 KB | 3 이상 |
| S3 Glacier Deep Archive | 180일 | 40 KB | 3 이상 |
| S3 Intelligent-Tiering | 없음 | 없음 | 3 이상 |
수명 주기 규칙 구성
{
"Rules": [
{
"ID": "originals-to-deep-archive",
"Status": "Enabled",
"Filter": { "Prefix": "originals/" },
"Transitions": [
{ "Days": 30, "StorageClass": "DEEP_ARCHIVE" }
]
},
{
"ID": "derived-to-intelligent-tiering",
"Status": "Enabled",
"Filter": {
"And": {
"Prefix": "derived/",
"ObjectSizeGreaterThan": 131072
}
},
"Transitions": [
{ "Days": 0, "StorageClass": "INTELLIGENT_TIERING" }
]
},
{
"ID": "logs-tiering-and-expiry",
"Status": "Enabled",
"Filter": { "Prefix": "logs/" },
"Transitions": [
{ "Days": 30, "StorageClass": "STANDARD_IA" },
{ "Days": 90, "StorageClass": "GLACIER" }
],
"Expiration": { "Days": 365 }
},
{
"ID": "cleanup-noncurrent-and-incomplete",
"Status": "Enabled",
"Filter": { "Prefix": "" },
"NoncurrentVersionExpiration": { "NoncurrentDays": 30 },
"Expiration": { "ExpiredObjectDeleteMarker": true },
"AbortIncompleteMultipartUpload": { "DaysAfterInitiation": 7 }
}
]
}
aws s3api put-bucket-lifecycle-configuration \
--bucket example-media \
--lifecycle-configuration file://lifecycle.json
aws s3api get-bucket-lifecycle-configuration \
--bucket example-media \
--query 'Rules[].[ID,Status,Filter.Prefix]' \
--output table
네 번째 규칙이 이 케이스의 핵심입니다.
NoncurrentVersionExpiration— 이전 버전을 30일 뒤 만료시킵니다. 제약 3(30일 복구)을 만족시키면서 그 이상은 쌓이지 않게 합니다.ExpiredObjectDeleteMarker— 뒤에 아무 버전도 남지 않은 삭제 마커를 정리합니다. 목록 조회 성능에도 도움이 됩니다.AbortIncompleteMultipartUpload— 시작된 지 7일이 지나도 완료되지 않은 멀티파트 업로드를 중단하고 파트를 정리합니다.
Intelligent-Tiering을 고르는 근거
S3 Intelligent-Tiering은 객체의 접근 여부를 모니터링해 자동으로 계층을 옮깁니다. 최소 저장 기간과 검색 요금이 없는 대신 객체당 모니터링·자동화 요금 항목이 생깁니다.
선택 기준은 명확합니다 — 접근 패턴을 알면 고정 클래스가 낫고, 모르면 Intelligent-Tiering이 낫습니다. 아카이브 티어를 켜면 90일 미접근 시 Archive Access, 180일 미접근 시 Deep Archive Access로 자동 이동합니다. 다만 아카이브 티어에 들어간 객체는 즉시 읽을 수 없으므로, 지연을 허용할 수 있을 때만 켭니다.
비용과 운영에 미치는 영향
| 처방 | 줄어드는 항목 | 새로 생기거나 늘어나는 항목 |
|---|---|---|
| 아카이브 클래스로 전환 | GB당 저장 요금 | 전환 요청 요금, 나중에 꺼낼 때의 검색 요금 |
| Intelligent-Tiering | 안 읽히는 객체의 저장 요금 | 객체당 모니터링·자동화 요금 |
| 비현재 버전 만료 | 이전 버전이 차지하던 저장 요금 | 없음 (복구 가능 기간이 짧아지는 것이 대가) |
| 미완료 업로드 정리 | 보이지 않던 저장 요금 | 없음 |
| 로그 만료 | 저장 요금이 상한에 고정된다 | 없음 (보관 기간을 규정과 맞춰야 한다) |
운영 측면에서는 사람이 하던 삭제 배치가 사라집니다. 수명 주기 규칙은 S3가 실행하므로 실패한 배치를 재실행할 일이 없고, 규칙이 곧 보관 정책의 문서 역할을 합니다.
설계 체크리스트
진단할 때
설계할 때
관련 시험 포인트
| 문제문의 신호 | 고르는 것 | 소거하는 것 |
|---|---|---|
| 재생성할 수 있는 2차 사본이다 | S3 One Zone-IA | Standard-IA(더 비싸다), Glacier(검색 지연) |
| 규정상 7년 보관, 거의 꺼내지 않는다 | S3 Glacier Deep Archive | Standard-IA |
| 아카이브지만 즉시 읽어야 한다 | S3 Glacier Instant Retrieval | Flexible Retrieval, Deep Archive |
| 비용이 계속 늘어나는데 원인을 모르겠다 | 미완료 멀티파트 업로드와 이전 버전을 먼저 확인 | 클래스 전환만으로 해결된다고 보는 선택지 |
| 운영 부담 없이 자동으로 최적화 | Intelligent-Tiering 또는 수명 주기 규칙 | 주기적으로 분석해 수동 전환하는 안 |
| 삭제했는데 용량이 줄지 않는다 | 비현재 버전 만료 규칙 | 버전 관리를 끄는 안(이미 쌓인 버전은 남는다) |
이어서 볼 곳
- 8장 · S3와 오브젝트 스토리지 스토리지 클래스 전체, 수명 주기, 버전 관리와 복제, 암호화 4종을 정면으로 다룹니다.
- 18장 · 비용 최적화 · 마이그레이션 · 재해 복구 비용 도구와 절감 레버 전체 지도. 스토리지 밖의 비용 항목까지 함께 봅니다.
- 케이스 6 · 데이터 전송 요금이 예산을 넘겼다 저장이 아니라 이동에서 새는 비용. 같은 버킷이 원인이 되는 다른 경로입니다.
- 케이스 10 · 규정 준수 감사에 대응하라 보관 기간을 비용이 아니라 규정 관점에서 고정해야 할 때의 설계입니다.
- 실습 3 · S3 정적 사이트 + CloudFront + OAC 버킷을 비공개로 유지한 채 배포하는 구성을 직접 만들어 봅니다.
- 비용 최적화 아키텍처 설계 (20%) 과제 진술 4개와 비용 한정어가 가리키는 선택지를 정리했습니다.
공식 문서 출처
- Amazon S3 사용 설명서 — 스토리지 클래스 사용 — 클래스별 최소 저장 기간, 최소 청구 크기, 가용 영역 수 비교표
- Amazon S3 사용 설명서 — 객체 수명 주기 관리 — 전환 작업과 만료 작업의 구분
- Amazon S3 사용 설명서 — 수명 주기 전환 시 일반 고려 사항 — 30일 최소 저장 조건과 128 KB 미만 객체가 전환되지 않는다는 제약
- Amazon S3 사용 설명서 — 수명 주기 구성 예제 — 접두사·크기 필터와 비현재 버전 규칙의 작성 형태
- Amazon S3 API 레퍼런스 — PutBucketLifecycleConfiguration
—
NoncurrentVersionExpiration,ExpiredObjectDeleteMarker,AbortIncompleteMultipartUpload,ObjectSizeGreaterThan요소 - Amazon S3 사용 설명서 — 멀티파트 업로드 개요 — 완료되지 않은 업로드의 파트가 저장 요금을 발생시킨다는 서술
- Amazon S3 사용 설명서 — 수명 주기 구성으로 미완료 멀티파트 업로드 중단 — 규칙으로 자동 정리하는 방법
- Amazon S3 사용 설명서 — 버전 관리 — 삭제 요청이 삭제 마커를 만들고 이전 버전이 남는다는 동작
- Amazon S3 사용 설명서 — S3 Intelligent-Tiering 개요 — 자동 계층화와 아카이브 액세스 티어의 이동 조건(90일 · 180일)