실제 블록스토리지 필요 workload (소수)
├── Hive Metastore / Iceberg Catalog DB (PostgreSQL/MySQL)
├── Airflow / Argo metadata DB
├── Kafka (on-K8s 운영 시)
└── Prometheus TSDB, Loki 청크
→ 나머지(데이터 레이크 본체)는 Object Storage로 충당
→ 블록스토리지 범위가 생각보다 작다는 것부터 확인
Node A Node B Node C
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ TopoLVM Agent │ │ TopoLVM Agent │ │ TopoLVM Agent │
│ ┌───────────┐ │ │ ┌───────────┐ │ │ ┌───────────┐ │
│ │ VG: data │ │ │ │ VG: data │ │ │ │ VG: data │ │
│ │ /dev/sdb │ │ │ │ /dev/sdb │ │ │ │ /dev/sdb │ │
│ │ /dev/sdc │ │ │ └───────────┘ │ │ └───────────┘ │
│ └───────────┘ │ └─────────────────┘ └─────────────────┘
└─────────────────┘
│
▼
TopoLVM Controller (scheduler extender)
→ "이 PVC는 500GB 필요 → Node A만 가능" 자동 판단
→ Pod를 해당 노드에 강제 배치 (topology-aware scheduling)
# 1. 각 노드에서 LVM VG 사전 생성 (수작업, 1회)
pvcreate /dev/sdb /dev/sdc
vgcreate data-vg /dev/sdb /dev/sdc
# 2. TopoLVM Helm 설치
helm repo add topolvm https://topolvm.github.io/topolvm
helm install topolvm topolvm/topolvm \
--namespace topolvm-system \
--set lvmd.deviceClasses[0].name=ssd \
--set lvmd.deviceClasses[0].volumeGroup=data-vg \
--set lvmd.deviceClasses[0].default=true
# 3. StorageClass 생성
kubectl apply -f - <<EOF
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: topolvm-ssd
provisioner: topolvm.io
parameters:
csi.storage.k8s.io/fstype: xfs
topolvm.io/device-class: ssd
volumeBindingMode: WaitForFirstConsumer # ← 핵심: pod 배치 후 볼륨 생성
reclaimPolicy: Delete
allowVolumeExpansion: true
EOF
✅ 장점
├── 네이티브 LVM 위에서 동작 → 커널 수준 성능 (overhead 거의 없음)
├── thin provisioning 지원 → 스토리지 오버커밋 가능
├── VolumeSnapshot (LVM snapshot 기반) 지원
├── 용량 확장(resize) 온라인 지원
├── 구조 단순: agent + controller만 존재, 장애 포인트 최소
└── CNCF 프로젝트, Cybozu(일본 대기업) 실운영 검증
❌ 단점
├── 노드 장애 = 데이터 손실 (복제 없음) ← 가장 큰 제약
├── Pod는 항상 해당 노드에 고정됨 (노드 죽으면 PVC도 접근 불가)
├── 노드 간 볼륨 이동 불가 (drain 시 stateful app 이동 불가)
└── VG 사전 생성 등 노드별 수작업 필요 (Ansible로 자동화 권장)
아키텍처:
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Node A │ │ Node B │ │ Node C │
│ │ │ │ │ │
│ Replica1 │◄──►│ Replica2 │◄──►│ Replica3 │
│ (주) │ │ (복제) │ │ (복제) │
└──────────┘ └──────────┘ └──────────┘
│
▼
iSCSI / NVMe-oF
│
▼
Frontend (볼륨 접근)
# Helm 설치
helm repo add longhorn https://charts.longhorn.io
helm install longhorn longhorn/longhorn \
--namespace longhorn-system \
--set defaultSettings.defaultReplicaCount=3 \
--set defaultSettings.storageReservedPercentageForDefaultDisk=20 \
--set defaultSettings.backupTarget=s3://my-backup-bucket/longhorn \
--set defaultSettings.backupTargetCredentialSecret=s3-secret
✅ 장점
├── UI 기반 운영 (웹 대시보드) → 직관적, 교육 비용 낮음
├── 노드 장애 시 자동 복구 (replica 재동기화)
├── 스냅샷 + S3 백업 내장 → Velero 없이도 백업 가능
├── 실시간 복제 현황 UI 확인 가능
└── CNCF incubating, 커뮤니티 활발
❌ 단점
├── 복제 트래픽이 클러스터 내부 네트워크 사용 → 네트워크 부하
├── 쓰기 레이턴시: replica count × 동기화 오버헤드
├── 대용량 볼륨(수 TB) 재동기화 시간이 김
└── CPU/메모리 오버헤드 Rook-Ceph보다 낮지만 TopoLVM보다 높음
아키텍처 (NVMe-oF 기반):
┌──────────────────────────────────────────┐
│ Mayastor Control Plane │
│ (io-engine DaemonSet on storage nodes) │
└──────────┬───────────────────────────────┘
│ NVMe-oF / TCP
┌──────▼──────┐ ┌─────────────┐
│ io-engine │◄──►│ io-engine │
│ Node A │ │ Node B │
│ /dev/nvme0 │ │ /dev/nvme0 │
└─────────────┘ └─────────────┘
helm repo add openebs https://openebs.github.io/openebs
helm install openebs openebs/openebs \
--namespace openebs \
--set engines.replicated.mayastor.enabled=true \
--set mayastor.io_engine.resources.limits.hugepages-2Mi=2Gi
# hugepage 필수 → 커널 파라미터 사전 설정 필요
✅ 장점
├── NVMe-oF 기반 → 현존 K8s 스토리지 중 최고 성능
├── 커널 바이패스(SPDK) → 레이턴시 100µs 이하 가능
├── 분산이면서도 로컬 NVMe에 근접한 처리량
└── CNCF graduated 예정, DataCore 지원
❌ 단점
├── hugepage 설정 필수 → 노드 커널 파라미터 사전 작업
├── NVMe 장치 전용 (SATA SSD만 있으면 이점 반감)
├── 운영 복잡도 Longhorn보다 높음
└── 디버깅 어려움 (SPDK 레벨 문제 시 난이도 높음)
| 항목 | TopoLVM (Local) | Longhorn (분산) | Mayastor (분산 고성능) |
|---|---|---|---|
| 아키텍처 | Local LVM | 분산 복제 (iSCSI) | 분산 복제 (NVMe-oF) |
| 쓰기 성능 | ★★★★★ | ★★★ | ★★★★★ |
| 읽기 성능 | ★★★★★ | ★★★★ | ★★★★★ |
| 레이턴시 | ~100µs | ~1ms+ | ~200µs |
| 노드 장애 내성 | ❌ 없음 | ✅ 자동복구 | ✅ 자동복구 |
| Pod 이동성 | ❌ 노드 고정 | ✅ 자유 | ✅ 자유 |
| 운영 복잡도 | 낮음 | 낮음~중간 | 중간~높음 |
| UI | ❌ | ✅ 웹 UI | ❌ (CLI/kubectl) |
| 백업 내장 | 스냅샷만 | ✅ S3 백업 | 스냅샷만 |
| 네트워크 부하 | 없음 | 복제 트래픽 | 복제 트래픽 |
| 필요 전제 | LVM 구성 | 없음 | hugepage + NVMe 권장 |
| 노드 최소 수 | 1 | 3 | 3 |
| 비용 | 무료 | 무료 | 무료 |
| 성숙도 | 높음 | 높음 | 중간 (빠르게 성장) |
┌─────────────────────────────────────────────────────────────┐
│ Workload 특성에 따른 StorageClass 분기 │
│ │
│ Metastore DB, Airflow DB ──► Longhorn (복제=3) │
│ (HA 필수, 용량 작음, 안정성 > 성능) │
│ │
│ Prometheus TSDB, Kafka ────► TopoLVM │
│ (쓰기 집중, 성능 중요, 데이터 재구성 가능) │
│ │
│ 데이터 레이크 본체 ──────────► Object Storage (S3/MinIO) │
│ (블록스토리지 사용 금지) │
└─────────────────────────────────────────────────────────────┘
┌─ 담당자가 적고 운영 단순성이 최우선이다
│ → Longhorn (UI + 내장백업으로 진입장벽 최저)
│
├─ DB 워크로드가 많고 노드 장애 대응이 중요하다
│ → Longhorn (replica=3 기본)
│
├─ NVMe 장치가 있고 고성능이 필수다
│ → Mayastor (단, 커널 파라미터 세팅 감수)
│
├─ Prometheus/Kafka처럼 성능 집중 + 데이터 재구성 가능하다
│ → TopoLVM (단, 노드 장애 = 데이터 유실 인지 필수)
│
└─ 현실적 추천:
TopoLVM(성능workload) + Longhorn(HA필요workload) 병행
→ 두 개 StorageClass 만들어두고 workload별 지정
가장 먼저 현재 PVC 전수조사(kubectl get pvc -A) 후 workload 유형 분류를 하고, 그에 맞게 StorageClass를 설계하는 순서를 권장합니다. 특정 workload(예: Kafka on K8s, Prometheus 장기보존 등)에 대해 더 구체적으로 파고들까요?
==
Local LVM (Kernel Path) Mayastor (SPDK/io_uring Path)
───────────────────── ─────────────────────────────
App App
│ │
▼ ▼
VFS (커널) VFS (커널)
│ │
▼ ▼
Block Layer io_uring (커널 바이패스에 가까운)
│ │
▼ ▼
LVM (dm-thin) io-engine (SPDK, userspace)
│ │
▼ ▼
디스크 NVMe 장치 (직접 접근)
→ 커널 스택 전체 통과 → 커널 컨텍스트 스위치 최소화
→ 오버헤드 낮지만 존재 → 오버헤드 극소
NVMe SSD 노드 기준
fio 테스트 (4K random, queue depth 32)
Local LVM ████████████████████░░░░░ ~180,000 IOPS
Mayastor ████████████████████████░ ~220,000 IOPS (복제 1개)
Mayastor ████████████████░░░░░░░░░ ~140,000 IOPS (복제 3개)
Raw NVMe █████████████████████████ ~250,000 IOPS (기준선)
Local LVM ████████████████████████░ ~240,000 IOPS
Mayastor ████████████████████████░ ~230,000 IOPS (복제 1개)
Mayastor ███████████████████████░░ ~210,000 IOPS (복제 3개)
Raw NVMe █████████████████████████ ~250,000 IOPS (기준선)
평균 P99
Raw NVMe 80µs 120µs
Local LVM 120µs 250µs ← 커널 LVM 오버헤드
Mayastor(R=1) 150µs 300µs ← 네트워크 홉 추가
Mayastor(R=3) 400µs 800µs ← 3중 동기화 대기
Read Write
Local LVM 3.2 GB/s 2.8 GB/s
Mayastor(R=1) 3.0 GB/s 2.6 GB/s
Mayastor(R=3) 3.0 GB/s 1.4 GB/s ← 3노드 동기 복제 병목
pgbench TPS (scale=100, clients=32)
Local LVM ████████████████████ 8,500 TPS
Mayastor(R=3) ████████████████░░░░ 6,800 TPS (-20%)
Mayastor(R=1) ████████████████████ 8,200 TPS (-3%)
→ fsync 빈번한 DB는 복제 동기화가 쓰기 레이턴시에 직결
→ R=3이면 체감 성능 차이 발생
→ DB 자체 HA(PG replication)를 쓴다면 Mayastor R=1도 충분
Producer throughput (MB/s)
Local LVM 1,200 MB/s ← 압도적
Mayastor(R=3) 650 MB/s (-46%)
→ append-only 순차쓰기 + fsync 조합에서 복제 오버헤드 가장 큼
→ Kafka는 Local LVM이 훨씬 유리
→ 사실 둘 다 쓰지 말 것
→ emptyDir (local NVMe) 사용 권장
→ shuffle 데이터는 복제 의미 없음
NVMe와 달리 SATA는 디바이스 자체가 병목
SATA SSD 기준 4K Random Write
Local LVM ~80,000 IOPS
Mayastor(R=1) ~75,000 IOPS (-6%) ← 차이 거의 없음
Mayastor(R=3) ~50,000 IOPS (-37%) ← 복제 오버헤드는 동일하게 있음
→ SATA 환경에서 Mayastor의 SPDK 이점이 희석됨
→ SATA라면 Local LVM이 더 가성비 좋음
┌─────────────────────────────────────────────────────┐
│ 성능만 보면 Local LVM > Mayastor(R=3) │
│ 가용성까지 보면 Mayastor(R=3) > Local LVM │
│ │
│ NVMe + 성능 최우선 → Local LVM │
│ NVMe + HA 필요 → Mayastor R=1~2 │
│ SATA + HA 필요 → Longhorn (Mayastor 이점 없음)│
│ SATA + 성능 최우선 → Local LVM │
└─────────────────────────────────────────────────────┘
| 워크로드 | 추천 | 이유 |
|---|---|---|
| Metastore DB | Mayastor R=2 또는 Local LVM + 외부백업 | HA vs 성능 트레이드오프 |
| Kafka | Local LVM | 순차쓰기 성능 차이 큼 |
| Prometheus | Local LVM | 재수집 가능, 성능 우선 |
| Airflow DB | Mayastor R=3 | 작은 용량, HA 중요 |
결론적으로 Data Lakehouse에서 블록스토리지가 필요한 DB류(Metastore, Airflow)는 용량이 크지 않으므로 Mayastor R=2 정도로 HA를 확보하고, Kafka/Prometheus처럼 성능 집중 + 재구성 가능한 워크로드는 Local LVM으로 분리하는 것이 최적입니다.
==
Mayastor의 존재 이유인 SPDK/io_uring 이점이
SATA SSD에서는 거의 사라짐
왜냐하면:
SATA SSD 자체 한계 (~550MB/s, ~100K IOPS)가
소프트웨어 스택 오버헤드보다 훨씬 큰 병목이기 때문
Raw SATA SSD ████████████████████ ~80,000 IOPS (기준)
Local LVM ███████████████████░ ~72,000 IOPS (-10%)
Mayastor(R=1) ██████████████████░░ ~68,000 IOPS (-15%)
Mayastor(R=2) █████████████░░░░░░░ ~52,000 IOPS (-35%)
Mayastor(R=3) ██████████░░░░░░░░░░ ~38,000 IOPS (-52%)
Longhorn(R=3) █████████░░░░░░░░░░░ ~35,000 IOPS (-56%)
Raw SATA SSD ████████████████████ ~80,000 IOPS
Local LVM ████████████████████ ~78,000 IOPS (-2%)
Mayastor(R=1) ███████████████████░ ~75,000 IOPS (-6%)
Mayastor(R=3) ██████████████████░░ ~70,000 IOPS (-12%)
→ 읽기는 복제 영향 거의 없음 (로컬 replica에서 읽기 가능)
평균 P99 P999
Raw SATA 200µs 400µs 800µs
Local LVM 250µs 500µs 1.2ms
Mayastor(R=1) 350µs 700µs 2ms
Mayastor(R=3) 900µs 2ms 5ms+
→ NVMe와 달리 베이스 레이턴시 자체가 높아서
Mayastor의 복제 추가 레이턴시가 상대적으로 더 크게 체감됨
Read Write
Raw SATA 540 MB/s 520 MB/s
Local LVM 520 MB/s 500 MB/s (SATA 한계에 수렴)
Mayastor(R=1) 500 MB/s 480 MB/s
Mayastor(R=3) 500 MB/s 250 MB/s ← 3중 동기화로 절반
NVMe 환경:
┌─────────────────────────────────────────┐
│ 디바이스 한계: 250,000 IOPS │
│ SPDK 절감 오버헤드: 30,000 IOPS │
│ → SPDK 효과가 의미있음 (12% 기여) │
└─────────────────────────────────────────┘
SATA 환경:
┌─────────────────────────────────────────┐
│ 디바이스 한계: 80,000 IOPS │
│ SPDK 절감 오버헤드: 5,000 IOPS │
│ → SPDK 효과 미미 (6% 기여) │
│ 복제 오버헤드: -30,000 IOPS (R=3) │
│ → 오히려 순손해 │
└─────────────────────────────────────────┘
| 워크로드 | 추천 | 이유 |
|---|---|---|
| Metastore DB | Local LVM + Velero 백업 | Mayastor R=3 쓰면 DB 성능 절반 |
| Airflow DB | Longhorn R=2 | 용량 작고 HA 필요, Mayastor 불필요 |
| Kafka | Local LVM | 순차쓰기 성능 최우선 |
| Prometheus | Local LVM | 재수집 가능, 성능 우선 |
| 공유 설정파일 | NFS or Longhorn | RWX 필요 시 |
┌─────────────────────────────────────────────────────┐
│ Mayastor는 SATA 환경에서 도입 가치 없음 │
│ 설치/운영 복잡도 대비 얻는 것이 없음 │
└─────────────────────────────────────────────────────┘
권장 조합:
성능 필요 workload (Kafka, Prometheus)
→ OpenEBS Local LVM
→ 장애 대비: Velero 스냅샷 + 외부 백업
HA 필요 workload (Metastore DB, Airflow DB)
→ Longhorn R=2
→ SATA에서 Mayastor보다 운영 단순하고 성능 차이 없음
→ 내장 S3 백업으로 Velero 없이도 관리 가능
Spark shuffle / 임시데이터
→ emptyDir (hostPath)
→ 블록스토리지 아예 사용 금지
SATA 환경이라면 Mayastor를 건너뛰고 OpenEBS Local LVM + Longhorn 조합이 가장 현실적입니다. Mayastor는 NVMe 전용이라고 봐도 무방합니다.