객체 스토리지 (Object Storage)
레퍼런스
| 블록, 파일, 객체 — 스토리지 3종류를 제대로 이해하기 | https://infinitecode.tistory.com/139 |
| MinIO - "온프레미스 S3" | https://infinitecode.tistory.com/141 |
객체 스토리지
HTTP API 기반으로 구성된 스토리지 시스템. 파일시스템과 달리 계층 구조 없이 Key-Value 형태로 데이터를 관리한다.
구조
애플리케이션
↓ HTTP REST
API Server
↓
Metadata Store (Key → 물리위치)
↓
Data Store (실제 바이트)
↓
블록 스토리지 (OS 파일시스템)
HTTP 인터페이스
HTTP Method → 객체 스토리지 동작
GET → 객체 조회 (다운로드)
PUT/POST → 객체 저장 (업로드)
DELETE → 객체 삭제
HEAD → 메타데이터 조회 (데이터 전송 없음)
객체 스토리지 고유 특성 (Single Node)
1. Flat Namespace
파일시스템처럼 폴더/파일 구조가 아닌 Key만으로 데이터를 관리한다.
파일시스템: /images/2026/photo.jpg
→ images 디렉토리 존재
→ 2026 디렉토리 존재
→ photo.jpg 파일 존재
→ 각 디렉토리가 실제 inode를 가짐
객체 스토리지: images/2026/photo.jpg
→ 전체가 하나의 Key (문자열)
→ 디렉토리 없음
→ inode 없음
Key값의 슬래시(/)는 경로처럼 보이게 하는 논리적 구분자일 뿐이다 (Logical Hierarchy).
실제 영향
# 파일시스템
ls /images/2026/ → 디렉토리 조회 가능
# 객체 스토리지
"images/2026/" 로 시작하는 Key 목록 조회
→ 디렉토리처럼 보이지만
→ 실제론 Key 문자열 prefix 필터링
→ 디렉토리가 존재하는 게 아님
2. Immutable
객체는 수정이 없다. 수정처럼 보이는 것도 실제론 새 Object 생성이다.
수정 요청 → 새 Object 저장 → Metadata Key가 새 위치 가리킴
→ 구 Object는 GC가 나중에 정리
파일시스템은 inode가 가리키는 특정 블록만 변경하지만, 객체 스토리지는 객체를 새로 생성하고 Metadata Key가 새로운 위치를 가리키도록 변경한다.
PUT photo.jpg (1차) → Object: abc123 저장
PUT photo.jpg (2차) → Object: def456 저장
Metadata: photo.jpg → def456
abc123 → GC 대기
GET photo.jpg → def456 반환
Versioning
Versioning OFF (기본)
PUT photo.jpg (v1) → abc123
PUT photo.jpg (v2) → def456 ← abc123 GC 대기
GET photo.jpg → def456 (최신)
Versioning ON
PUT photo.jpg (v1) → abc123 ← 보존
PUT photo.jpg (v2) → def456 ← 보존
GET photo.jpg → def456 (최신)
GET photo.jpg?v=abc123 → abc123 (과거)
이점
- 감사 추적 (Audit Trail): 언제 무엇이 바뀌었는지 추적 가능
- 백업/복구 단순화: 구 버전이 항상 존재 (Versioning ON 시)
- 인터페이스 단순화: 수정 API 없으니 구현이 단순
트레이드오프
1MB 파일에서 1Byte만 변경해도 1MB 전체를 새로 저장해야 한다. → 스토리지 사용량 증가, GC 부하, Versioning ON 시 구버전 누적
수정이 빈번한 데이터에는 객체 스토리지가 부적합하다.
| 적합한 경우 | 부적합한 경우 |
| 이미지, 영상 | DB 데이터 |
| 백업, 아티팩트 | 실시간 로그 append |
| 정적 파일 | 자주 수정되는 문서 |
3. HTTP REST 기반
객체 스토리지는 HTTP로 인터페이스가 구성되어 있어 인터넷만 되면 어디서든 접근 가능하다.
파일시스템과의 차이
파일시스템 접근
→ OS 시스템콜 (open, read, write)
→ 마운트 필요
→ 같은 서버 or 네트워크 파일시스템
객체 스토리지 접근
→ HTTP 요청
→ 마운트 없음
→ 인터넷만 되면 어디서든 접근
HTTP 기반의 이점
- 언어 무관: HTTP가 되는 모든 언어에서 사용 가능
- 방화벽 친화적: 80/443 포트만 열면 됨
- Presigned URL: 서명된 임시 URL을 발급해 인증 없이 특정 Object 접근 허용
# Presigned URL 활용 예시
→ S3에 저장된 파일을 외부에 임시 공개할 때
→ 클라이언트가 서버를 거치지 않고 직접 업로드할 때
→ 파일시스템에서는 불가능한 개념
4. Metadata 분리
파일시스템에서 메타데이터는 inode에 저장되어 데이터와 같은 서버에서 관리된다.
객체 스토리지는 Metadata Store가 별도로 존재하며 Data Store와 분리되어 있다.
파일시스템
┌──────────────────────────┐
│ inode │
│ - 파일 크기 │
│ - 권한 │
│ - 생성일 │
│ - 블록 위치 │ ← 데이터와 같은 서버
└──────────────────────────┘
객체 스토리지
┌─────────────────────┐ ┌─────────────────────┐
│ Metadata Store │ │ Data Store │
│ - Key │ │ - 실제 바이트 │
│ - 크기 │ │ │
│ - 생성일 │ │ │
│ - 커스텀 태그 │ │ │
│ - 물리 위치 포인터 ─┼────┼→ 실제 데이터 │
└─────────────────────┘ └─────────────────────┘
파일시스템은 정해진 속성만 저장되는 반면, 객체 스토리지는 커스텀 메타데이터를 자유롭게 추가할 수 있다.
파일시스템: 정해진 속성만 (크기, 권한, 날짜)
객체 스토리지: 자유롭게 추가 가능
x-amz-meta-author: ryohei
x-amz-meta-project: almhub
x-amz-meta-version: 1.0.3
HEAD 메서드 활용
커스텀 메타데이터를 활용하면 실제 데이터를 전송하지 않고 필요한 정보만 조회할 수 있어 성능 이점을 얻을 수 있다.
HEAD /bucket/photo.jpg
→ 데이터 전송 없이 메타데이터만 반환
→ 파일 존재 여부 확인
→ 커스텀 태그 조회
→ Content-Type, 크기 확인
정리
| 특성 | 파일시스템 | 객체 스토리지 |
| 구조 | 계층형 (디렉토리/파일) | Flat (Key-Value) |
| 수정 | 블록 단위 수정 가능 | 새 Object 생성 |
| 접근 | 시스템콜 / 마운트 | HTTP REST |
| 메타데이터 | inode (고정 속성) | 별도 Store (커스텀 가능) |
| 확장성 | 단일 서버 전제 | 분산 환경 전제 |
분산 환경에서의 객체 스토리지
아래 내용은 멀티 노드(분산) 환경 기준이다. 싱글 노드(로컬 Docker 등)에서는 해당되지 않는다.
분산 환경 데이터 저장 구조 모식도
분산 저장 구조 자체는 객체 스토리지만의 특성이 아닌 공통 영역.
Client
│ PUT /bucket/photo.jpg (100MB)
▼
API Server
│ 1. 인증/권한 확인
│ 2. Consistent Hashing → 저장 노드 결정
│ 3. 데이터 → chunk 분할
▼
├─→ Node A: chunk 1, 2 (데이터)
├─→ Node B: chunk 3, 4 (데이터)
├─→ Node C: chunk 5, 6 (데이터)
├─→ Node D: parity 1 (패리티)
└─→ Node E: parity 2 (패리티)
▼
Metadata Store
│ Key: photo.jpg
│ → chunk 위치, 노드 정보, 크기, 태그 기록
▼
Client ← 200 OK
// 인증 → 라우팅 → 데이터 분산 저장 → 메타데이터 기록
분산 구조를 위해 채택한 개념들
객체 스토리지가 자체적으로 만든 개념이 아닌, 분산 시스템에서 가져다 쓰는 것들이다.
분산 시스템 일반 개념
├── Consistent Hashing ← 어느 노드에 저장할지
├── Erasure Coding ← 데이터 내구성
├── CAP Theorem ← 일관성 모델
└── Eventual Consistency ← 일관성 모델
1. Consistent Hashing
Key를 해시하여 저장할 노드를 결정한다.
hash("images/photo.jpg") = 38291
↓
해시 공간에서 38291이 속한 범위의 노드 결정
↓
Node C (192.168.1.3) 에 저장
노드 추가/제거 시 전체 데이터를 재분배하지 않고, 해당 범위의 데이터만 이동한다.
Before: Node A(0~21845), Node B(21846~43690), Node C(43691~65535)
Node D 추가 (43691~54613 담당)
After
Node A: 0~21845 ← 그대로
Node B: 21846~43690 ← 그대로
Node C: 54614~65535 ← 일부만 줄어듦
Node D: 43691~54613 ← Node C에서 이 범위만 이동
Consistent Hashing 링 구조
해시 공간: 0 ~ 65535 (예시)
0
/ \
Node A Node D
(0~16383) (49152~65535)
| |
Node B Node C
(16384~32767)(32768~49151)
2. Erasure Coding
데이터를 N개 chunk + M개 패리티로 분산 저장한다. M개 노드가 죽어도 복원 가능하다.
원본 데이터 → 6개 chunk + 3개 패리티 = 9개 노드에 분산
→ 3개 노드 장애 발생해도 복원 가능 // 패리티 개수가 곧 허용 장애 노드 수
XOR 기반의 RAID-5와 달리, Erasure Coding은 갈루아 필드(GF) 위의 행렬 연산을 사용한다.
임의 m개 노드가 손실되어도 수학적으로 복구가 보장된다는 점이 핵심 차이다.
RAID-5는 EC의 특수케이스(m=1, XOR 한정)로 볼 수 있다.
이 밖에도 구현체별로 분산 알고리즘은 다르게 구성될 수 있다.
3. CAP Theorem
분산 시스템은 아래 3가지를 동시에 만족할 수 없다.
C (Consistency) - 모든 노드가 항상 같은 데이터
A (Availability) - 항상 응답 가능
P (Partition Tolerance) - 네트워크 분리돼도 동작
네트워크 장애(P)는 현실에서 반드시 발생하므로 P는 포기 불가. 결국 C와 A 중 하나를 선택해야 한다.
객체 스토리지는 AP (가용성 우선) 를 선택한다.
4. Eventual Consistency
지금 당장의 불일치를 허용하고, 시간이 지나면 모든 노드가 동기화된다.
PUT photo.jpg 직후 GET photo.jpg
→ 구버전 반환될 수 있음 (수십ms ~ 수초)
→ 이후 모든 노드 동기화 완료
→ 이후 GET → 항상 최신 버전 반환
5. Immutable과 분산 환경
Immutable은 분산 환경에서 동시성 문제를 구조적으로 단순화한다.
파일 수정 방식 (파일시스템)
→ 모든 노드에 동시에 같은 블록 업데이트 필요
→ 특정 노드 장애 시 데이터 불일치
→ 분산 락, 트랜잭션, 롤백 필요 → 복잡도 폭발
새 Object 생성 방식 (객체 스토리지)
→ 각자 새 Object 생성
→ 락 필요없음, 충돌 없음
→ 노드 간 불일치는 Write Quorum + Eventual Consistency로 처리
Write Quorum
N개 노드 중 W개 이상 저장 성공 → 클라이언트에게 성공 응답
나머지 노드는 이후 Eventual Consistency로 동기화
불변성 자체가 노드 간 불일치를 완전히 해결하지는 않는다.
불일치 해결은 Write Quorum + Eventual Consistency가 담당하고, 불변성은 그 과정을 단순하게 만드는 역할이다.
참고
객체 스토리지의 공통적인 부분에 대해 정리를 했고,
이를 구현하는 구현체 별로 Metadata Store, 분산 알고리즘, 데이터 복제는 다를 수 있습니다.
※해당 글에서는 오픈소스인 Minio를 기준으로 정리
'CS > DataBase' 카테고리의 다른 글
| MinIO - "온프레미스 S3" (0) | 2026.05.21 |
|---|---|
| 블록, 파일, 객체 — 스토리지 3종류를 제대로 이해하기 (1) | 2026.05.05 |
| [TIL] RDBMS (1) | 2024.10.10 |
| [MySQL] 인덱스(INDEX) (1) | 2023.12.29 |
| [MySQL] View (0) | 2022.10.26 |
