Database scaling adalah cara membuat database sanggup menerima beban yang lebih besar: lebih banyak query per detik, atau lebih banyak data. Bayangin semua penjualan tiket dicatat di satu buku besar oleh satu petugas. Orang yang cuma bertanya ("kursi A-12 masih ada?") dan orang yang membeli (petugas menulis di buku) antre di meja yang sama. Kamu bisa mengganti petugasnya dengan yang lebih cepat, memberi buku fotokopian ke petugas lain khusus untuk menjawab pertanyaan, atau memecah bukunya: pembeli A sampai M di meja 1, N sampai Z di meja 2. Tiga cara itu adalah vertical scaling, read replica, dan sharding.
🧪 Tebakan cepat: saat war tiket, primary database TiketNada di 130% karena 520 write per detik. Sudah ada 4 read replica. Kamu tambah replica ke-5. Primary-nya turun di bawah 100%? Tebak dulu, jawabannya ada di bagian "Read replica: membagi read, bukan write".
Model contoh: database TiketNada
Angka di lesson ini dan di Lab adalah model contoh, bukan benchmark. Di hari biasa (traffic 1x), aplikasi TiketNada mengirim 1.300 read (SELECT) dan 130 write (INSERT, UPDATE, DELETE) per detik ke PostgreSQL. Satu server 8 vCPU sanggup 4.000 read per detik, atau 400 write per detik. Write lebih mahal karena harus mencatat ke disk dan memperbarui index.
Beban server = read / 4.000 + write / 400 = 32,5% + 32,5% = 65%. Di bawah 100%, query menunggu sekitar 4 ms / (1 - beban): 11 ms di 65%, 40 ms di 90%. Di atas 100%, server menerima lebih banyak kerja daripada yang sanggup dia selesaikan, jadi antreannya bertambah terus. Di traffic 2x bebannya 130%: tiap detik antrean bertambah 0,3 detik kerja. Setelah 10 detik, query baru menunggu sekitar 3 detik, dan pembeli melihat timeout.
Sebelum menambah server, pastikan query-nya sudah sehat. Query tanpa index yang membaca 2 juta baris gak tertolong server mana pun. Bahasannya ada di lesson Index Strategy dan Connection Pooling (track Database), dan cache di lesson Caching Strategies.
Vertical scaling: server yang lebih besar
Vertical scaling (scale up) artinya menambah resource di satu server: CPU, RAM, disk yang lebih cepat. Di model ini, server dua kali lebih besar sanggup sekitar 1,8 kali bebannya, bukan 2 kali, dan harganya dua kali.
| Ukuran | Kapasitas | Biaya | Beban di traffic 2x | Beban di traffic 6x |
|---|---|---|---|---|
| 8 vCPU | 1x | 1x | 130% | 390% |
| 16 vCPU | 1,8x | 2x | 72% | 217% |
| 32 vCPU | 3,2x | 4x | 41% | 122% |
| 64 vCPU | 5,8x | 8x | 22% | 67% |
Kelebihannya: satu klik di cloud, kode gak berubah sama sekali. Kekurangannya: ada batas mesin terbesar, biayanya naik lebih cepat dari kapasitasnya, dan tetap satu mesin. Kalau mesin itu mati, semuanya ikut mati.
Horizontal scaling: lebih banyak server
Horizontal scaling (scale out) artinya menambah jumlah server. Untuk server aplikasi ini gampang, karena tiap server sama (lesson Load Balancing). Untuk database lebih sulit, karena datanya harus ada di server-server itu. Ada dua cara:
- Read replica: semua server menyimpan data yang sama. Read dibagi, write tetap ke satu server.
- Sharding: tiap server menyimpan sebagian data. Read dan write sama-sama dibagi.
Read replica: membagi read, bukan write
Read replica adalah salinan database yang cuma bisa dibaca. Satu server jadi primary yang menerima semua write, lalu setiap perubahan disalin ke replica. Aplikasi mengirim SELECT ke replica, dan INSERT, UPDATE, DELETE ke primary:
function route(sql) {
return sql.trim().toUpperCase().startsWith('SELECT') ? 'replica' : 'primary';
}
console.log(route('SELECT * FROM orders WHERE user_id = 48213')); // replica
console.log(route('INSERT INTO orders (user_id, event_id, qty) VALUES (48213, 42, 2)')); // primary
sql.trim()membuang spasi di awal,toUpperCase()membuatselectdanSELECTsama.- Query yang diawali
SELECTke replica; sisanya ke primary.
Yang sering terlupa: setiap replica juga harus menerapkan ulang setiap write supaya datanya sama. Di model ini, itu makan setengah biaya write. Ini traffic 3x (3.900 read dan 390 write per detik):
| Setup | Primary | Tiap replica |
|---|---|---|
| Tanpa replica | 97,5% + 97,5% = 195% | - |
| 1 replica | 390 / 400 = 97,5% | 97,5% read + 48,75% replay = 146% |
| 2 replica | 97,5% | 48,75% + 48,75% = 97,5% |
| 4 replica | 97,5% | 24,4% + 48,75% = 73% |
Naik ke traffic 4x: 520 write per detik semuanya tetap ke primary, 520 / 400 = 130%, berapa pun replica-nya. Replica ke-5 cuma mengambil read, jadi primary tetap 130%. Itu jawaban tebakannya. Read replica menolong beban yang read-heavy (kebanyakan aplikasi web), tapi gak menolong write.
Satu lagi: replica selalu sedikit tertinggal dari primary (replication lag), jadi data yang baru ditulis bisa belum terlihat di replica. Bahasan lengkapnya ada di lesson Replication & HA (track Database).
Sharding: membagi data
Sharding memecah satu tabel besar ke beberapa server. Tiap server, disebut shard, memegang sebagian baris dan menerima read dan write untuk baris itu saja. Kolom yang menentukan sebuah baris masuk ke shard mana disebut shard key.
Di Lab, TiketNada punya 120.000 user dan 4 shard. Ada tiga pilihan shard key:
// hash(user_id): angka acak tapi tetap, dari id-nya
function shardByHash(userId) {
return hash(String(userId)) % 4; // hash() = FNV-1a, ada di kode Lab
}
// range user_id: id 1-30.000 di shard 0, 30.001-60.000 di shard 1, dan seterusnya
function shardByRange(userId) {
return Math.min(3, Math.floor((userId - 1) / 30000));
}
// event_id: semua pesanan satu event di satu shard
function shardByEvent(eventId) {
return eventId % 4;
}
console.log(shardByHash(48213), shardByRange(48213), shardByEvent(42)); // 2 1 2
hash(...) % 4mengubah id jadi angka 0 sampai 3. Hash yang baik menyebar id secara merata, dan id yang sama selalu ke shard yang sama.- Range membagi id per blok berurutan: gampang dibaca, tapi user yang baru daftar selalu masuk blok terakhir.
eventId % 4: Konser Nusantara (event 42) selalu di shard 2.
Hot shard dan query lintas shard
Dua fakta model ini: 7 dari 10 pembeli memburu Konser Nusantara, dan user yang daftar paling akhir (id 90.001 ke atas) tiga kali lebih aktif, jadi mereka membawa 50% traffic. Di traffic 4x, 4 shard:
| Shard key | Shard tersibuk memegang | Bebannya |
|---|---|---|
hash(user_id) |
25,2% traffic | 66% |
range user_id |
50% (shard 3, user terbaru) | 130% |
event_id |
70% (shard 2, Konser Nusantara) | 182% |
Shard yang menanggung jauh lebih banyak dari yang lain disebut hot shard. Tiga shard santai, satu kewalahan, dan sistemnya ikut lambat. Pilih shard key yang nilainya banyak dan traffic-nya tersebar rata.
Kelemahan utama sharding adalah query lintas shard. Query yang gak menyebut shard key harus dikirim ke semua shard lalu digabung di aplikasi (scatter-gather): latency-nya ikut shard paling lambat, dan bebannya 4 query, bukan 1. JOIN antar shard lebih sulit lagi.
| Query | Shard key hash(user_id) |
Shard key event_id |
|---|---|---|
SELECT * FROM orders WHERE user_id = 48213 |
1 shard | 4 shard |
SELECT COUNT(*) FROM orders WHERE event_id = 42 |
4 shard | 1 shard |
Jadi shard key diambil dari query yang paling sering. Kelemahan lain: menambah shard dengan % N memindahkan hampir semua baris (consistent hashing mengurangi ini, lihat lesson Load Balancing), dan id harus unik di semua shard, bukan per shard.
🎯 Urutan dari yang paling murah
- Perbaiki query dan index. Cek dengan
EXPLAIN. Sering kali selesai di sini. - Connection pooling dan cache. Redis untuk data yang sering dibaca.
- Vertical scaling. Satu klik, tanpa ubah kode.
- Read replica. Untuk beban yang kebanyakan read.
- Pisah per fitur (vertical partitioning): tabel analytics di database sendiri, misalnya.
- Sharding. Paling akhir, karena paling rumit dijalankan dan sulit dibatalkan.
⚠️ Jebakan yang sering ketemu
- Sharding terlalu cepat. Banyak aplikasi dengan jutaan user masih cukup satu primary dan beberapa replica. Sharding menambah kerumitan di setiap query.
- Mengira replica menolong write. Semua write tetap ke primary, dan setiap replica malah ikut menerapkan ulang semuanya.
- Shard key yang timpang.
event_idsaat war tiket, tanggal daftar, atau negara: satu shard jadi hot shard. - Shard key yang gak ada di query utama. Query paling sering jadi scatter-gather ke semua shard.
TL;DR: Vertical scaling menambah resource di satu server: mudah, tapi ada batas mesin terbesar dan biayanya naik cepat. Horizontal scaling menambah jumlah server. Read replica menyalin seluruh database ke server read-only: SELECT dibagi ke replica, semua write tetap ke primary, jadi replica menolong read tapi gak menolong write (di model ini primary tetap 130% di traffic 4x berapa pun replica-nya). Sharding memecah data ke beberapa shard lewat shard key, jadi read dan write sama-sama dibagi. Pilih shard key yang tersebar rata dan ada di query paling sering: event_id membuat hot shard (182%), hash(user_id) rata (66%). Kelemahan utama sharding adalah query lintas shard yang harus ditanyakan ke semua shard lalu digabung. Perbaiki query, index, dan cache dulu; sharding paling akhir.