Jawaban singkat untuk pertanyaan yang paling sering diajukan pembaca tentang topik ini.
01Bagaimana cara mendesain high availability?
Cari dan hilangkan single point of failure dengan menjalankan minimal dua instance di tiap tier, lengkap dengan health check yang mendeteksi node gagal dan mekanisme yang mengalihkan traffic. Jaga tier stateless tetap active-active dengan kapasitas cadangan, siapkan jalur promote database yang sudah dilatih, dan uji failover secara rutin. Lalu cocokkan hasilnya dengan budget downtime memakai rumus availability seri dan paralel.
02Berapa downtime untuk availability 99,9% dan 99,99%?
Dalam setahun 365 hari, 99,9% mengizinkan downtime 8,76 jam dan 99,99% mengizinkan 52,56 menit. Per bulan 30 hari, angkanya 43,2 menit dan 4,32 menit. Rumusnya satu dikurangi availability, dikali panjang periode.
03Apa beda failover active-active dan active-passive?
Di active-active semua node melayani traffic dan kegagalan memindahkan porsinya ke node yang tersisa, jadi mereka butuh kapasitas cadangan. Di active-passive satu node melayani sementara standby menunggu dipromosikan, jadi failover mencakup waktu deteksi dan takeover. Tier app stateless cocok active-active, sedangkan database dengan satu writer biasanya cocok active-passive.
04Secepat apa failover dengan keepalived dan VRRP?
RFC 5798 menetapkan timer takeover backup sebesar tiga kali advertisement interval ditambah skew time. Dengan interval 1 detik dan priority backup 90, hasilnya 3,648 detik. Health script yang butuh beberapa kegagalan berturut-turut menambah waktu itu, jadi kasus terburuk mendekati 10 detik realistis, tetapi Anda tetap perlu mengukurnya lewat uji failover.
05Apakah DNS failover cukup untuk high availability?
Biasanya tidak kalau berdiri sendiri, karena resolver menyimpan cache record selama TTL-nya dan TTL yang lebih panjang menunda perubahan berlaku. Dengan TTL 60 detik dan health check tiap 10 detik, client bisa menyimpan alamat mati sekitar 90 detik. DNS cocok untuk berpindah antar site, sementara floating IP atau proxy lebih cepat di dalam satu site.
Desain High Availability: Redundancy, Failover dan Nines
Cara mendesain high availability: arti tiap nine dalam menit, matematika availability seri vs paralel, waktu deteksi failover, plus contoh config keepalived dan nginx.
Untuk mendesain high availability, hilangkan setiap single point of failure dengan menjalankan minimal dua instance di tiap tier, di belakang mekanisme failover yang punya health check. Tier seri saling mengalikan availability, pasangan redundan yang independen naik menjadi satu dikurangi probabilitas gagal kuadrat, waktu deteksi memakan budget downtime, dan database stateful adalah bagian tersulit.
Pertanyaan yang selalu saya ajukan untuk deployment single VPS, tempat backend point-of-sale atau ERP biasanya bermula, sederhana: apa yang terjadi di jam tersibuk kalau satu mesin itu mati? Bukan bencana besar, cukup kernel update yang butuh reboot, disk penuh, atau jendela maintenance dari provider.
Post ini menjawab cara mendesain high availability, dimulai dari hitungannya. Tabel nines dan rumusnya diturunkan langsung, output kalkulator adalah output asli dari mesin saya, dan config mengikuti dokumentasi keepalived dan nginx. Saya belum menjalankan pasangan keepalived ini di production, jadi anggap config-nya titik awal berdasarkan dokumentasi yang harus Anda uji, bukan resep yang sudah teruji.
Berapa downtime yang diizinkan 99.9% atau 99.99% availability?
Availability adalah porsi waktu sebuah service berfungsi, dan biasanya disebut dalam nines, seperti di buku Google SRE dengan 99.9%, 99.99% dan 99.999%. Konversinya satu baris: downtime sama dengan satu dikurangi availability, dikali panjang periode. Dalam setahun 365 hari ada 8.760 jam, dan tabel di bawah adalah hasil perkalian itu.
Availability
Downtime per tahun
Downtime per bulan (30 hari)
Failover 60 detik per tahun
99%
87,60 jam
7,20 jam
5.256
99,5%
43,80 jam
3,60 jam
2.628
99,9%
8,76 jam
43,20 menit
525
99,95%
4,38 jam
21,60 menit
262
99,99%
52,56 menit
4,32 menit
52
99,999%
5,26 menit
25,92 detik
5
Kolom terakhir yang mengubah desain. Isinya budget tahunan dibagi 60 detik, dibulatkan ke bawah: di 99,99% Anda hanya mampu 52 failover satu menit dalam setahun penuh, dan di 99,999% hanya 5. Buku SRE menyebut angka 52,56 menit yang sama untuk 99,99%. Kalau target seketat itu, failover yang makan beberapa menit adalah outage itu sendiri, jadi desain harus membuat deteksi dan takeover cepat.
Bagaimana redundancy dan dependency seri mengubah availability?
Tier dalam satu request path tersusun seri: proxy, app dan database semuanya harus hidup agar request berhasil, sehingga availability-nya dikalikan. Tiga tier masing-masing 99,9% menghasilkan 0,999 x 0,999 x 0,999 = 0,997003, yaitu 99,7003% atau 26,25 jam downtime per tahun. Menambah tier ke dalam rantai tidak pernah memperbaikinya, dan rantai selalu lebih buruk dari mata rantai terlemahnya.
Salinan redundan dari satu tier tersusun paralel: tier baru mati kalau semua salinannya mati. Untuk n salinan independen dengan availability a, availability tier-nya adalah 1 dikurangi (1 dikurangi a) pangkat n. Sepasang mesin 99,9% memberi 1 dikurangi 0,001 x 0,001 = 0,999999, jadi 99,9999% untuk tier itu di atas kertas.
Ini kalkulator yang saya jalankan, TypeScript biasa tanpa dependency, dieksekusi dengan Node terbaru yang bisa membuang type. Kalkulator ini juga menghitung waktu takeover VRRP yang saya pakai di bagian berikutnya.
const HOURS_PER_YEAR = 365 * 24; // 8760
// Every tier must be up, so availabilities multiply.
const serial = (tiers: number[]): number => tiers.reduce((acc, a) => acc * a, 1);
// n replicas, any one is enough. Assumes failures are independent.
const parallel = (a: number, n: number): number => 1 - Math.pow(1 - a, n);
const hoursDown = (a: number): number => (1 - a) * HOURS_PER_YEAR;
// RFC 5798: Master_Down_Interval = 3 * advert + (256 - priority) * advert / 256
const vrrpTakeover = (advertSec: number, backupPriority: number): number =>
3 * advertSec + ((256 - backupPriority) * advertSec) / 256;
const proxy = 0.999;
const app = 0.999;
const db = 0.999;
const single = serial([proxy, app, db]);
const everyTierPaired = serial([proxy, app, db].map((a) => parallel(a, 2)));
console.log("one of each: " + (single * 100).toFixed(4) + "% = " + hoursDown(single).toFixed(2) + " h/yr");
console.log("every tier paired: " + (everyTierPaired * 100).toFixed(4) + "% = " + (hoursDown(everyTierPaired) * 60).toFixed(2) + " min/yr");
console.log("99.99% budget: " + (hoursDown(0.9999) * 60).toFixed(2) + " min/yr");
console.log("VRRP takeover: " + vrrpTakeover(1, 90).toFixed(3) + " s (advert 1 s, backup priority 90)");
$ node ha-calc.ts
one of each: 99.7003% = 26.25 h/yr
every tier paired: 99.9997% = 1.58 min/yr
99.99% budget: 52.56 min/yr
VRRP takeover: 3.648 s (advert 1 s, backup priority 90)
Menggandakan tier app saja, yang dicetak versi lebih panjang dari script yang sama, menaikkan stack ke 99,8%, atau 17,52 jam per tahun, karena proxy dan database masih tunggal dan masih seri. Memasangkan semua tier memberi 99,9997%, atau 1,58 menit per tahun. Pelajarannya, redundancy hanya berguna di tempat ia menghilangkan mata rantai terlemah yang tersisa, dan kotak tunggal terakhir mendominasi hasilnya.
Rumus paralel mengasumsikan dua salinan gagal secara independen dan failover berlangsung instan serta sempurna. Dua replica di satu host, satu aliran listrik, satu deploy pipeline atau satu push config yang salah akan gagal bersamaan, dan saat itu 1 dikurangi (1 dikurangi a) kuadrat hanyalah fiksi. Baca angka pasangan sebagai batas atas, bukan prakiraan.
Apa itu single point of failure dan bagaimana mencarinya?
Single point of failure adalah komponen mana pun yang kegagalannya menghentikan seluruh service karena tidak ada yang bisa mengambil alih. Cara praktis menemukannya: gambar request path, lalu untuk setiap kotak tanyakan apa yang terjadi kalau ia mati sekarang. Jawaban semuanya berhenti berarti single point of failure. Tersangka yang biasa di stack kecil adalah berikut ini.
Satu VPS atau virtual machine yang menjalankan proxy, app dan database sekaligus.
Load balancer atau reverse proxy itu sendiri, karena app server redundan di belakang satu proxy hanya memindahkan single point ke tier di atasnya.
Satu primary database atau satu instance Redis yang dibaca dan ditulis semua app server.
Satu alamat IP publik atau satu DNS provider yang dilalui semua client.
Hal bersama yang menjatuhkan semua replica sekaligus: sertifikat TLS yang kedaluwarsa, satu secrets store, satu deploy pipeline yang mengirim build rusak yang sama ke mana-mana.
Perbaiki berdasarkan seberapa besar bagian request path yang dijatuhkan masing-masing, bukan berdasarkan mana yang paling menarik. Proxy dan database biasanya didahulukan, dan hal bersama terakhir, karena butuh perubahan proses seperti staged rollout, bukan server tambahan.
Pilih active-active atau active-passive?
Di active-active setiap node melayani traffic sepanjang waktu, dan kegagalan berarti node yang tersisa mengambil porsi lebih besar. Di active-passive satu node melayani dan satu standby menunggu, dan kegagalan berarti standby harus dipromosikan. Tidak ada yang lebih baik secara umum, dan pilihannya berbeda per tier.
Pertanyaan
Active-active
Active-passive
Kapasitas yang Anda bayar
Semuanya melayani traffic
Standby menganggur sampai dibutuhkan
Isi proses failover
Keluarkan node mati dari rotasi, tidak ada yang dipromosikan
Deteksi, lalu promote atau pindahkan alamat: seluruh budget deteksi berlaku
Risiko utama
Node tersisa kelebihan beban oleh porsi yang hilang
Standby belum pernah diuji atau datanya usang saat dibutuhkan
Paling cocok untuk
Tier app stateless di belakang proxy
Database atau apa pun dengan satu writer
Risiko kelebihan beban adalah hitungan biasa. Dua node aktif yang masing-masing berjalan di utilisasi 60% butuh 120% kapasitas satu node saat salah satunya gagal, sehingga node yang tersisa tumbang dan pasangan itu mati total, bukan sekadar menurun. Untuk n node, jaga tiap node di bawah (n - 1) / n kapasitas: 50% untuk sepasang, sekitar 67% untuk tiga. Default saya active-active untuk tier stateless dan active-passive untuk database.
Seberapa cepat failover mendeteksi kegagalan dan mengambil alih?
Failover punya tiga bagian, deteksi, keputusan dan pengalihan, dan masing-masing memakai budget downtime. Deteksi biasanya yang terbesar. Tiga mekanisme umum, floating IP dengan VRRP, proxy yang berhenti mengirim ke upstream mati, dan DNS, berbeda terutama pada lamanya tiap bagian.
Untuk VRRP, RFC 5798 memberi timer takeover milik backup: Master_Down_Interval sama dengan 3 kali advertisement interval ditambah skew time sebesar (256 dikurangi priority-nya) kali interval dibagi 256. Dengan interval 1 detik dan priority backup 90, hasilnya 3 + 0,648 = 3,648 detik, angka yang dicetak kalkulator saya. Health script di depannya menambah waktu: dengan pengecekan tiap 2 detik dan 3 kegagalan berturut-turut, master menurunkan priority-nya sendiri setelah paling lama 6 detik, dan karena backup membuang advertisement berpriority lebih rendah selama preempt aktif, yang merupakan default, ia lalu menunggu timer-nya habis. Totalnya sekitar 6 + 3,65, mendekati 10 detik pada kasus terburuk. Ini hitungan saya dari dokumen, bukan hasil pengukuran.
# /etc/keepalived/keepalived.conf on node A (preferred). Node B is identical
# except: state BACKUP, priority 90.
vrrp_script chk_nginx {
script "/usr/bin/curl -fsS --max-time 1 http://127.0.0.1/healthz"
interval 2 # run the check every 2 s
fall 3 # 3 failed runs in a row = the check is KO
rise 2 # 2 good runs in a row = OK again
weight -20 # on KO, subtract 20 from priority: 100 -> 80, below B's 90
}
vrrp_instance VI_WEB {
state MASTER
interface eth0
virtual_router_id 51 # must match on both nodes
priority 100
advert_int 1 # advertise every 1 s
authentication {
auth_type PASS
auth_pass change-me
}
virtual_ipaddress {
203.0.113.10/24 # the address clients and DNS point at
}
track_script {
chk_nginx
}
}
Itulah yang dikodekan config keepalived di bawah. Weight minus 20 hanya berhasil karena menurunkan node A dari 100 ke 80, di bawah 90 milik node B; weight yang terlalu kecil untuk melewati selisih itu tidak akan pernah memindahkan alamat. Blok nginx menangani lapisan lain: passive check di modul upstream open-source, sedangkan active health check adalah fitur komersial.
upstream app {
# Passive checks: 2 failures inside 10 s take a server out for the next 10 s.
server 10.0.0.11:3000 max_fails=2 fail_timeout=10s;
server 10.0.0.12:3000 max_fails=2 fail_timeout=10s;
# Only receives traffic when the two above are unavailable.
server 10.0.0.13:3000 backup;
}
server {
listen 80;
location = /healthz { return 200 "ok\n"; }
location / {
proxy_pass http://app;
# Retry the next server on connection errors, timeouts and 502/503.
# POST is NOT retried unless you add non_idempotent: leave it off for payments.
proxy_next_upstream error timeout http_502 http_503;
}
}
nginx tidak meneruskan POST ke server berikutnya setelah request itu terkirim ke sebuah upstream, kecuali Anda menambahkan non_idempotent pada proxy_next_upstream. Untuk pembayaran, biarkan mati. Charge yang di-retry tanpa idempotency key adalah charge ganda, dan failover persis saat retry terjadi.
DNS failover adalah opsi paling lambat dan TTL penyebabnya. Dokumentasi Route 53 menjelaskan TTL sebagai lama resolver menyimpan cache sebuah record, dan memperingatkan bahwa nilai yang lebih panjang menunda perubahan berlaku. Dengan TTL 60 detik, health check tiap 10 detik dan asumsi tiga kegagalan, client bisa menyimpan alamat lama selama 30 + 60 = 90 detik. Di 99,99% itu budget tahunan 3.153,6 detik dibagi 90, hanya 35 failover seperti itu, dibanding lebih dari 320 untuk jalur VRRP sekitar 9,65 detik. Pakai DNS saat harus melintasi site, dan floating IP atau proxy di dalam satu site.
Mengapa tier stateful adalah bagian tersulit?
Tier stateless menjadi redundan dengan cara disalin. Jalankan container lain dan hasilnya identik. Database tidak bisa disalin begitu, karena salinannya harus sepakat soal setiap write. Tiap salinan tambahan karena itu menuntut satu keputusan konsistensi, dan failover harus memutuskan salinan mana yang benar.
Detail yang menggigit adalah mode commit. Pada replikasi asynchronous primary mengonfirmasi write sebelum replica menerimanya, jadi failover bisa kehilangan write terbaru yang sudah di-commit. Pada replikasi synchronous ia menunggu, yang menambah latency dan, kalau replica mati, mengurangi availability juga. Mekanismenya saya bahas di post tentang replikasi leader-follower, dan jebakan lag saat membaca dari replica di post read replica. Untuk sistem point-of-sale, order hilang setelah promote berarti selisih laci kas, jadi trade-off ini penting.
Promosi otomatis juga menambah risiko split-brain: kalau primary lama hanya terputus jaringan, bukan mati, dua node menerima write. Melakukan fencing pada primary lama sebelum promote adalah pencegahnya. Aturan saya untuk tim kecil: manual promote yang terdokumentasi dan sudah dilatih mengalahkan otomatisasi yang belum pernah dipicu, dan session, upload serta cache sebaiknya dipindahkan dulu dari tier app supaya node mana pun bisa melayani request apa pun.
Cukup multi-AZ, atau perlu multi-region?
Availability Zone AWS adalah satu atau lebih data center terpisah dengan listrik, jaringan dan konektivitas sendiri, dan AWS menyebut zone dalam satu region berjarak hingga sekitar 100 km: cukup jauh untuk menghindari kegagalan berkorelasi, cukup dekat untuk replikasi synchronous dengan latency satu digit milidetik. Kombinasi itulah alasan multi-AZ jadi jawaban default, karena Anda mendapat failure domain independen tanpa melepas replikasi synchronous.
Multi-region melindungi dari kegagalan satu region penuh, tetapi jarak membuat replikasi praktis asynchronous, menggandakan infrastruktur dan mengembalikan jendela kehilangan data. Mulai dari multi-AZ, dan pindah ke multi-region hanya kalau target menuntutnya. Di VPS biasa, pengecekan setaranya adalah apakah dua server Anda benar-benar di fasilitas berbeda atau hanya mesin berbeda di rak yang sama, poin yang juga diangkat post disaster recovery VPS saya.
Bagaimana menguji failover sebelum benar-benar dibutuhkan?
Failover yang belum pernah dijalankan hanyalah hipotesis. Game day adalah latihan terjadwal dan diumumkan di mana Anda sengaja merusak sesuatu lalu membandingkan hasilnya dengan prediksi. Urutan minimal untuk setup di atas seperti ini.
Tulis prediksi lebih dulu: virtual IP pindah dalam 10 detik dan tidak ada request yang gagal setelah itu.
Hentikan proses nginx di master dan ukur waktu sampai backup menjawab di virtual IP.
Reboot seluruh node master, yang menguji kasus yang tersembunyi saat hanya restart service.
Rusak sebuah dependency, misalnya memblokir port database dari satu app node, lalu amati health check dan retry.
Lakukan fail back, lalu pastikan master lama bergabung kembali sebagai standby dan tidak ada data yang hilang.
Catat waktu terukur terhadap budget di bagian pertama, tutup selisihnya dan ulangi. Rilis satu node per satu, seperti di post zero-downtime deploy saya, diam-diam melatih jalur yang sama di setiap release, makanya saya suka itu sebagai tes yang terus berjalan.
Lakukan hitungannya sebelum membeli apa pun. Hilangkan single point of failure berdasarkan seberapa besar masing-masing menjatuhkan sistem, jalankan tier stateless active-active dengan ruang kapasitas, beri database promote yang sudah dilatih, dan belanjakan budget downtime pada waktu deteksi yang Anda ukur di game day, bukan angka dari datasheet.