Menentukan strategi skalabilitas basis data relasional (RDBMS) seperti PostgreSQL atau MySQL memerlukan pemahaman mendalam terkait batas fisik hardware dan karakteristik beban kerja (workload). Dua pendekatan utama yang sering dipertimbangkan adalah penambahan Read Replicas dan implementasi Database Sharding. Keduanya menyelesaikan masalah performa pada layer yang berbeda dengan konsekuensi biaya dan kompleksitas operasional yang terpaut jauh.
1. Batas Skalabilitas Read Replicas
Read Replicas bekerja dengan mereplikasi data dari satu node primer (Primary/Leader) ke satu atau lebih node sekunder (Replica/Follower) menggunakan mekanisme streaming replication (WAL di PostgreSQL atau binlog di MySQL). Pola ini efektif untuk workload yang didominasi pembacaan data (read-heavy), namun memiliki batas teknis mendasar:
- Single-Writer Bottleneck: Replikasi read tidak menyelesaikan limitasi throughput penulisan. Seluruh operasi
INSERT,UPDATE,DELETE, dan DDL tetap harus diproses oleh satu node primer. Jika kapasitas CPU atau storage write pada node primer jenuh, penambahan replika tidak memberikan mitigasi apa pun. - Replication Lag Asinkron: Replikasi bawaan umumnya berjalan asinkron untuk menjaga latensi write pada master tetap rendah. Konsekuensinya adalah replikasi lag. Jika aplikasi membaca dari replica sesaat setelah menulis ke primary (pola read-after-write), data terbaru berisiko belum tersedia (stale read). Menangani konsistensi ini di level kode aplikasi menambah kompleksitas routing query.
- Saturasi Connection Pool: Menambah instance replica membutuhkan koneksi pooling terpisah (misalnya via PgBouncer atau ProxySQL). Setiap node replica tetap membutuhkan resource memory dan buffer cache untuk mengelola koneksi aktif, yang pada titik tertentu membebani infrastruktur routing tanpa meningkatkan write capacity.
Contoh routing sederhana berbasis role koneksi di aplikasi:
// Pattern routing koneksi read/write di application level
class DatabaseRouter {
private \PDO $writerConnection;
private array $readerConnections;
public function getConnection(string $query): \PDO {
if ($this->isWriteQuery($query)) {
return $this->writerConnection;
}
// Load balancing sederhana antar read replicas
return $this->readerConnections[array_rand($this->readerConnections)];
}
private function isWriteQuery(string $query): bool {
return !preg_match('/^\s*(SELECT|SHOW|DESCRIBE|EXPLAIN)/i', $query);
}
}2. Kondisi Spesifik yang Mewajibkan Sharding
Sharding adalah partisi data horizontal di mana subset baris disimpan pada node basis data terpisah yang independen (shared-nothing architecture). Pendekatan ini merupakan langkah drastis yang hanya dibutuhkan ketika sistem menyentuh limitasi berikut:
- Kapasitas Disk dan Memory Working Set Mentok: Ukuran dataset telah melampaui batas instance terbesar yang tersedia di cloud provider (misal instance multi-terabyte), atau ukuran index dan working set tabel utama melebihi kapasitas RAM maksimum instance, menyebabkan drop drastis pada cache hit ratio dan lonjakan disk read.
- Saturasi IOPS Write pada Storage Tier: Ketika volume transaksi write menghasilkan I/O per second yang melampaui kemampuan hardware storage (misalnya EBS io2/gp3 maksimum atau local NVMe RAID limit), satu-satunya cara mendistribusikan beban I/O write adalah memecah tabel ke beberapa host independen.
- Beban Kunci Baris (Lock Contention): Transaksi konkuren tinggi pada tabel monolitik menghasilkan bottleneck pada row-level lock atau table latching yang tidak bisa diselesaikan hanya dengan tuning isolasi transaksi atau partisi lokal (declarative partitioning).
3. Kompleksitas Maintainability pada Database Sharding
Sharding memecah batasan fisik database dan merusak sebagian besar fitur relasional yang disediakan oleh RDBMS standar. Dampak engineering meliputi:
Hilangnya Foreign Key dan Constraint Antarnode
Database engine tidak dapat memvalidasi integritas referensial (Foreign Key) yang merujuk pada data di shard lain. Validasi integritas data terpaksa dipindahkan ke application logic, yang rentan terhadap inkonsistensi saat terjadi network partition atau race conditions.
Overhead Transaksi Terdistribusi
Menjalankan transaksi ACID yang melibatkan lebih dari satu shard memerlukan protokol Two-Phase Commit (2PC). 2PC memperkenalkan overhead latensi tinggi dan risiko blocking jika salah satu partisipan gagal. Alternatifnya adalah menerapkan arsitektur Saga Pattern di layer service, yang menuntut penanganan compensating transactions manual dan toleransi terhadap eventual consistency.
Migrasi Skema dan Resharding
Eksekusi schema migration (DDL) harus diorkestrasi secara serial atau terdistribusi di seluruh node shard. Risiko terbesar muncul saat distribusi data tidak seimbang (hotspotting) akibat pemilihan shard key yang buruk. Melakukan resharding (mengubah skema partisi dan memindahkan data antar-shard yang sedang aktif) membutuhkan tooling kompleks dan berpotensi memicu downtime signifikan.
4. Analisis Biaya Operasional (TCO)
Perbandingan biaya antara kedua strategi mencakup lisensi/hosting serta cognitive load tim engineer:
- Read Replicas (Cloud Native Managed): Biaya operasional rendah. Layanan seperti AWS RDS, GCP Cloud SQL, atau DigitalOcean Managed Databases menyediakan provisioning one-click, auto-failover, dan monitoring replikasi bawaan. Tim dapat beroperasi tanpa dedicated Database Administrator (DBA). Biaya infrastruktur bertambah linear sesuai jumlah node tambahan.
- Sharding Layer (Vitess / Citus / Custom App Logic): Memerlukan middleware proxy, metadata server (seperti ZooKeeper/etcd pada Vitess), dan mekanisme rebalancing data. Kompleksitas monitoring melonjak: distributed tracing wajib ada untuk mendiagnosis query lambat yang menyentuh multi-shard (cross-shard scatter-gather queries). Menjalankan sharding cluster umumnya membutuhkan dedicated SRE atau DBA berpengalaman tinggi.
5. Decision Framework: Kapan Harus Sharding?
Jangan mengadopsi sharding sebelum seluruh alternatif vertikal dan optimasi lokal dieksploitasi sepenuhnya. Gunakan alur pengambilan keputusan berikut:
- Optimasi Query dan Indeks: Audit slow query logs, pastikan index coverage memadai, eliminasi unindexed table scans, dan implementasikan connection pooler (misal: PgBouncer).
- Offload Read ke Cache dan Replica: Letakkan caching layer (Redis/Memcached) untuk hot-keys read-intensive, lalu pasang Read Replicas untuk laporan atau operasi read non-kritis terhadap lag.
- Skala Vertikal Maksimal: Naikkan spesifikasi instance compute dan storage tier node primer ke batas finansial yang rasional. Biaya cloud instance besar hampir selalu lebih murah dibanding gaji tim untuk mengelola distributed database system.
- Partisi Lokal (Table Partitioning): Gunakan partisi bawaan RDBMS (PostgreSQL Declarative Partitioning atau MySQL Table Partitioning) untuk memecah tabel besar berdasarkan waktu atau rentang ID dalam satu host yang sama guna menjaga ukuran working set index.
- Sharding: Jika kapasitas write IOPS atau storage volume per-node tetap jenuh setelah langkah 1-4 diterapkan, tentukan Shard Key dengan distribusi entropi tinggi dan adopsi sharding engine seperti Vitess (MySQL) atau Citus (PostgreSQL).
Simpulan arsitektur: Gunakan Read Replicas selama beban dominan adalah pembacaan data. Terapkan Sharding hanya sebagai jalan keluar terakhir ketika batas throughput penulisan dan kapasitas storage fisik single-node telah terlampaui.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!