Jawaban singkat untuk pertanyaan yang paling sering diajukan pembaca tentang topik ini.
01Bagaimana cara kerja algoritma konsensus Raft?
Raft memilih satu leader per term. Leader menambahkan command dari client ke lognya, mereplikasinya ke follower, dan menandai entry sebagai committed setelah mayoritas menyimpannya. Jika leader gagal, follower yang election timeout-nya habis lebih dulu menjadi candidate dan menang dengan suara mayoritas.
02Mengapa Raft memakai election timeout acak?
Jika semua follower memakai timeout yang sama, mereka akan menjadi candidate bersamaan dan suara terbelah berulang kali. Timeout acak, seperti 150 sampai 300 ms pada contoh di paper, membuat satu follower biasanya habis lebih dulu dan menang sebelum yang lain mulai. Jika split vote tetap terjadi, tiap candidate mengambil timeout acak baru untuk percobaan ulang.
03Berapa kegagalan node yang bisa ditoleransi cluster Raft?
Cluster berisi n server butuh floor(n / 2) + 1 server untuk membentuk quorum, sehingga ia toleran terhadap n dikurangi jumlah itu kegagalan. Hasilnya 1 kegagalan untuk 3 node, 2 untuk 5 node, dan 3 untuk 7 node. Empat node tetap hanya toleran 1, itulah sebabnya ukuran ganjil direkomendasikan.
04Apa beda entry committed dan applied di Raft?
Entry committed ketika leader tahu entry itu tersimpan di mayoritas server. Setiap server lalu menerapkan entry committed ke state machine sesuai urutan log. Leader membagikan commit index lewat AppendEntries berikutnya, jadi follower menerapkan entry sedikit lebih lambat dari leader.
05Sistem apa saja yang memakai Raft?
etcd memakai Raft untuk key-value store yang direplikasi, dan FAQ-nya menjelaskan desain berbasis leader yang menyimpan Raft log ke disk. HashiCorp Consul menjalankan Raft di antara server agent-nya dan mendokumentasikan ukuran quorum untuk 3 sampai 8 server. Situs Raft mendaftar banyak implementasi lain.
Algoritma Konsensus Raft: Penjelasan Election dan Log
Cara kerja algoritma konsensus Raft: term dan role, leader election dengan timeout acak, log replication dan commit index, hitungan quorum untuk 3, 5, 7 node, safety, serta pemakaian di etcd dan Consul.
Raft menjaga cluster tetap sepakat pada satu log berurutan dengan memilih satu leader per term lewat timeout acak, mereplikasi tiap entry ke mayoritas sebelum di-commit, dan menolak memberi suara kepada kandidat dengan log usang. Quorum mayoritas berarti 3 node toleran 1 kegagalan, 5 node toleran 2, dan 7 node toleran 3.
Begitu sebuah service stateful berjalan di lebih dari satu node, pertanyaan yang penting bukan lagi cara menyalin data, melainkan siapa yang berhak memutuskan. Sistem saya sendiri, yaitu ERP, POS, dan back office carwash di atas NestJS dan Postgres, menyerahkan keputusan itu kepada database, jadi saya tidak perlu membangun jawabannya sendiri. Raft adalah jawaban yang dipakai database dan layanan koordinasi di bawahnya.
Artikel ini menjawab satu pertanyaan: bagaimana cara kerja algoritma konsensus Raft? Isinya mengikuti paper asli oleh Diego Ongaro dan John Ousterhout, menurunkan angka quorum lewat hitungan alih-alih sekadar mengutipnya, dan ditutup dengan toy TypeScript kecil yang benar-benar saya jalankan, sehingga outputnya asli. Toy ini untuk memahami konsep. Ini bukan implementasi, dan artikel menyebut dengan jelas apa saja yang ditinggalkan.
Mengapa sistem terdistribusi butuh konsensus?
Konsensus adalah cara beberapa server menyepakati satu urutan command walaupun sebagian server crash atau terputus dari jaringan. Paper membingkainya lewat replicated state machine: setiap server memegang salinan state machine yang sama dan menerapkan command yang sama dalam urutan yang sama, sehingga semua salinan berakhir di state yang sama. Algoritma konsensus mengelola replicated log berisi command tersebut. Jika log identik di mana-mana, state pun identik di mana-mana.
Bagian yang sulit: server yang berhenti menjawab tidak bisa dibedakan dari server yang lambat, dan dua sisi jaringan yang terbelah bisa sama-sama merasa dirinya yang berkuasa. Raft menyelesaikannya dengan menjadikan satu server sebagai leader, hanya leader yang boleh mengurutkan command, dan setiap command harus diterima mayoritas sebelum dianggap sah. Selama mayoritas server masih bisa berkomunikasi, cluster tetap menerima write. Di bawah mayoritas, cluster berhenti, dan itu pilihan sengaja: konsistensi di atas availability.
Apa itu term dan role (follower, candidate, leader) di Raft?
Setiap server Raft berada di tepat satu dari tiga role pada satu waktu, dan waktu dipotong menjadi term bernomor. Term adalah logical clock yang hanya maju: dimulai dengan sebuah election dan berlangsung sampai election berikutnya. Server saling bertukar nomor term di setiap pesan, dan server yang melihat term lebih tinggi dari miliknya langsung mengadopsinya lalu turun menjadi follower.
Role
Tugasnya
Cara berganti role
Follower
Pasif. Menjawab request dari leader dan candidate, serta menerapkan entry yang sudah committed.
Menjadi candidate saat election timeout habis tanpa heartbeat yang valid.
Candidate
Menaikkan term, memilih dirinya sendiri, lalu meminta suara dari server lain.
Menang dengan mayoritas lalu menjadi leader, atau melihat leader atau term lebih tinggi lalu turun, atau timeout dan mencoba lagi.
Leader
Menangani semua write dari client, mereplikasinya, dan mengirim heartbeat untuk mempertahankan otoritasnya.
Turun menjadi follower jika melihat term lebih tinggi.
Nomor term inilah yang membuat leader usang tidak berbahaya. Leader yang sempat terputus lalu kembali masih percaya pada term lamanya. Pesan pertama yang ia kirim atau terima membawa term lebih tinggi, jadi ia turun alih-alih menimpa data. Setiap server juga hanya memilih satu candidate per term, sehingga satu term menghasilkan paling banyak satu leader.
Bagaimana leader election bekerja dengan timeout acak?
Server mulai sebagai follower. Leader mengirim heartbeat berkala, yaitu pesan AppendEntries tanpa entry. Follower yang tidak mendengar apa pun selama periode bernama election timeout menganggap tidak ada leader yang layak, menaikkan term, menjadi candidate, memilih dirinya sendiri, dan mengirim RequestVote ke semua server lain. Contoh di paper adalah timeout yang diambil acak dari interval seperti 150 sampai 300 ms.
broadcastTime << electionTimeout << MTBF (Raft paper, section 9.3)
heartbeat interval : well under the timeout (heartbeats are empty AppendEntries)
election timeout : drawn at random per node, per attempt, e.g. 150-300 ms
split vote : nobody reaches quorum -> every candidate waits a NEW random
timeout -> one of them usually fires first and wins the retry
Keacakan inilah triknya. Jika semua follower memakai timeout yang sama, mereka akan menjadi candidate bersamaan, suara terbelah dan tidak ada yang mencapai mayoritas, berulang-ulang. Dengan timeout acak, biasanya satu follower habis lebih dulu, memenangkan election, dan mulai mengirim heartbeat sebelum yang lain bangun. Kalau split vote tetap terjadi, tiap candidate memilih timeout acak baru untuk percobaan ulang. Paper juga memberi batasan waktu agar ini stabil: broadcast time sebaiknya satu orde besaran di bawah election timeout, dan election timeout beberapa orde besaran di bawah rata-rata waktu antar kegagalan.
Election timeout juga sekaligus waktu failover Anda. Selama leader lama hilang, cluster tidak menerima write selama kira-kira satu timeout. Setel di atas round trip jaringan dan latensi disk sync yang sebenarnya, kalau tidak follower yang sehat akan memulai election yang tidak perlu.
Bagaimana log replication dan commit index bekerja?
Client mengirim command ke leader. Leader menambahkannya ke log sendiri sebagai entry baru bertanda term saat ini, lalu mengirim AppendEntries ke semua follower. Setiap pesan menyebut entry tepat sebelum entry baru, lengkap dengan index dan term. Follower hanya menerima jika lognya punya entry yang cocok di posisi itu. Pemeriksaan konsistensi inilah yang menjamin properti Log Matching: jika dua log punya entry dengan index dan term yang sama, kedua log identik sampai entry tersebut.
index: 1 2 3 4
term: 1 1 2 2
cmd: SET s=10 DEC s 3 DEC s 2 DEC s 1
A replicated state machine applies the SAME log in the SAME order on every node:
s = 10 -> 7 -> 5 -> 4 (every node ends at s = 4)
committed = replicated on a majority AND safe to apply
commitIndex = 3 means entries 1..3 may be applied; entry 4 is not safe yet
AppendEntries(term, prevLogIndex, prevLogTerm, entries[], leaderCommit)
follower rejects unless its log has an entry at prevLogIndex with term prevLogTerm
(this is the Log Matching check; on rejection the leader backs nextIndex up by one)
Sebuah entry berstatus committed begitu leader tahu entry itu tersimpan di mayoritas server. Leader mencatatnya sebagai commit index dan menyertakannya di AppendEntries berikutnya, sehingga follower tahu mana yang aman diterapkan ke state machine mereka. Jika log follower menyimpang, leader mundur lewat nextIndex untuk follower itu sampai log cocok, lalu menimpa entry follower yang bertentangan. Follower tidak pernah menimpa leader.
Berapa kegagalan yang bisa ditoleransi 3, 5, dan 7 node?
Quorum adalah mayoritas, dan hitungannya muat dalam empat baris. Cluster berisi n server membutuhkan floor(n / 2) + 1 server yang setuju, sehingga ia bertahan dari n dikurangi jumlah itu kegagalan. Alasan yang lebih dalam mengapa mayoritas tepat: dua mayoritas mana pun pasti berbagi setidaknya satu server, dan server bersama itulah yang membawa pengetahuan tentang entry committed terakhir ke leader berikutnya.
quorum(n) = floor(n / 2) + 1
tolerated(n) = n - quorum(n)
n = 3: quorum = floor(3/2) + 1 = 2 tolerated = 3 - 2 = 1
n = 5: quorum = floor(5/2) + 1 = 3 tolerated = 5 - 3 = 2
n = 7: quorum = floor(7/2) + 1 = 4 tolerated = 7 - 4 = 3
n = 4: quorum = floor(4/2) + 1 = 3 tolerated = 4 - 3 = 1 (same as n = 3)
Why a majority is the right size: two quorums of size q out of n nodes
overlap in at least 2q - n nodes. With q = floor(n/2) + 1 that is always >= 1.
n = 5, q = 3: 3 + 3 - 5 = 1 node is in BOTH quorums
That shared node is the witness: it saw the last committed entry, so a new
leader that needs its vote cannot be elected with a log that lacks it.
Node (n)
Quorum
Kegagalan yang ditoleransi
Catatan
3
2
1
Cluster terkecil yang bertahan dari satu kegagalan.
4
3
1
Toleransi sama dengan 3 node, dengan quorum yang lebih besar.
5
3
2
Pilihan umum di production untuk availability lebih tinggi.
7
4
3
Bertahan lebih banyak, tetapi tiap write menunggu 4 acknowledgement.
Tabel yang sama muncul di dokumentasi Consul, yang merekomendasikan 3 atau 5 server untuk production dan melarang single server di luar development. Perhatikan apa yang tidak dibeli oleh cluster lebih besar: write tidak jadi lebih cepat. Setiap commit tetap harus sampai ke mayoritas lewat satu leader, jadi menambah node menukar throughput dan latensi dengan fault tolerance.
Ukuran cluster genap adalah jebakan. Empat node hanya toleran satu kegagalan, persis seperti tiga, tetapi butuh tiga acknowledgement per write, bukan dua. Dua node tidak toleran sama sekali, karena kehilangan salah satunya menyisakan satu dari dua, yang bukan mayoritas. Jalankan jumlah ganjil.
Apa yang menjaga Raft tetap aman? Election restriction
Safety bertumpu pada satu aturan: candidate tidak boleh menang kecuali lognya paling tidak sama up to date dengan log setiap server dalam mayoritas yang memilihnya. Up to date artinya last term yang lebih tinggi menang, dan jika last term sama, log yang lebih panjang menang. Karena entry committed berada di mayoritas, dan pemenang butuh suara mayoritas, setidaknya satu pemilih memegang semua entry committed dan akan menolak candidate yang tidak memilikinya. Dari sinilah paper mendapatkan properti Leader Completeness: log leader selalu memuat setiap entry yang committed di term sebelumnya.
Ada satu kehalusan lagi. Leader hanya boleh meng-commit entry dari term-nya sendiri dengan menghitung replika. Entry lama menjadi committed secara tidak langsung, ketika entry yang lebih baru di atasnya ikut committed. Figure 8 di paper menunjukkan bagaimana menghitung replika entry lama bisa membuat entry yang tampak committed tertimpa. Toy di bawah menerapkan kedua aturan itu, dan saya menjalankannya sungguhan, dengan node2 terputus saat write pertama.
// raft-toy.ts (excerpt): the three rules that carry the safety argument.
// Teaching toy: single process, "RPCs" are method calls, no disk, no snapshots,
// no membership change, no real timers. NOT an implementation of Raft.
// RequestVote receiver: term rule, one vote per term, election restriction.
requestVote(term: number, cand: number, lastIdx: number, lastTerm: number): boolean {
if (term > this.term) { this.term = term; this.votedFor = null; this.role = "follower"; }
if (term < this.term) return false;
const upToDate =
lastTerm > this.lastTerm() ||
(lastTerm === this.lastTerm() && lastIdx >= this.log.length);
if (!upToDate) return false; // never vote for a log older than ours
if (this.votedFor !== null && this.votedFor !== cand) return false;
this.votedFor = cand;
return true;
}
// AppendEntries receiver: consistency check on prevIdx/prevTerm, then append.
appendEntries(term: number, prevIdx: number, prevTerm: number,
entries: Entry[], leaderCommit: number): boolean {
if (term < this.term) return false;
this.term = term; this.role = "follower"; // a valid leader exists this term
if (prevIdx > this.log.length ||
(prevIdx > 0 && this.log[prevIdx - 1].term !== prevTerm)) return false;
this.log = this.log.slice(0, prevIdx).concat(entries);
this.commitIndex = Math.max(this.commitIndex, Math.min(leaderCommit, this.log.length));
return true;
}
// Leader commit rule: majority AND an entry of the CURRENT term (Figure 8).
if (stored >= quorum && this.log[idx - 1].term === this.term) this.commitIndex = idx;
// Driver: 3 nodes, timeouts drawn from 150-300 ticks with a seeded PRNG (seed 7).
// 1) tick until the first timeout fires -> that node runs an election
// 2) leader.propose("SET stock=7", [node1]) // node2 is unreachable
// 3) leader crashes; stale node2 starts an election first
// 4) node1 (up to date) starts an election
$ node raft-toy.ts
1) boot: all followers, timeouts = 151, 159, 296 ticks
t=151 node0 starts election for term 1, votes=3/3, quorum=2
node0 is leader of term 1
node0 leader term=1 log=[] commit=0
node1 follower term=1 log=[] commit=0
node2 follower term=1 log=[] commit=0
2) client write while node2 is partitioned away (only node1 reachable)
node0 appended "SET stock=7" at index 1, stored on 2/3, commitIndex=1
node0 leader term=1 log=["1:SET stock=7"] commit=1
node1 follower term=1 log=["1:SET stock=7"] commit=0
node2 follower term=1 log=[] commit=0
3) leader crashes, partition heals; the STALE node (no entry) asks for votes first
t=152 node2 starts election for term 2, votes=1/3, quorum=2
stale node became leader? false
4) the up-to-date node runs its own election and wins with the stale node's vote
t=153 node1 starts election for term 3, votes=2/3, quorum=2
node1 is leader of term 3
node0 DOWN term=1 log=["1:SET stock=7"] commit=1
node1 leader term=3 log=["1:SET stock=7"] commit=0
node2 follower term=3 log=[] commit=0
Baca outputnya dengan teliti. Node2 tidak punya entry, jadi ketika meminta suara di term 2 ia hanya mendapat suaranya sendiri, 1 dari 3, dan tidak bisa menang walau leader lama sudah mati. Node1, yang memegang entry committed, lalu menang di term 3 dengan suara node2. Log selamat dari kematian leader. Dua detail jujur juga terlihat: follower menampilkan commit sama dengan 0 karena commit index dibawa oleh AppendEntries berikutnya, dan leader baru menampilkan 0 karena leader baru tidak bisa menghitung entry lama. Paper membuat setiap leader baru meng-commit entry no-op kosong di awal term-nya tepat untuk alasan ini.
Yang ditinggalkan toy ini adalah sebagian besar Raft: persistensi term, vote, dan log sebelum membalas, timer dan heartbeat sungguhan, kehilangan dan perubahan urutan pesan, mundurnya nextIndex, snapshot dan log compaction, serta perubahan membership. Toy ini mengajarkan aturannya. Ini bukan sesuatu untuk di-deploy.
Bagaimana mengubah membership cluster dengan aman?
Mengganti server berbahaya karena server berbeda bisa beralih dari konfigurasi lama ke baru pada saat berbeda, dan dalam jendela itu dua mayoritas yang terpisah masing-masing bisa memilih leader. Paper Raft menghindarinya dengan pendekatan dua fase bernama joint consensus. Cluster lebih dulu pindah ke konfigurasi transisi yang menggabungkan lama dan baru, di mana keputusan butuh mayoritas dari keduanya. Setelah itu di-commit, barulah cluster pindah ke konfigurasi baru saja.
Dalam praktik Anda jarang mengimplementasikannya sendiri, dan sebaiknya ubah satu server per kali. Periksa apa yang didukung tool Anda. FAQ etcd, misalnya, menyatakan node yang rusak permanen bisa dikeluarkan dari cluster lewat runtime reconfiguration.
Di mana Raft dipakai, dan perlukah Anda menjalankannya sendiri?
Raft berada di bawah infrastruktur nyata. FAQ etcd menyatakan etcd berbasis leader, request yang butuh konsensus dan dikirim ke follower diteruskan ke leader, dan etcd menyimpan Raft log ke disk lalu memutarnya ulang setelah listrik mati. Dokumentasi Consul menggambarkan server-nya sebagai peer set Raft di mana quorum harus setuju sebelum perubahan state di-commit. Situs Raft mendaftar banyak implementasi lain.
Untuk stack ERP atau POS biasa di satu VPS, Anda tidak akan menulis Raft. Satu primary Postgres atau satu instance Redis lebih sederhana, dan konsensusnya ada di dalam layanan terkelola atau lapisan koordinasi yang Anda pakai. Gunakan checklist ini sebelum menjangkaunya.
Apakah Anda butuh beberapa node menyepakati satu riwayat write berurutan, bukan sekadar menyalin data satu arah?
Apakah service bisa menolak write saat mayoritas tidak terjangkau? Raft memilih konsistensi di atas availability.
Apakah sudah ada sistem (etcd, Consul, database dengan konsensus bawaan) yang menyediakannya, sehingga Anda tidak mengimplementasikan protokolnya?
Apakah Anda akan menjalankan jumlah server ganjil, tiga untuk satu kegagalan atau lima untuk dua, di failure domain yang terpisah?
Apakah election timeout sudah disetel di atas latensi jaringan dan disk yang Anda ukur, dan apakah penggantian member sudah direncanakan?
Raft terkenal mudah dipahami karena konsensus diringkas menjadi tiga ide kecil: satu leader per term yang dipilih dengan timeout acak, log yang harus cocok sebelum follower menambahkan entry, dan aturan mayoritas yang ditopang election restriction. Ingat hitungannya, floor(n / 2) + 1, ukuran cluster ganjil, dan anggap protokol ini sesuatu yang Anda adopsi lewat sistem matang, bukan Anda tulis.