오브젝트 스토리지 운영: S3 라이프사이클, 멀티파트, 성능 패턴
오브젝트 스토리지는 파일시스템이 아니라 운영 계약이다
S3 같은 오브젝트 스토리지는 POSIX 파일시스템처럼 열고, 조금 고치고, 닫는 저장소가 아니다. 기본 단위는 object이고, object는 key, metadata, storage class, version, tag, encryption 상태 같은 운영 속성과 함께 관리된다. 데이터 플랫폼에서는 이 차이를 제대로 이해해야 비용과 성능 사고를 줄일 수 있다.
가장 자주 생기는 문제는 세 가지다.
- 로그·이미지·Parquet 파일이 계속 쌓이지만 만료 정책이 없어 비용이 누적된다.
- 큰 파일 업로드가 단일 요청에 묶여 실패하면 처음부터 다시 보낸다.
- prefix, 병렬성, retry, KMS quota를 고려하지 않고 S3를 하나의 디스크처럼 사용한다.
이 장에서는 S3를 기준으로 라이프사이클, 멀티파트 업로드, 성능 패턴을 운영자 관점에서 정리한다. 다른 클라우드의 object storage도 이름은 다르지만 대부분 같은 판단 구조를 갖는다.
라이프사이클: 비용 정책을 코드처럼 다루기
S3 Lifecycle은 특정 object 집합에 대해 자동으로 두 가지 일을 한다.
- Transition: 더 낮은 비용의 storage class로 이동
- Expiration: 보존 기간이 지난 object 삭제
중요한 점은 라이프사이클이 단순 정리 스크립트가 아니라 bucket에 걸린 데이터 보존 정책이라는 것이다. 한 번 켜면 기존 object에도 적용될 수 있다. 예를 들어 “생성 후 30일이 지난 object 삭제” 규칙을 오늘 추가하면, 이미 30일이 넘은 object도 삭제 대상이 된다. 운영자는 규칙을 배포하기 전에 prefix, tag, object size, versioning 상태를 반드시 검토해야 한다.
Transition 판단: 싸지는 것이 항상 좋은 것은 아니다
Storage class 전환은 “GB당 저장 비용”만 보면 쉬워 보인다. 하지만 실제 비용은 다음 요소가 함께 결정한다.
| 판단 항목 | 운영 질문 |
|---|---|
| 접근 빈도 | 최근 30일/90일 동안 실제 GET이 있었는가? |
| 복구 시간 | Glacier 계열로 이동해도 복구 지연을 허용할 수 있는가? |
| 최소 보관 기간 | 조기 삭제 또는 조기 전환 비용이 생기지 않는가? |
| object 크기 | 작은 object를 대량 전환할 때 요청 비용이 절감액보다 커지지 않는가? |
| 규정 요구 | 감사·법적 보존 기간과 충돌하지 않는가? |
AWS 문서 기준으로 S3 Standard-IA와 One Zone-IA로 전환하려면 object가 최소 30일은 저장되어 있어야 한다. 또한 2024년 9월 이후 새 lifecycle 동작에서는 기본적으로 128KB 미만 object가 어떤 storage class로도 transition되지 않는다. 작은 object는 storage 절감액보다 transition request 비용이나 metadata성 비용이 더 커질 수 있기 때문이다.
따라서 데이터 플랫폼에서는 보통 다음처럼 구간을 나눈다.
- 0~30일: 재처리, backfill, 품질 검증 때문에 Standard 유지
- 30~90일: 접근은 드물지만 장애 분석이나 재집계에 필요하면 Standard-IA 또는 Intelligent-Tiering 검토
- 90일 이후: 법적 보존·감사·장기 재현 목적이면 Glacier 계열 검토
- 만료 시점: source system 재수집 가능성, 감사 요구, downstream 재처리 가능성을 확인한 뒤 삭제
Expiration은 삭제 자동화가 아니라 복구 가능성의 포기다
Expiration rule은 비용을 줄이는 데 강력하지만, 운영 사고도 강력하게 만든다. 특히 versioning이 켜진 bucket에서는 현재 버전 삭제와 noncurrent version 삭제의 의미가 다르다. 일반적인 “오래된 파일 삭제” 정책을 versioning bucket에 그대로 적용하면 delete marker만 생기고 실제 과금 대상인 noncurrent version은 남을 수 있다. 반대로 noncurrent version expiration을 과격하게 잡으면 실수 삭제 복구 기간이 사라진다.
운영 기준은 다음 순서가 안전하다.
- prefix와 tag로 대상 범위를 좁힌다.
- Storage Lens, Inventory, Athena 등으로 대상 object 수와 크기를 추정한다.
- dry-run에 해당하는 목록 조회를 먼저 남긴다.
- lifecycle rule을 적용한 뒤 전환·삭제 지표를 모니터링한다.
- versioned bucket은 current version과 noncurrent version 정책을 분리해서 검토한다.
멀티파트 업로드: 큰 object를 여러 실패 단위로 나누기
S3 Multipart Upload는 하나의 큰 object를 여러 part로 나누어 업로드한 뒤 마지막에 조립하는 방식이다. AWS는 100MB 이상 object에는 단일 PUT 대신 multipart upload를 사용하는 것을 권장한다.
멀티파트의 운영상 장점은 명확하다.
- part를 병렬 업로드하여 네트워크 대역폭을 더 잘 사용한다.
- 실패한 part만 재시도하므로 큰 object 전체를 다시 보내지 않는다.
- 최종 크기를 처음부터 몰라도 업로드를 시작할 수 있다.
- 불안정한 네트워크에서 pause/resume 형태의 구현이 가능하다.
멀티파트 업로드 절차
upload id 발급
metadata·checksum 결정
ETag 기록
ETag 기록
실패 시 이 part만 retry
part number + ETag 제출
object 조립
S3는 part number 오름차순으로 part를 연결한다. 각 part upload 응답의 ETag와 part number는 CompleteMultipartUpload 요청에 필요하므로 클라이언트는 반드시 기록해야 한다. 또 완료 후 object의 ETag는 단순히 전체 파일의 MD5라고 가정하면 안 된다. 멀티파트, 암호화, checksum 설정에 따라 의미가 달라질 수 있다.
미완료 multipart upload는 비용 누수다
멀티파트를 시작하고 part를 하나 이상 올린 뒤 complete도 abort도 하지 않으면, 업로드된 part는 저장 비용을 발생시킨다. 이 part는 정상 object 목록에는 보이지 않아 운영자가 놓치기 쉽다. 그래서 S3 Lifecycle에는 AbortIncompleteMultipartUpload action이 있다. 예를 들어 7일이 지나도 완료되지 않은 multipart upload를 자동 abort하면, 관련 part가 삭제되고 비용 누수를 줄일 수 있다.
{
"Rules": [
{
"ID": "abort-incomplete-multipart-after-7-days",
"Status": "Enabled",
"Filter": { "Prefix": "" },
"AbortIncompleteMultipartUpload": {
"DaysAfterInitiation": 7
}
}
]
}이 action은 완료된 object를 삭제하지 않는다. 미완료 multipart upload에만 적용된다. 따라서 대용량 업로드를 쓰는 bucket에는 거의 기본 안전장치로 보는 편이 좋다.
성능 패턴: prefix, 병렬성, retry, locality
S3는 단일 디스크가 아니라 대규모 분산 시스템이다. 성능 튜닝도 “디스크 큐 길이”가 아니라 “요청 분산과 병렬성” 관점으로 접근해야 한다.
1. prefix별 요청률과 점진적 확장
AWS 문서 기준으로 S3는 prefix당 최소 초당 3,500 PUT/COPY/POST/DELETE 또는 5,500 GET/HEAD 요청을 지원한다. bucket 안 prefix 수에는 제한이 없으므로 여러 prefix로 읽기·쓰기를 병렬화하면 처리량을 확장할 수 있다. 다만 새로운 높은 요청률에 맞춰 S3 내부가 scale-out되는 과정은 즉시 완료되지 않을 수 있고, 이때 일시적인 503 Slow Down이 보일 수 있다.
운영자는 다음을 구분해서 봐야 한다.
- 일시적 503: 새 트래픽 패턴으로 ramp-up 중일 수 있음. SDK retry와 backoff가 중요하다.
- 지속적 503: 특정 prefix, hot key, KMS quota, 클라이언트 병목, 네트워크 병목을 의심한다.
- 낮은 throughput: S3보다 클라이언트 instance type, NIC, CPU, TLS, DNS, SDK connection pool이 병목일 수 있다.
2. 많은 connection으로 수평 확장
고처리량 업로드·다운로드는 단일 HTTP connection에 기대지 않는다. 여러 connection에서 병렬 GET/PUT을 발행해 aggregate bandwidth를 만든다. 대용량 파일 업로드는 multipart upload, 대용량 파일 다운로드는 byte-range GET을 활용할 수 있다. 특히 multipart로 올린 object는 동일한 part 크기나 part boundary에 맞춰 range GET을 하면 재시도와 병렬 처리에 유리하다.
대용량 object 다운로드 예시
나쁜 패턴:
1개 worker가 500GB object 전체 GET
→ 중간 실패 시 긴 재시도, 단일 connection 병목
좋은 패턴:
object를 range로 나누어 16~64개 worker가 병렬 GET
→ 느린 range만 재시도, aggregate throughput 증가3. retry는 장애 은폐가 아니라 분산 시스템 프로토콜이다
S3는 SDK 수준에서 retry와 exponential backoff를 제공한다. latency-sensitive workload에서는 timeout과 retry 정책을 명시적으로 조정해야 한다. AWS 문서는 큰 요청은 느린 하위 비율을 추적해 재시도하고, 작은 요청은 예를 들어 2초 후 1회, 추가 4초 후 2회처럼 빠른 재시도를 고려하라고 설명한다.
하지만 retry는 무제한으로 늘리면 안 된다. retry storm은 downstream 장애를 키울 수 있다. 운영 기준은 다음과 같다.
- timeout은 workload의 SLO에 맞춘다.
- retry 횟수와 backoff 상한을 정한다.
503 Slow Down,5xx, network timeout을 별도 지표로 본다.- batch job은 실패 part 또는 실패 partition만 재처리한다.
- KMS 암호화를 쓰면 S3뿐 아니라 KMS request quota도 함께 본다.
4. compute와 bucket region을 맞춘다
S3와 EC2/Spark/Flink worker가 서로 다른 region에 있으면 latency와 egress cost가 동시에 증가한다. 데이터 레이크 작업은 같은 region에 compute를 두는 것이 기본이다. 전 세계 사용자가 다운로드하는 정적 콘텐츠라면 CloudFront cache를 앞에 두고, 먼 거리 대용량 업로드가 많다면 Transfer Acceleration을 검토한다. 운영 DB 백업이나 데이터 파이프라인 랜딩존에는 보통 “같은 region + private endpoint/VPC endpoint + 제한된 IAM” 조합이 더 중요하다.
데이터 플랫폼에서의 설계 패턴
Raw zone과 processed zone은 lifecycle이 다르다
데이터 레이크 bucket을 하나로 보더라도 prefix별 데이터 성격은 다르다.
| Zone | 예시 | 운영 정책 |
|---|---|---|
| raw | source dump, CDC landing, original log | 재처리 근거이므로 보존 기간 길게, 삭제 신중 |
| staging | 임시 변환 결과, failed batch output | 짧은 expiration, multipart abort 필수 |
| processed | Parquet/ORC, curated table files | table format의 snapshot/vacuum 정책과 충돌 금지 |
| audit | manifest, checksum, run ledger | 작지만 중요함. transition보다 무결성과 조회성 우선 |
특히 Iceberg, Delta Lake, Hudi 같은 table format을 쓰는 prefix에 lifecycle expiration을 직접 걸 때는 조심해야 한다. table format은 자체 metadata와 snapshot retention 정책을 갖는다. S3 lifecycle이 임의로 data file이나 metadata file을 먼저 삭제하면 table의 time travel, rollback, query가 깨질 수 있다. table format이 관리하는 경로는 해당 엔진의 expire_snapshots, vacuum, cleaner, compaction 절차를 우선한다.
작은 파일 문제와 object storage 비용
S3는 많은 작은 object도 저장할 수 있지만, 데이터 처리 비용은 크게 나빠질 수 있다.
- list 요청이 많아진다.
- query engine이 file open을 반복한다.
- lifecycle transition request 비용이 object 수에 비례한다.
- metadata 관리 비용과 catalog 부하가 증가한다.
따라서 데이터 플랫폼에서는 “압축률”만 보지 말고 file size target을 잡아야 한다. Spark나 Flink sink는 너무 작은 파일을 계속 만들지 않도록 compaction, checkpoint interval, partition 수, writer parallelism을 조정한다. object storage 운영은 스토리지 정책만으로 끝나지 않고, upstream writer의 파일 생성 방식까지 포함한다.
운영 체크리스트
Bucket 생성·정책 단계
- bucket owner, data owner, 비용 owner를 명확히 둔다.
- prefix naming convention을 정한다. 예:
raw/source/table/dt=YYYY-MM-DD/. - public access block, encryption, access log, audit log를 기본값으로 둔다.
- lifecycle rule은 prefix/tag 단위로 작게 시작한다.
- versioning과 object lock 사용 여부를 복구·규정 요구와 함께 결정한다.
대용량 업로드 단계
- 100MB 이상 object는 multipart upload를 기본으로 검토한다.
- part size, concurrency, retry 정책을 명시한다.
- part number와 ETag 기록을 안전하게 보관한다.
- 실패 job은 complete 또는 abort를 확실히 호출한다.
- bucket lifecycle에 incomplete multipart abort 규칙을 둔다.
성능 운영 단계
- 5xx/503, first byte latency, total request latency, throughput을 본다.
- hot prefix 또는 hot key가 있는지 Storage Lens, access log, application metric으로 확인한다.
- worker 수, connection pool, SDK 버전, DNS, TLS CPU 사용률을 함께 본다.
- KMS 암호화 사용 시 KMS throttling과 quota를 별도 확인한다.
- 같은 region 접근을 기본으로 하고, cross-region 접근은 비용과 latency를 명시적으로 승인한다.
마무리
오브젝트 스토리지 운영의 핵심은 “싸고 무한한 저장소”라는 인상을 버리는 것이다. S3는 매우 높은 내구성과 확장성을 제공하지만, 비용·성능·복구 가능성은 object 단위 정책과 클라이언트 접근 패턴이 결정한다.
운영자는 다음 세 가지 질문을 반복해야 한다.
- 이 object는 언제까지, 어떤 storage class에 있어야 하는가?
- 큰 object 업로드·다운로드의 실패 단위는 충분히 작게 나뉘어 있는가?
- 요청률과 retry는 S3의 분산 시스템 특성에 맞게 설계되었는가?
이 질문에 답할 수 있으면 object storage는 단순 백업 저장소를 넘어 데이터 플랫폼의 안정적인 landing zone, archive layer, serving layer가 된다.
References
- AWS Documentation — Managing the lifecycle of objects
- AWS Documentation — Transitioning objects using Amazon S3 Lifecycle
- AWS Documentation — Uploading and copying objects using multipart upload in Amazon S3
- AWS Documentation — Configuring a bucket lifecycle configuration to delete incomplete multipart uploads
- AWS Documentation — Best practices design patterns: optimizing Amazon S3 performance
- AWS Documentation — Performance guidelines for Amazon S3
- AWS Documentation — Performance design patterns for Amazon S3
- AWS Documentation — Understanding and managing Amazon S3 storage classes