Jawaban singkat untuk pertanyaan yang paling sering diajukan pembaca tentang topik ini.
01Apa itu eventual consistency dengan bahasa sederhana?
Eventual consistency berarti replica dari data yang sama boleh berbeda sebentar, tetapi jika tidak ada write baru semuanya berakhir dengan nilai terakhir yang sama. Ia menjanjikan ke mana data berakhir, bukan apa yang dilihat pembaca di tengah jalan. Sistem menerimanya agar write tetap cepat dan available.
02Kapan eventual consistency boleh dipakai?
Boleh dipakai ketika read yang stale sebentar murah untuk salah dan write bersamaan punya aturan merge, seperti feed, jumlah like, analytics dan field profil. Tidak boleh untuk saldo, stok pada saat penjualan atau pengecekan keunikan. Ujian yang baik adalah apakah keputusan berdasarkan nilai berusia beberapa detik bisa merugikan uang.
03Apa beda strong consistency dan eventual consistency?
Pada strong consistency setiap read melihat write terakhir yang sudah di-acknowledge, seolah hanya ada satu salinan, dengan harga koordinasi dan availability yang lebih rendah saat partition. Pada eventual consistency read bisa stale atau tidak berurutan sampai replica konvergen. Session guarantee seperti read-your-writes berada di antara keduanya.
04Apa itu read-your-writes dan monotonic reads?
Read-your-writes berarti process yang melakukan write akan melihatnya di read berikutnya. Monotonic reads berarti setelah process melihat suatu nilai, read berikutnya tidak pernah menampilkan state yang lebih lama. Jepsen menggolongkan yang pertama sticky available dan yang kedua totally available, dan keduanya berlaku per process, bukan antar user.
05Bagaimana sistem eventual consistent menyelesaikan conflict?
Pendekatan umumnya last-write-wins, yang sederhana tetapi bisa membuang edit yang lebih baru jika jam tidak sinkron, version vector yang mendeteksi write bersamaan dan menyimpan keduanya agar di-merge aplikasi, serta CRDT yang merge-nya commutative, associative dan idempotent. Counter dan set adalah contoh CRDT yang umum.
Eventual Consistency Explained: Kapan Data Stale Boleh?
Apa jaminan eventual consistency, bagaimana replica konvergen lewat LWW, version vector dan CRDT, serta fitur mana yang boleh membaca data stale dan mana yang tidak.
Eventual consistency berarti jika tidak ada write baru, setiap replica dari sebuah item akhirnya mengembalikan nilai terakhir yang sama. Ini boleh dipakai untuk feed, jumlah like dan field profil, di mana read yang stale sebentar tidak berbahaya. Ini tidak boleh dipakai untuk saldo, stok dan pengecekan keunikan, yang butuh strong consistency pada titik pengambilan keputusan.
Bayangkan ERP carwash di mana dashboard pemilik menampilkan jumlah cuci hari ini terlambat beberapa detik dari tablet kasir. Tidak ada yang sadar dan tidak ada yang dirugikan. Sekarang bayangkan keterlambatan beberapa detik yang sama pada angka yang bilang sisa shampoo tinggal tiga botol, sementara dua kasir menjual sisa itu bersamaan. Mekanismenya sama, akibatnya sama sekali berbeda.
Post ini menjawab pertanyaan yang sering dicari: apa itu eventual consistency dan kapan boleh dipakai? Isinya spektrum dari strong sampai eventual, session guarantee yang membuat sistem eventual terasa wajar, cara replica menyelesaikan conflict, dan checklist keputusan. Definisi diambil dari Werner Vogels, model konsistensi Jepsen dan Wikipedia; angkanya berupa hitungan yang ditunjukkan atau output dari script yang saya jalankan.
Apa itu eventual consistency?
Vogels mendefinisikannya sebagai jaminan bahwa jika tidak ada update baru pada sebuah object, pada akhirnya semua akses akan mengembalikan nilai terakhir yang di-update. Baca dengan teliti. Ini menjanjikan ke mana replica berakhir, bukan apa yang dilihat pembaca di tengah jalan. Selama jeda itu, dua pembaca bisa mendapat dua jawaban berbeda, bahkan pembaca yang sama bisa mendapat jawaban yang lebih lama setelah jawaban yang lebih baru.
Sistem menerima ini karena biayanya. Menunggu semua replica mengonfirmasi tiap write membuat write lambat dan gagal saat ada replica atau link yang mati. Mengakui write secara lokal lalu menyebarkannya di background menjaga write tetap cepat dan available, dengan harga berupa jendela ketidaksamaan data. Saya sudah menulis kenapa trade-off ini dipaksa oleh network partition di post CAP theorem, dan tentang replica lag yang menciptakan jendela itu di post read replicas, jadi di sini fokusnya pada konsep dan keputusan.
Di mana posisinya antara strong dan eventual consistency?
Consistency adalah spektrum, bukan saklar. Cara berguna untuk menempatkan sebuah sistem adalah dari apa yang dijanjikan kepada pembaca selama jeda. Tabel berikut berisi titik-titik yang saya pakai saat mereview desain.
Model
Yang dijanjikan ke pembaca
Biayanya
Cocok untuk
Strong (linearizable)
Setiap read melihat write terakhir yang sudah di-acknowledge, seolah hanya ada satu salinan
Koordinasi di setiap write; lebih lambat, dan tidak available di sisi minoritas saat partition
Saldo, stok saat checkout, unique constraint
Session guarantee
Client melihat write miliknya sendiri dan tidak pernah melihat waktu mundur
Routing atau pelacakan versi per client; client lain masih bisa stale
Edit profil, pengaturan, post milik user sendiri
Eventual
Jika write berhenti, semua replica konvergen ke nilai yang sama
Read stale dan tidak berurutan mungkin terjadi; write bersamaan butuh aturan conflict
Feed, view count, analytics, cache
Strong eventual (CRDT)
Eventual, ditambah replica yang sudah melihat update yang sama memegang state yang sama
Data harus dimodelkan sebagai tipe yang bisa di-merge; tidak semua aturan bisa diungkapkan
Counter, set, collaborative editing
Perhatikan bahwa eventual consistency adalah baris terlemah, bukan kategori yang berbeda. Kebanyakan sistem nyata ada di baris kedua: eventual consistent di bawahnya dan menambah session guarantee di atasnya, yang menjadi pertanyaan berikutnya.
Apa itu read-your-writes dan monotonic reads?
Eventual consistency murni terasa rusak bagi user karena membuat seseorang kehilangan edit-nya sendiri. Session guarantee memperbaiki bagian terburuknya tanpa strong consistency penuh. Dua yang paling penting dalam praktik, dan keduanya didefinisikan dengan tepat oleh Jepsen dan Vogels.
Read your writes: jika sebuah process melakukan write lalu read berikutnya, read itu harus melihat write tersebut. Jepsen menggolongkannya sticky available, artinya setiap node tetap bisa berjalan saat partition selama client terus berbicara dengan server yang sama.
Monotonic reads: setelah sebuah process membaca suatu nilai, read berikutnya tidak boleh melihat state yang lebih lama, sehingga read tidak pernah mundur. Jepsen menggolongkannya totally available, jadi bertahan saat partition di node mana pun.
Session consistency: Vogels menggambarkannya sebagai read-your-writes yang berlaku selama session ada, tanpa janji yang dibawa ke session baru.
Kedua jaminan ini berlaku per process. Keduanya tidak menjanjikan apa pun tentang apa yang dilihat user lain, itulah sebabnya sebuah feed bisa menampilkan komentar baru Anda kepada Anda sementara teman masih melihat thread lama. Itu boleh untuk komentar dan tidak boleh untuk pembayaran.
Sticky routing adalah cara termurah untuk mendapat kedua jaminan: pin user ke satu replica, atau ke primary untuk jangka pendek setelah mereka menulis. User mendapat tampilan yang koheren tanpa membuat seluruh sistem strongly consistent.
Bagaimana replica konvergen saat write saling conflict?
Konvergensi butuh aturan untuk kasus ketika dua replica menerima write berbeda pada item yang sama. Wikipedia menyebut last writer wins sebagai pendekatan rekonsiliasi yang luas dipakai, bersama pertukaran anti-entropy dan read repair. Script berikut menjalankan dua aturan berdampingan: last-write-wins pada field teks, dan CRDT counter pada angka stok.
// convergence.ts (run with: node convergence.ts on Node 22.18+, or npx tsx)
// Two replicas accept writes while partitioned, then exchange state.
type Lww = { value: string; ts: number; node: string };
type PnCounter = { inc: Record<string, number>; dec: Record<string, number> };
// LWW register: highest timestamp wins; node id breaks ties so BOTH replicas
// pick the same winner. Without the tie-break they could swap values forever.
const mergeLww = (a: Lww, b: Lww): Lww =>
a.ts !== b.ts ? (a.ts > b.ts ? a : b) : a.node > b.node ? a : b;
// PN-counter: one slot per node, merged by taking the max of each slot.
// max is commutative, associative and idempotent, so merge order never matters.
const maxSlots = (x: Record<string, number>, y: Record<string, number>) => {
const out: Record<string, number> = { ...x };
for (const [n, v] of Object.entries(y)) out[n] = Math.max(out[n] ?? 0, v);
return out;
};
const mergeCounter = (a: PnCounter, b: PnCounter): PnCounter => ({
inc: maxSlots(a.inc, b.inc),
dec: maxSlots(a.dec, b.dec),
});
const total = (c: PnCounter) =>
Object.values(c.inc).reduce((s, v) => s + v, 0) -
Object.values(c.dec).reduce((s, v) => s + v, 0);
// Case 1: one field edited on both sides during the partition
const a: Lww = { value: "Jl. Merdeka 1", ts: 1000, node: "A" };
const b: Lww = { value: "Jl. Sudirman 9", ts: 1004, node: "B" };
console.log("LWW A merges B ->", mergeLww(a, b).value);
console.log("LWW B merges A ->", mergeLww(b, a).value);
// If B's clock runs 10 ms behind, its later edit carries ts 994 and loses silently:
const bSkewed: Lww = { ...b, ts: 994 };
console.log("LWW skewed B ->", mergeLww(a, bSkewed).value, "(B's newer edit is lost)");
// Case 2: stock starts at 10; A sells 3 and B sells 4 while partitioned
const base: PnCounter = { inc: { A: 10 }, dec: {} };
const left: PnCounter = { ...base, dec: { A: 3 } };
const right: PnCounter = { ...base, dec: { B: 4 } };
const lwwTotal = 10 - 3; // LWW on a plain number: A's write (7 left) wins, B's 4 sales vanish
console.log("LWW counter ->", lwwTotal, "left (true answer is 3)");
const m1 = mergeCounter(left, right);
const m2 = mergeCounter(right, left);
console.log("CRDT counter A<-B =", total(m1), " B<-A =", total(m2), " idempotent =", total(mergeCounter(m1, m1)));
Saya menjalankannya dan outputnya ditampilkan apa adanya. Kedua replica memilih alamat yang sama, itulah konvergensi. Tetapi LWW hanya sebaik jam-nya: geser satu replica 10 ms dan edit yang sebenarnya lebih baru dibuang diam-diam. Kasus stok lebih buruk, karena LWW pada angka biasa mempertahankan nilai satu sisi, sehingga 4 penjualan B hilang dan stok terbaca 7 padahal jawaban yang benar adalah 10 dikurangi 3 dikurangi 4, yaitu 3.
LWW A merges B -> Jl. Sudirman 9
LWW B merges A -> Jl. Sudirman 9
LWW skewed B -> Jl. Merdeka 1 (B's newer edit is lost)
LWW counter -> 7 left (true answer is 3)
CRDT counter A<-B = 3 B<-A = 3 idempotent = 3
Counter konvergen ke 3 di kedua urutan merge, dan me-merge state dengan dirinya sendiri tidak mengubah apa pun. Itu mengikuti syarat yang disebut Wikipedia untuk CRDT berbasis state: fungsi merge harus commutative, associative dan idempotent. Version vector adalah alat ketiga. Setiap replica menyimpan satu counter per node, dan satu write menggantikan yang lain hanya jika vector-nya lebih besar atau sama di semua posisi. Ambil A di A:2, B:0 dan B di A:1, B:1. Tidak ada yang mendominasi, jadi write-nya concurrent, dan sistem menyimpan keduanya sebagai sibling untuk di-merge oleh aplikasi, bukan menebak pemenang.
LWW tidak pernah melaporkan conflict. Ia konvergen, jadi semua dashboard tampak sehat, padahal data dibuang. Pakai hanya untuk field yang kehilangan salah satu dari dua edit bersamaan memang tidak masalah, dan jangan pernah pada angka yang harus berjumlah benar.
Fitur mana yang boleh eventual consistency dan mana yang tidak?
Pertanyaan penentunya bukan seberapa penting datanya. Melainkan apa yang terjadi jika satu pembaca bertindak berdasarkan nilai yang usianya beberapa detik. Berikut hasilnya untuk fitur yang akan saya temui di ERP, POS dan aplikasi web.
Fitur
Boleh read stale?
Alasan
Yang dilakukan
Feed berita atau aktivitas
Ya
Post yang muncul terlambat beberapa detik tidak merugikan siapa pun
Eventual, dengan read-your-writes untuk penulisnya
Counter like atau view
Ya
Perkiraan cukup, tetapi increment tidak boleh hilang
CRDT counter atau atomic increment yang di-batch
Edit profil atau pengaturan
Umumnya
Pengeditnya harus melihat perubahan sendiri; yang lain boleh tertinggal
Read-your-writes, LWW boleh
Saldo akun atau pembayaran
Tidak
Saldo stale memungkinkan overdraft atau double spend
Strong consistency pada ledger yang menjadi acuan
Stok saat checkout
Tidak
Dua penjual bisa sama-sama menjual unit terakhir, seperti contoh 10 dikurangi 3 dikurangi 4
Atomic decrement atau reservasi di primary
Username atau nomor invoice unik
Tidak
Dua replica bisa sama-sama menerima nilai yang sama
Unique constraint ditegakkan di satu tempat
Polanya: read murah untuk salah, keputusan tidak. Angka stok di halaman produk boleh eventual. Angka yang sama pada saat penjualan tidak boleh. Kebanyakan sistem butuh keduanya, jadi pilihan desain sebenarnya adalah di mana batas strong ditempatkan, bukan apakah harus ada.
Bagaimana memutuskan eventual consistency boleh dipakai?
Jalankan fitur melalui lima pertanyaan ini secara berurutan. Jawaban tidak yang pertama mengarahkan Anda ke strong consistency untuk jalur itu.
Jika pembaca bertindak berdasarkan nilai yang usianya beberapa detik, apakah uang, stok atau catatan hukum bisa salah?
Apakah fitur menegakkan invariant keunikan atau urutan, misalnya satu pemilik per username atau nomor invoice tanpa celah?
Bisakah dua replica menerima write pada item yang sama bersamaan, dan apa aturannya saat itu terjadi?
Apakah user yang menulis perlu langsung melihat perubahannya? Jika ya, tambahkan read-your-writes.
Bisakah layar dengan jujur mengatakan nilai mungkin sedikit usang, atau ia menjanjikan angka yang persis?
Jawaban ya untuk dua pertanyaan pertama berarti strong consistency untuk jalur write itu, meski semua di sekitarnya eventual. Jika kedua pertanyaan itu dijawab tidak dan Anda punya aturan merge untuk yang ketiga, eventual consistency adalah pilihan yang sehat, bukan kompromi.
Pola UI apa yang membuat data stale aman?
Eventual consistency adalah properti lapisan storage, tetapi user bertemu dengannya di antarmuka, dan antarmukalah yang menentukan apakah jeda itu terasa seperti bug. Pola-pola ini menyembunyikan jeda atau membuatnya jujur.
Optimistic update: tampilkan perubahan user segera dari state lokal, yang memberi read-your-writes di level layar, lalu rollback dengan pesan jelas jika server menolaknya.
Pending state: tandai record sebagai saving atau syncing sampai write dikonfirmasi, supaya item yang belum muncul terbaca sebagai sedang diproses, bukan hilang.
Kejujuran soal staleness: beri label updated-at pada dashboard dan tampilkan hitungan perkiraan sebagai perkiraan, bukan angka yang tampak presisi tetapi mungkin salah.
Cek ulang saat commit: ketika user menekan beli atau bayar, baca nilai yang menjadi acuan dari store yang strongly consistent dan tampilkan pesan jelas jika nilainya berubah.
Pola terakhir adalah yang membuat sisa halaman boleh tetap eventual. Read yang murah, cepat dan mungkin stale menggerakkan browsing, dan satu pengecekan strong menjaga aksi yang tidak bisa dibatalkan.
Eventual consistency boleh dipakai ketika read yang stale murah untuk salah dan setiap write bersamaan punya aturan merge yang Anda pilih dengan sengaja. Tidak boleh untuk saldo, stok pada saat penjualan atau keunikan. Jaga batas strong tetap kecil, tambahkan read-your-writes untuk orang yang baru menulis, dan jangan biarkan last-write-wins menyentuh angka yang harus berjumlah benar.