Masalah dan Skenario yang Berlaku
Rancang message queue terdistribusi yang digunakan bersama oleh beberapa tim produk. Ingress stabil adalah 1 juta pesan per detik dengan rata-rata 1 KB per pesan, dan lonjakan lalu lintas dapat mencapai 3 juta pesan per detik selama 15 menit. Pesan diretensi selama 24 jam secara default. Produsen mempublikasikan secara batch. Konsumen menarik (pull) dalam kelompok (group), melakukan commit offset, dan memutar ulang (replay) dalam masa retensi. Pesan dengan kunci bisnis yang sama memerlukan pengurutan lokal, sementara kunci yang berbeda dapat berjalan secara paralel. Pesan biasa menggunakan pengiriman at-least-once, dan acknowledgment publikasi memiliki target p99 di bawah 50 milidetik. Setiap partisi memiliki tiga replika di tiga availability zone; kehilangan satu zone tidak boleh menghilangkan pesan yang telah di-acknowledge.
Sebagian besar pesan berukuran kecil, tetapi API mengizinkan payload bisnis hingga 100 MB. Payload besar tidak boleh berulang kali melewati log broker, transfer replika, dan buffer konsumen. Dalam desain ini, payload besar pertama-tama masuk ke penyimpanan objek (object storage), sementara antrean hanya menyimpan referensi yang tidak dapat diubah (immutable), ukuran, dan checksum. Throughput, latensi, retensi, ambang batas, dan jumlah replika adalah asumsi wawancara yang memerlukan benchmarking pada perangkat keras target. Hal-hal tersebut bukan klaim produk.
Sebuah artikel desain sistem berbahasa Mandarin yang diterbitkan pada Mei 2026 secara langsung membahas antrean yang memproses puluhan miliar pesan per hari dengan lonjakan jutaan QPS. Sebuah prompt PracHub yang diperbarui pada Juni 2026 meminta kandidat untuk mencakup API, consumer group, offset, partisi, replika, payload besar, dan isolasi multi-tenant. Bersama-sama, keduanya membentuk prompt desain sistem yang dapat diverifikasi saat ini. Hanya satu halaman yang menyatakan atribusi perusahaan, sehingga artikel ini membiarkan perusahaan tidak ditetapkan.
Apa yang Dievaluasi oleh Pewawancara
Pertama, apakah kandidat mendefinisikan kontrak pengiriman? Publikasi yang berhasil, penyimpanan broker yang tahan lama (durable), pengiriman pesan ke konsumen, penyelesaian efek samping bisnis (business side effect), dan commit offset adalah lima batasan yang terpisah. Menyebut semuanya sebagai "keberhasilan pesan" menyembunyikan dua celah kegagalan: produsen dapat mengulangi publikasi setelah kehilangan acknowledgment, dan konsumen dapat mengulangi pekerjaan setelah menyelesaikan efek samping tetapi mengalami crash sebelum melakukan commit offset.
Kedua, apakah pemartisian, pengurutan, dan penskalaan mengikuti satu alur argumen? Mengirim satu kunci ke satu partisi mempertahankan urutan log kunci tersebut. Partisi yang sama membatasi throughput penulisan dan paralelisme consumer group. Partisi yang lebih banyak menambah slot paralel, tetapi tidak membagi kunci panas (hot key) yang terus-menerus kelebihan beban atau menciptakan pengurutan global.
Ketiga, apakah aturan acknowledgment replika bertahan dari kegagalan? Jawaban yang kuat menyatakan kapan produsen dapat diberi acknowledgment, replika mana yang berhak menjadi leader baru, dan bagaimana epoch membatasi (fence) leader lama yang pulih. Mengatakan "tiga replika melakukan failover secara otomatis" tidak membuktikan bahwa rekaman yang telah di-acknowledge tetap bertahan.
Keempat, apakah offset konsumen terhubung dengan hasil bisnis? Melakukan commit sebelum pemrosesan dapat melewatkan efek bisnis. Memproses sebelum commit dapat memutarnya ulang setelah crash. At-least-once memilih celah kedua, lalu menyerap pengulangan dengan ID pesan yang stabil, business idempotency key, batasan unik (unique constraint), atau kondisi versi. Transaksi broker hanya mencakup sumber daya yang berpartisipasi dalam transaksi tersebut; transaksi broker tidak secara otomatis memberikan efek exactly-once ke layanan pembayaran eksternal, penyedia email, atau database.
Terakhir, bisakah antrean mempertahankan batasan-batasan ini di bawah tekanan? Kandidat harus menghitung penyimpanan 24 jam dan backlog lonjakan, menangani pesan besar, partisi panas, konsumen lambat, poison message, disk penuh, dan tenant yang berisik (noisy tenants), kemudian menginjeksikan kegagalan untuk membuktikan bahwa pesan yang di-acknowledge tidak hilang, pekerjaan yang belum di-commit tidak dilewati, dan pemilik yang basi (stale) tidak dapat memajukan offset.
Pertanyaan Klarifikasi Sebelum Menjawab
- Apakah ini log yang diretensi atau work queue model claim-and-delete? Desain ini memilih log yang diretensi karena beberapa
consumer group dan fitur replay diperlukan. Jika tepat satu pekerja mengklaim setiap tugas dan replay historis tidak diperlukan, lease queue dengan visibility timeout akan lebih sederhana.
- Apa cakupan pengurutannya? Pengurutan mencakup urutan penambahan (append order) dalam satu partisi topik, dengan satu kunci bisnis dipatok
ke satu partisi. Tidak ada urutan global lintas kunci, partisi, atau topik. Urutan global akan menurunkan throughput menjadi satu log serial.
- Apa arti dari acknowledgment publikasi? Dua dari tiga replika telah menyimpan rekaman secara durable, dan control plane
masih mengenali epoch leader saat ini. Topik dengan durabilitas kuat menolak penulisan jika replika yang tersedia kurang dari dua.
- Apa semantik konsumsinya? Default-nya adalah at-least-once: memproses dengan sukses, lalu melakukan commit offset berikutnya.
Efek samping eksternal memerlukan idempoten atau rekonsiliasi. Hanya beban kerja bernilai rendah yang mengizinkan kehilangan data tetapi melarang duplikat yang boleh melakukan commit terlebih dahulu.
- Apakah konsumen memerlukan replay arbitrer? Sebuah grup dapat melakukan reset berdasarkan offset atau timestamp dalam rentang waktu retensi 24 jam.
Di luar masa retensi, grup harus memulihkan dari arsip, atau gagal secara eksplisit jika arsip tidak ada.
- Bolehkah poison message dilewati? Topik biasa dapat memindahkan pesan ke dead-letter topic setelah batas percobaan ulang tertentu.
Topik dengan pengurutan kunci yang ketat tidak dapat langsung melewatinya; jeda kunci atau partisi tersebut dan perbaiki, jika tidak pesan-pesan berikutnya dapat mendahului kegagalan tersebut.
- Haruskah payload 100 MB berbentuk inline? Tidak. Desain ini mengasumsikan payload inline hingga 256 KiB dan menggunakan referensi objek
di atas ambang batas tersebut. Benchmarking dan biaya menentukan ambang batas; 100 MB adalah batas payload objek.
- Apa persyaratan lintas-wilayah (cross-region)? Desain utama adalah satu wilayah di tiga availability zone.
Disaster recovery lintas-wilayah asinkron tidak dapat menjanjikan nol kehilangan data (zero data loss) sekaligus latensi penulisan lokal. Persyaratan lintas-wilayah dengan RPO nol mengubah jalur acknowledgment dan anggaran latensi.
- Seberapa kuat isolasi tenant? Broker digunakan bersama secara default, dengan batas ingress, egress, penyimpanan, partisi,
dan koneksi per-tenant. Tenant yang sangat besar atau terikat regulasi dapat menggunakan pool broker khusus di bawah control plane dan protokol yang sama.
Kerangka Jawaban 30 Detik
"Saya akan memodelkan ini sebagai log terpartisi yang diretensi dan dapat diputar ulang (replayable). Produsen merutekan berdasarkan kunci bisnis ke leader partisi, menggabungkan penulisan secara batch, dan menerima acknowledgment hanya setelah dua replika di availability zone yang berbeda menyimpan batch tersebut. Hal ini memberikan pengurutan per-kunci, bukan pengurutan global. Consumer group memiliki partisi secara eksklusif, menyelesaikan penulisan bisnis yang idempoten, dan kemudian melakukan commit offset berikutnya, sehingga pengiriman bersifat at-least-once dan efek eksternal dideduplikasi berdasarkan ID pesan. Ingress stabil sekitar 1 GB/s dan 86,4 TB per hari secara logis, atau 259,2 TB dengan tiga replika. Lonjakan tiga kali lipat selama 15 menit menciptakan backlog ekstra sekitar 1,8 TB jika konsumen mempertahankan laju stabil. Payload di atas 256 KiB masuk ke penyimpanan objek dan antrean membawa referensi serta checksum. Saya akan membuktikan batasan ini dengan kuota tenant, penjadwalan yang adil, peringatan lag, kegagalan leader, acknowledgment yang hilang, dan uji crash konsumen."
Pendalaman Langkah demi Langkah
Langkah 1: Tulis API dan invarian sebelum komponen.
Permukaan penting mencakup topik, publikasi, pengambilan (fetching), commit, dan reset offset:
POST /v1/topics
POST /v1/topics/{topic}/messages:publish
POST /v1/groups/{group}/messages:fetch
POST /v1/groups/{group}/offsets:commit
POST /v1/groups/{group}/offsets:resetPermintaan publikasi membawa konteks tenant yang terotentikasi, topik, message_key opsional, message_id yang stabil, payload atau referensi objek, epoch produsen, dan urutan per-partisi. Respons batch mengembalikan partisi, offset, dan status commit dari setiap pesan. Fetch membawa grup, generasi kepemilikan partisi, offset awal, byte maksimum, dan durasi long-poll. Commit menulis offset rekaman berikutnya yang akan dibaca.
Desain ini mempertahankan empat invarian: rekaman yang telah di-acknowledge tetap dapat dibaca setelah kegagalan satu availability zone; konsumen hanya melihat prefiks yang telah di-commit; offset meningkat secara monotonik dalam satu epoch leader; dan konsumen dengan generasi yang kedaluwarsa tidak dapat melakukan commit offset atau terus menulis hasil. message_id tingkat API mendukung deduplikasi bisnis. producer_id + epoch + sequence memungkinkan broker mengenali percobaan ulang dari publikasi yang sama.
Langkah 2: Pisahkan control plane dari data plane.
Control plane: tenants and ACLs, topic configuration, partition placement,
replica membership, leader epochs, quotas
Data plane:
Producer -> metadata cache -> partition leader -> follower replicas
Consumer group -> group coordinator -> partition leaders -> business sinkKlaster kecil berbasis konsensus menyimpan metadata topik dan partisi serta menetapkan epoch yang meningkat secara monotonik ke setiap masa jabatan (term) leader. Klaster ini tidak membawa isi pesan. Broker menambahkan (append), mereplikasi, membaca, dan meretensi rekaman. Klien menyimpan cache leader partisi dan menyegarkan metadata setelah menerima respons stale-epoch atau not-leader. Throughput pesan menghindari proksi pusat, sementara partisi yang ada dapat terus berjalan selama masa sewa (lease) tertentu saat terjadi pemadaman control plane. Pembuatan topik dan pemindahan partisi dapat dijeda; metadata yang basi tidak boleh memilih leader sembarangan.
Langkah 3: Gunakan log terpartisi untuk throughput, replay, dan pengurutan lokal.
Setiap partisi adalah sekumpulan segmen append-only yang rekamannya berisi:
MessageEnvelope {
tenant_id, topic, partition, offset
message_id, message_key, producer_id, producer_epoch, sequence
created_at, headers, payload_or_ref, payload_size, checksum
}Segmen aktif menerima penambahan sekuensial. Indeks offset yang renggang (sparse offset index) menemukan lokasi pembacaan, dan segmen yang ditutup akan bergulir (roll) berdasarkan waktu atau ukuran. Konsumen mengambil batch berdasarkan offset, memungkinkan I/O sekuensial, penggunaan page-cache, dan transfer jaringan batch. Retensi menghapus seluruh segmen setelah 24 jam. Segmen yang sedang berada di bawah pemutaran ulang (replay) valid atau pengunggahan penyimpanan berjenjang (tiered-storage) menahan referensi sehingga penghapusan tidak mengalami race condition dengan pembaca.
Hash perutean mencakup tenant tepercaya, topik, dan kunci bisnis. Rekaman dengan kunci yang sama tetap berada di satu partisi; rekaman tanpa kunci dapat menggunakan penetapan round-robin atau sticky-batch. Perutean khusus tenant membuat tenant besar menjadi panas (hot), sementara perutean acak sepenuhnya menghilangkan urutan kunci. Menambahkan partisi memengaruhi rekaman di masa mendatang. Perubahan modulo dapat menempatkan satu kunci di partisi lama dan baru. Jika urutan yang stabil penting, petakan virtual shard ke partisi fisik; jeda virtual shard selama pemindahan, catat cutover offset, kosongkan (drain) pemilik lama, dan lanjutkan di bawah epoch baru.
Langkah 4: Berikan satu definisi commit pada replikasi dan pemilihan leader.
Setiap partisi memiliki tiga replika di tiga availability zone. Leader menetapkan offset, menambahkan batch secara durable, dan mereplikasikannya secara paralel. Setelah dua replika berhasil menyimpan batch secara persisten, commit_watermark akan maju dan produsen menerima acknowledgment. Konsumen hanya membaca offset di bawah watermark tersebut. Saat terjadi kegagalan leader, control plane hanya memilih replika yang berisi prefiks yang telah di-commit dan menaikkan nilai epoch. Leader lama yang pulih akan memotong ekornya yang belum di-commit dan mengejar ketertinggalan sebelum melayani permintaan; permintaan yang membawa epoch lamanya akan ditolak.
Kebijakan ini menoleransi kegagalan satu availability zone. Dengan dua replika yang tersisa, keduanya harus memberikan acknowledgment, sehingga latensi dan kapasitas menurun. Jika salah satu dari replika yang tersisa kemudian gagal, topik dengan durabilitas kuat berhenti memberikan acknowledgment untuk penulisan sampai replikasi dipulihkan. Memilih replika yang basi untuk meningkatkan ketersediaan akan melanggar janji tanpa kehilangan data (no-loss promise). Selama partisi jaringan (network partition), hanya sisi dengan mayoritas commit yang boleh menulis; sisi lainnya akan dibatasi (fenced).
Produsen mencoba lagi ketika rekaman telah di-commit tetapi respons acknowledgment hilang. Broker melakukan deduplikasi di dalam partisi menggunakan epoch produsen dan urutan monotonik, lalu mengembalikan offset asli. Produsen zombi dengan epoch lama akan ditolak. Ini menghapus duplikat log yang disebabkan oleh percobaan ulang publikasi. Ini tidak menggabungkan dua permintaan bisnis berbeda yang menggunakan ID berbeda, atau mendeduplikasi efek samping eksternal konsumen.
Langkah 5: Hubungkan kepemilikan grup dan offset ke hasil bisnis.
Dalam sebuah consumer group, satu anggota memiliki satu partisi pada satu waktu. Koordinator grup mengelola anggota, sewa (lease), generasi, dan penugasan. Peristiwa timeout atau penskalaan menciptakan generasi baru, dan permintaan fetch atau commit dari anggota lama akan ditolak. Rebalancing bertahap (incremental rebalancing) hanya memindahkan partisi yang diperlukan dan mengurangi jeda di seluruh grup, tetapi konsumen tetap harus berhenti mengambil data dan melakukan commit pada pekerjaan yang selesai sebelum kepemilikan dicabut.
Urutan default-nya adalah mengambil batch, melakukan penulisan bisnis yang idempoten, lalu melakukan commit offset berikutnya. Jika konsumen mengalami crash setelah commit bisnis dan sebelum commit offset, pemilik baru akan memutar ulang rekaman yang telah selesai, yang menghasilkan pengiriman at-least-once. message_id yang stabil dapat mendukung unique constraint atau rekaman pesan yang telah diproses, atau di-commit dalam transaksi database yang sama dengan status bisnis. Jika output kembali ke sistem perpesanan yang sama, rekaman output dan offset input dapat berbagi transaksi broker. Database eksternal, penyedia pembayaran, atau email tetap membutuhkan idempotensi, pencarian status, atau rekonsiliasi.
Offset disimpan dalam log metadata yang direplikasi di bawah (tenant, group, topic, partition) dan membawa informasi generasi. Pemantauan mencakup log_end_offset - committed_offset dan usia pesan tertua yang belum diproses. Jumlah pesan saja dapat memberikan gambaran backlog yang keliru jika ukuran rekaman bervariasi, sehingga sistem juga melaporkan lag byte dan waktu pengejaran (catch-up time) pada laju konsumsi bersih saat ini.
Langkah 6: Nyatakan konflik antara retry, dead-letter, dan pengurutan.
Kegagalan jaringan sementara dan throttling masuk ke topik percobaan ulang tertunda (delayed retry topic) dengan jitter. Kegagalan skema, izin, atau validasi bisnis yang bersifat deterministik tidak boleh dicoba ulang secara membabi buta. Percobaan ulang mempertahankan message_id asli, topik sumber, partisi, offset, waktu pertama kali dilihat, jumlah percobaan, dan kelas kesalahan. Setelah batas percobaan atau batas waktu bisnis terlampaui, pesan berpindah ke dead-letter topic, memicu peringatan, dan memungkinkan redrive terkontrol. Redrive mempertahankan ID asli sehingga tidak dapat melewati idempotensi.
Memindahkan rekaman yang gagal ke samping memungkinkan rekaman berikutnya selesai lebih dulu, yang bertentangan dengan pengurutan ketat per-kunci. Jika status urutan harus berkembang secara ketat, jeda kunci tersebut dan tampung rekaman berikutnya dalam jalur berurutan yang terpisah, lalu lanjutkan dari offset yang gagal setelah diperbaiki. Menjeda seluruh partisi lebih sederhana tetapi memiliki dampak (blast radius) yang lebih besar. Jika bisnis dapat menerima konvergensi berdasarkan versi, rekaman berikutnya dapat dilanjutkan dan sistem tujuan (sink) menolak versi yang basi. Kontrak topik harus memilih; kontrak tidak dapat menjanjikan "poison message tidak pernah memblokir" sekaligus "pesan tidak pernah saling mendahului."
Langkah 7: Tempatkan pesan besar di balik referensi objek dan selesaikan race condition pada garbage collection.
Desain ini menetapkan 256 KiB sebagai ambang batas inline. Payload yang lebih besar menggunakan kredensial unggah berumur pendek untuk menulis objek yang tidak dapat diubah (immutable) beserta ukuran, hash konten, dan metadata enkripsinya. Hanya setelah pengunggahan berhasil, produsen mempublikasikan referensinya. Konsumen membaca objek dan memverifikasi hash. Replika broker hanya menyalin amplop (envelope) kecil, sehingga rekaman 100 MB tidak dapat memonopoli buffer jaringan, batch replikasi, atau memori konsumen.
Pengunggahan yang berhasil tetapi referensinya tidak pernah dipublikasikan adalah yatim piatu (orphan) dan kedaluwarsa sesuai TTL sesi unggah. Setelah referensi di-commit, retensi objek harus mencakup retensi pesan, replay yang valid, dead-letter, dan margin keamanan. Tugas penghapusan pertama-tama memeriksa referensi yang dilindungi dan menghapusnya setelah masa tenggang (grace period). Jika pembacaan objek gagal, konsumsi tetap uncommitted dan mencoba lagi; memberikan acknowledgment terlebih dahulu dapat meninggalkan isi pesan yang hilang secara permanen. Payload besar menerima kuota laju byte, unduhan bersamaan (concurrent download), dan penyimpanan terpisah per-tenant karena pembatasan berbasis jumlah pesan salah dalam menentukan biayanya.
Langkah 8: Hitung partisi, disk, dan ruang cadangan (headroom) pengejaran dari kapasitas.
Menggunakan desimal 1 KB, ingress logis stabil adalah:
1,000,000 messages/s × 1,000 bytes = 1 GB/s
1 GB/s × 86,400 s = 86.4 TB/day
Lower bound for three replica writes = 86.4 × 3 = 259.2 TB/dayTotal ingress selama lonjakan 15 menit adalah 3 GB/s × 900 = 2.7 TB. Jika konsumen hanya mempertahankan laju stabil 1 GB/s, backlog ekstra adalah:
(3 GB/s - 1 GB/s) × 900 s = 1.8 TBSetelah lonjakan, anggaplah konsumen mempertahankan laju 1,5 GB/s sementara ingress baru tetap 1 GB/s. Laju pengejaran bersih adalah 0,5 GB/s, sehingga 1,8 TB membutuhkan waktu 3.600 detik, atau sekitar satu jam, untuk dikuras secara teori. Pemulihan replika, overhead batch, kompresi, indeks, cadangan filesystem, dan penyimpanan objek pesan besar menambah kapasitas, jadi angka-angka ini adalah batas bawah.
Jumlah partisi dibatasi oleh byte dan pesan. Misalkan benchmark dengan tiga replika dan target p99 menemukan bahwa satu partisi dapat mempertahankan 40 MB/s dan 40.000 pesan per detik. Kedua dimensi puncak tersebut membutuhkan setidaknya 75 partisi. Menambahkan ruang cadangan 50% untuk kegagalan dan rebalancing menghasilkan sekitar 113, sehingga 128 adalah pilihan praktis. Hasil per-partisi tersebut adalah asumsi benchmark wawancara. Perangkat keras, batch, acknowledgment, atau ukuran rekaman yang berbeda memerlukan pengujian baru; 128 bukanlah jawaban universal.
Langkah 9: Terapkan backpressure, isolasi tenant, dan operasional yang dapat diverifikasi.
Konsumen menggunakan long polling dan mengontrol lajunya dengan max_bytes serta batas batch yang sedang berjalan (in-flight). Saat watermark disk broker meningkat, sistem pertama-tama menghentikan pembuatan partisi baru, menurunkan toleransi lonjakan (burst allowances) untuk tenant berprioritas rendah, lalu menolak publikasi yang melebihi kuota dengan sinyal yang dapat dicoba lagi (retryable). Antrean memori dan percobaan ulang tanpa batas mengubah kemacetan menjadi kegagalan proses. Produsen menggunakan buffer batch terbatas, tenggat waktu, dan backoff dengan jitter sehingga pemadaman broker tidak menciptakan badai percobaan ulang yang tersinkronisasi.
Identitas tenant berasal dari kredensial, tidak pernah dari isi pesan. Ingress dibatasi oleh laju pesan dan byte. Egress dijadwalkan secara adil berdasarkan byte pengambilan (fetch bytes) dan CPU permintaan. Penyimpanan, partisi, consumer group, koneksi, permintaan in-flight, dan objek besar juga memiliki batasan. Penempatan beban menghindari pemusatan replika satu tenant atau partisi panas pada segelintir broker. Tenant yang sangat besar dipindahkan ke pool khusus, sementara pool bersama tetap mengukur dan melaporkan penolakan per-tenant.
Metrik utama mencakup acknowledgment publikasi p50/p95/p99, kesalahan, dan hasil yang tidak diketahui (unknown outcomes); byte ingress per-partisi, lag leader dan follower, commit_watermark, watermark disk, dan hot key; offset ter-commit consumer group, lag konsumen, usia pesan tertua, rebalance, retry, dan dead-letter; objek orphan dan kegagalan pembacaan; serta pembatasan (throttling) dan keadilan per-tenant. Canary menyeluruh (end-to-end canary) mempublikasikan ID yang stabil, melakukan commit hasil bisnis yang idempoten, lalu melakukan commit offset dan merekonsiliasi status broker, grup, dan bisnis.
Matriks kesalahan mencakup crash leader sebelum replikasi, setelah commit, dan sebelum mengembalikan acknowledgment; kehilangan satu availability zone; partisi jaringan; disk penuh; pemulihan stale-leader; hot key; lonjakan tiga kali lipat selama 15 menit; crash konsumen sebelum dan setelah commit bisnis; commit basi selama rebalance; poison message; pengunggahan berhasil diikuti kegagalan publikasi; kegagalan membaca objek; dan redrive dead-letter. Kriteria penerimaan memastikan bahwa rekaman yang di-acknowledge tetap bertahan, pekerjaan yang belum di-commit tidak dilewati, urutan kunci mengikuti kontrak topik, generasi yang basi tidak dapat memajukan offset, dan setiap duplikat, penolakan, atau pesan yang terbuang memiliki metrik yang dapat diatribusikan.
Contoh Jawaban Berkualitas Tinggi
"Pertama-tama saya akan mengonfirmasi bahwa ini adalah layanan retained-log yang membutuhkan beberapa consumer group dan replay 24 jam. Sebuah topik dibagi menjadi partisi-partisi, dan kunci bisnis yang sama tetap berada di satu partisi. Oleh karena itu, pengurutan mencakup kunci dan partisi, sementara partisi yang berbeda berjalan secara paralel. Produsen mendapatkan metadata leader dari control plane dan menulis batch secara langsung. Setiap partisi memiliki tiga replika di berbagai availability zone; hanya dua replika durable yang memajukan commit_watermark dan memberi acknowledgment kepada produsen. Leader baru harus berisi prefiks yang telah di-commit, dan epoch membatasi (fence) leader dan produsen lama.
Penyimpanan menggunakan segmen append-only dan indeks offset yang renggang. Konsumen grup secara eksklusif memiliki partisi dan melakukan long-poll. Konsumen melakukan commit hasil bisnis yang idempoten sebelum melakukan commit offset berikutnya. Crash dapat menyebabkan pemutaran ulang pekerjaan tetapi tidak dapat melewatinya secara diam-diam. Di sisi produsen, epoch dan urutan produsen menghapus retry yang disebabkan oleh hilangnya acknowledgment. Di sisi konsumen, ID pesan yang stabil, unique constraint, atau kondisi versi menyerap efek yang berulang. Saya hanya akan mengklaim transaksi broker end-to-end ketika offset input dan output berada dalam transaksi broker tersebut; sistem eksternal tetap membutuhkan idempotensi atau rekonsiliasi.
Kapasitas stabil adalah 1 GB/s dan 86,4 TB data logis per hari, dengan batas bawah 259,2 TB untuk penulisan tiga replika. Lonjakan tiga kali lipat selama 15 menit menciptakan backlog ekstra 1,8 TB ketika kapasitas konsumen tetap pada status stabil. Jika laju pengejaran bersih pasca-lonjakan adalah 0,5 GB/s, pengurasannya memakan waktu sekitar satu jam secara teori. Jumlah partisi menggunakan nilai yang lebih besar dari perhitungan laju pesan dan laju byte, menambahkan ruang cadangan untuk kegagalan, dan dikalibrasi pada perangkat keras nyata.
Isi payload di atas 256 KiB pertama-tama masuk ke penyimpanan objek. Antrean menyimpan referensi yang immutable, ukuran, dan checksum. TTL sesi unggah menghapus objek orphan, sementara referensi yang telah di-commit melindungi objeknya selama jendela retensi, replay, dan dead-letter. Percobaan ulang mempertahankan ID pesan asli. Topik yang diurutkan secara ketat menjeda kunci atau partisi saat menemui poison message karena langsung memindahkannya ke dead-letter akan membiarkan pesan-pesan berikutnya mendahului.
Terakhir, saya akan membatasi ingress, egress, penyimpanan, partisi, dan objek besar per tenant; mengisolasi tenant yang panas di pool khusus; serta memantau latensi acknowledgment, publikasi yang tidak diketahui, lag replika, watermark disk, usia konsumen tertua, hot key, dan dead-letter. Uji kesalahan mencakup acknowledgment yang hilang, crash leader sebelum dan setelah commit, kegagalan zone, commit offset yang basi, crash konsumen setelah penulisan bisnis, dan kegagalan penyimpanan objek. Setiap pengujian memeriksa batasan acknowledgment yang spesifik."
Kesalahan Umum
- **Kesalahan: Hanya menggambar Produsen, Kafka, dan Konsumen → Kegagalan: Nama komponen tidak mendefinisikan batasan acknowledgment, offset,
urutan, atau kegagalan → Solusi: Nyatakan kontrak pengiriman dan empat invarian, lalu petakan setiap komponen ke dalamnya.**
- **Kesalahan: Menjanjikan urutan global saat melakukan penskalaan horizontal → Kegagalan: Urutan global membutuhkan satu titik keputusan serial,
sementara paralelisme partisi menghilangkan urutan tersebut → Solusi: Batasi cakupan pengurutan pada kunci bisnis dan partisi serta nyatakan batas hot-key.**
- **Kesalahan: Memberikan acknowledgment setelah penulisan disk lokal milik leader → Kegagalan: Kehilangan availability zone leader dapat menghapus
satu-satunya salinan yang durable → Solusi: Berikan acknowledgment setelah mayoritas commit lintas-zona tercapai dan pilih hanya replika yang memiliki prefiks yang telah di-commit.**
- **Kesalahan: Melakukan commit offset segera setelah fetch → Kegagalan: Crash setelah commit tersebut akan melewatkan hasil bisnis
secara permanen → Solusi: Lakukan commit hasil bisnis yang idempoten terlebih dahulu, lalu offset berikutnya, dan terima replay yang terkontrol.**
- **Kesalahan: Menyamakan exactly-once broker dengan efek eksternal exactly-once → Kegagalan: Sistem eksternal tidak bergabung dalam
transaksi broker, sehingga hilangnya acknowledgment masih menyisakan celah duplikasi → Solusi: Gunakan business idempotency key, unique constraint, kondisi versi, atau rekonsiliasi.**
- **Kesalahan: Langsung memindahkan setiap pesan yang gagal ke dead-letter → Kegagalan: Rekaman berikutnya untuk kunci yang sama dapat mendahuluinya dan merusak
urutan status → Solusi: Biarkan kontrak topik memilih antara menjeda kunci, menjeda partisi, atau konvergensi berbasis versi.**
- **Kesalahan: Menulis payload 100 MB langsung ke dalam log broker → Kegagalan: Beberapa rekaman memonopoli replikasi,
buffer, dan batch fetch → Solusi: Simpan isi pesan di penyimpanan objek dan catat referensi, ukuran, serta checksum-nya di log.**
- **Kesalahan: Merencanakan kuota dan kapasitas hanya berdasarkan jumlah pesan → Kegagalan: Rekaman 1 KB dan rekaman 100 MB memiliki
biaya jaringan, disk, dan memori yang sangat berbeda → Solusi: Ukur jumlah pesan, byte, batch in-flight, dan konkurensi objek.**
- **Kesalahan: Menambah konsumen untuk menghilangkan semua lag → Kegagalan: Satu anggota grup memiliki satu partisi pada satu waktu, dan hot key
tetap dibatasi oleh jalur partisi serial → Solusi: Periksa distribusi partisi dan kunci sebelum menambah partisi, membagi kunci bisnis, atau melakukan throttling.**
- **Kesalahan: Hanya memantau uptime broker → Kegagalan: Klaster yang aktif masih bisa mengalami replika yang tertinggal, disk habis,
offset basi, dan dead-letter yang menumpuk → Solusi: Pantau latensi tersegmentasi, prefiks yang di-commit, usia pesan tertua, waktu pengejaran, dan end-to-end canary.**
Pertanyaan Lanjutan dan Tanggapan
Pertanyaan Lanjutan 1: Bagaimana Anda menyediakan zero data loss lintas-wilayah sambil menjaga p99 publikasi di bawah 50 milidetik?
Acknowledgment lintas-wilayah yang sinkron menambah round-trip time jaringan area luas (WAN) ke jalur publikasi. Apakah 50 milidetik dapat dicapai bergantung pada jarak antar-wilayah dan latensi tail jaringan. Bisnis harus memprioritaskan antara RPO nol atau latensi lokal. Ketika RPO nol diprioritaskan, penulisan harus menunggu mayoritas commit jarak jauh dan SLO latensi harus disesuaikan kembali. Ketika latensi diprioritaskan, replikasi bersifat sinkron di dalam wilayah dan asinkron lintas-wilayah, dengan risiko eksplisit pada ekor data yang belum direplikasi. Sistem active-active juga membutuhkan satu pemilik untuk setiap kunci atau aturan resolusi konflik; wilayah utama (primary region) tunggal per topik atau rentang kunci biasanya mempertahankan urutan dengan lebih jelas.
Pertanyaan Lanjutan 2: Satu tenant memiliki satu kunci bisnis dengan 200.000 pesan per detik. Mengapa 128 partisi tidak membantu?
Kunci yang sama harus tetap berada di satu partisi untuk menjaga urutan, sehingga tetap dibatasi oleh kapasitas hasil benchmark satu partisi yaitu sekitar 40.000 pesan per detik. Pilihannya adalah mengoptimalkan jalur serial, membatasi (throttle) tenant tersebut, atau mendefinisikan ulang domain urutan yang independen, seperti kunci sub-entitas yang tidak saling memengaruhi. Jika bisnis memerlukan urutan total untuk kunci tersebut, layanan harus menolak janji performa di atas kapasitas serial. Menyebarkan kunci secara acak hanya menukar kegagalan kapasitas dengan kegagalan pengurutan.
Pertanyaan Lanjutan 3: Seorang konsumen telah menagih pembayaran lalu mengalami crash sebelum melakukan commit offset-nya. Bagaimana Anda mencegah penagihan ganda?
Gunakan message_id atau ID operasi bisnis sebagai payment idempotency key. Jika penyedia pembayaran mendukung API idempoten, pemutaran ulang menggunakan kunci yang sama dan meminta hasil asli. Jika hanya database lokal yang dikendalikan, lakukan commit status bisnis dan rekaman unik pesan-yang-diproses dalam satu transaksi, lalu gunakan pola outbox untuk langkah eksternal. Jika sistem eksternal tidak memiliki idempotensi maupun pencarian status, catat status UNKNOWN, lakukan rekonsiliasi, dan berikan kompensasi secara manual. Melakukan commit offset lebih awal hanya menyembunyikan ketidakpastian dengan membiarkan terjadinya kehilangan data.
Pertanyaan Lanjutan 4: Bagaimana cara melakukan redrive poison message dengan aman?
Perbaiki konsumen atau data terlebih dahulu, bekukan cakupan redrive, dan pertahankan ID pesan asli, offset sumber, waktu pertama kali dilihat, dan riwayat percobaan. Validasi versi baru dengan konsumsi bayangan (shadow consumption), lalu putar ulang pada laju per-tenant dan per-partisi sambil menjaga idempotensi sink tetap aktif. Topik yang diurutkan secara ketat juga menjeda rekaman berikutnya untuk kunci tersebut dan melanjutkan dari offset yang gagal secara berurutan. Jika kontrak mengizinkan penataan ulang, sink akan menolak versi bisnis yang lama. Redrive tidak boleh membuat ID baru untuk melewati deduplikasi atau membanjiri topik utama selama lonjakan lalu lintas normal.
Pertanyaan Lanjutan 5: Apa yang berubah pertama kali ketika retensi bertambah dari 24 jam menjadi 30 hari?
Pada status stabil, 30 hari adalah sekitar 86.4 × 30 = 2.592 PB secara logis. Menyimpan tiga replika lokal penuh memiliki batas bawah mendekati 7,776 PB, membuat biaya dan waktu pemulihan menjadi faktor dominan. Simpan segmen aktif dan terbaru di broker, dan unggah segmen tertutup yang telah diverifikasi ke penyimpanan objek. Metadata mencatat lokasi objek dan checksum; pengambilan historis menggunakan cache atau proksi baca. Penghapusan, pemutaran ulang, pemadatan (compaction), dan siklus hidup objek harus berbagi satu state machine retensi sehingga segmen lokal tidak pernah dihapus sebelum objek jarak jauhnya dapat dibaca.