Storage Problem di Distributed Systems #
Storage di sistem terdistribusi bukan sekadar “simpan file di disk”. Ketika aplikasi berjalan di banyak node yang bisa gagal kapan saja, bisa di-restart, bisa dipindah ke node lain, muncul serangkaian masalah yang tidak ada di environment non-distributed. Memahami masalah-masalah ini adalah prasyarat untuk merancang solusi storage yang benar — dan untuk memutuskan kapan lebih baik menggunakan managed service daripada mengelola sendiri di Kubernetes.
Masalah 1: Pod Berpindah, Data Tidak #
Kubernetes bisa memindahkan Pod ke node lain kapan saja — saat rolling update, node maintenance, atau node failure. Ini menimbulkan masalah fundamental dengan storage yang terikat ke node tertentu.
Skenario dengan node-local storage:
Node A: postgres-0 berjalan
└── /data/postgres/ ← data tersimpan di disk Node A
Node A mengalami masalah → Pod di-evict → dijadwalkan ulang ke Node B
Node B: postgres-0 berjalan
└── /data/postgres/ ← direktori ini KOSONG di Node B
└── Data hilang!
Solusinya adalah storage yang independen dari node — cloud persistent disk (EBS, GCE PD), network storage (NFS, Ceph), atau distributed storage. Volume semacam ini bisa “di-attach” ke node mana saja saat Pod berpindah.
Dengan cloud persistent disk:
Node A: postgres-0 → EBS volume vol-abc123 (attached ke Node A)
Node A down → Pod pindah ke Node B
→ EBS volume di-detach dari Node A
→ EBS volume di-attach ke Node B
→ postgres-0 di Node B mount EBS volume yang sama
→ Data tetap ada dan konsisten
Masalah 2: Banyak Pod, Satu Storage #
Beberapa workload butuh banyak Pod yang membaca dan menulis ke storage yang sama — misalnya web server yang melayani file statis, atau aplikasi yang berbagi session storage berbasis file.
Masalah dengan block storage (EBS, GCE PD):
EBS volume hanya bisa di-attach ke SATU node dalam satu waktu (RWO)
Pod A (Node 1) ─── mount EBS vol-abc ✓
Pod B (Node 2) ─── mount EBS vol-abc ✗ GAGAL — sudah dipakai Pod A
Jika Pod B perlu akses volume yang sama, ada dua opsi:
Opsi 1: Pastikan Pod A dan Pod B selalu di node yang sama
→ Menggunakan Pod Affinity
→ Mengurangi ketersediaan (satu node down → semua Pod down)
Opsi 2: Gunakan network filesystem yang mendukung RWX
→ NFS, CephFS, Azure Files, Amazon EFS
→ Banyak node bisa mount bersamaan
→ Ada overhead performa dari network filesystem
Masalah 3: Konsistensi Data di Database Terdistribusi #
Menjalankan database dengan replication di Kubernetes menghadirkan tantangan konsistensi yang serius.
Database dengan primary-secondary replication:
postgres-0 (primary) ← semua write masuk ke sini
postgres-1 (secondary) ← replika dari primary, hanya read
postgres-2 (secondary) ← replika dari primary, hanya read
Skenario yang harus ditangani:
1. postgres-0 down → siapa yang jadi primary?
→ Butuh mekanisme leader election (Patroni, pg_auto_failover)
→ Selama election berlangsung: write tidak bisa dilakukan
2. postgres-1 tertinggal replikasinya (replication lag)
→ Read dari postgres-1 mungkin tidak mendapat data terbaru
→ Bisa menyebabkan inconsistency dari perspektif user
3. Network partition: postgres-0 tidak bisa berkomunikasi dengan postgres-1
→ Apakah postgres-0 terus menerima write?
→ Apakah postgres-1 mempromosikan dirinya jadi primary?
→ Split-brain: dua node sama-sama menganggap diri primary
Split-brain adalah skenario paling berbahaya: dua instance database secara bersamaan menerima write tanpa sinkronisasi. Hasilnya adalah data yang divergen dan sangat sulit di-merge.
Masalah 4: Volume Attachment Race Condition #
Ketika Pod berpindah dengan cepat (misalnya node failure diikuti rescheduling cepat), ada race condition dalam proses detach-attach volume:
Race condition pada volume attachment:
[10:00:00] Node A down
[10:00:00] Kubernetes mulai proses eviction Pod dari Node A
[10:00:15] Pod dijadwalkan ke Node B
[10:00:15] Kubernetes coba attach EBS volume ke Node B
Masalah:
→ EBS volume masih tercatat "attached" ke Node A (walaupun Node A sudah down)
→ Cloud provider butuh waktu untuk memverifikasi Node A benar-benar down
→ Sampai verifikasi selesai, volume tidak bisa di-attach ke Node B
Kubernetes menangani ini dengan:
→ Volume attachment timeout (default ~6 menit untuk beberapa provider)
→ Selama itu, Pod baru tidak bisa dimulai dan menunggu
Ini adalah salah satu alasan mengapa recovery database di Kubernetes bisa lebih lambat dari yang diharapkan — bukan karena Pod lambat dimulai, tapi karena volume lambat di-attach.
Masalah 5: Storage Performance di Multi-Tenant Cluster #
Di cluster yang digunakan bersama banyak tim (multi-tenant), workload satu tim bisa mempengaruhi performa storage tim lain — fenomena yang disebut noisy neighbor.
Noisy neighbor pada shared storage:
Team A: batch job yang menulis 500 MB/s ke NFS
Team B: database yang butuh latensi read < 5ms
Tanpa isolasi:
→ Batch job Team A menyebabkan NFS overload
→ Latensi read Team B naik dari 2ms ke 50ms
→ Database Team B mengalami timeout
Solusi yang umum digunakan:
→ StorageClass berbeda untuk workload berbeda
(storage premium untuk database, storage biasa untuk batch)
→ IOPS limit per volume (didukung beberapa cloud provider)
→ Pisahkan workload ke node pool yang berbeda dengan storage terpisah
Mengapa Ini Penting untuk Keputusan Arsitektur #
Masalah-masalah di atas bukan berarti tidak boleh menjalankan stateful workload di Kubernetes — tapi mereka menjelaskan mengapa ini lebih kompleks dari stateless workload dan membutuhkan perencanaan yang matang.
Decision framework untuk stateful workload di Kubernetes:
Apakah data ini kritikal dan tidak boleh hilang?
└─ Ya → Apakah tim punya keahlian mengelola database di Kubernetes?
└─ Tidak → Pertimbangkan managed database service (RDS, Cloud SQL)
└─ Ya → Gunakan StatefulSet dengan CSI driver yang tepat
Pastikan ada backup dan tested restore procedure
Apakah butuh shared storage (banyak Pod akses bersamaan)?
└─ Ya → Apakah RWX performance overhead acceptable?
└─ Ya → NFS, CephFS, atau cloud file storage (EFS, Azure Files)
└─ Tidak → Pertimbangkan object storage (S3) atau arsitektur ulang
Apakah ini storage sementara dalam satu Pod?
└─ Ya → emptyDir sudah cukup
Ringkasan #
- Pod berpindah, data tidak — storage yang terikat ke node hilang saat Pod pindah; gunakan network-attached storage atau cloud persistent disk yang bisa follow Pod.
- Block storage (RWO) untuk satu Pod, network filesystem (RWX) untuk banyak Pod — pilih access mode berdasarkan pola akses; RWX ada overhead performa.
- Split-brain adalah risiko terbesar database terdistribusi — butuh mekanisme leader election yang solid; ini salah satu alasan mengelola database di Kubernetes lebih kompleks dari sekedar membuat StatefulSet.
- Volume attachment race condition — saat node failure, ada periode ~6 menit sebelum volume bisa di-attach ke node baru; rancang availability target sesuai realita ini.
- Noisy neighbor di shared cluster — isolasi workload storage-intensive dengan StorageClass berbeda dan IOPS limit untuk mencegah satu workload mendegradasi yang lain.
- Pertimbangkan managed service untuk database kritikal — kompleksitas operasional database di Kubernetes nyata; managed service sering lebih pragmatis kecuali ada alasan spesifik.