Topik dan Peran yang Berlaku
Database produk adalah sumber kebenaran tunggal (source of truth) untuk pencarian. Rancang pipeline CDC mendekati waktu nyata (near-real-time) yang menyinkronkan operasi insert, update, dan delete secara andal ke indeks pencarian. Pipeline ini harus mendukung snapshot awal, catch-up, pengiriman duplikat, gangguan konsumen, evolusi skema, dan rebuild indeks. Jelaskan bagaimana Anda membuktikan bahwa tidak ada event yang hilang dan event yang lebih lama tidak dapat menimpa event yang lebih baru.
Topik ini cocok untuk wawancara backend, infrastruktur data, platform pencarian, dan desain sistem. Asumsikan sumber dapat mengekspos urutan commit atau posisi log yang setara, dan indeks pencarian adalah sistem turunan yang dapat dibangun ulang. Kafka, Debezium, dan Elasticsearch adalah opsi, bukan persyaratan wajib; tentukan semantik dan batasan kegagalan terlebih dahulu.
Apa yang Diuji oleh Pewawancara
Pewawancara ingin melihat apakah Anda memisahkan antara "penulisan database telah di-commit" dan "indeks akhirnya terlihat," dengan kontrak yang dapat diobservasi untuk setiap tahap. Jawaban yang kuat mendefinisikan kunci event, operasi, transaksi atau posisi log, dan versi skema; memilih penangkapan berbasis log alih-alih polling timestamp yang tidak aman; serta menangani tumpang tindih snapshot, replay at-least-once, pengurutan per kunci, tombstone penghapusan, dan pengalihan alias. Diagram yang hanya berisi database, antrean, dan kotak pencarian tidak dapat membuktikan keandalan tanpa checkpoint, replay, dan aturan rekonsiliasi.
Pertanyaan Klarifikasi Sebelum Menjawab
- Berapa target pembaruan data (freshness target)? Lima detik setelah commit atau beberapa menit? Hal ini menentukan batas buffering, peringatan (alert), dan fallback.
- Pengurutan seperti apa yang diperlukan? Biasanya satu produk harus mengikuti urutan commit sumber; urutan global di seluruh produk tidak diperlukan. Invarian lintas tabel mungkin memerlukan event gabungan (aggregate).
- Apakah penghapusan bersifat hard delete atau soft delete? Hard delete memerlukan tombstone yang tahan lama atau event delete; soft delete memerlukan aturan visibilitas di dalam dokumen yang diindeks.
- Apakah operasi penulisan boleh berlanjut selama snapshot? Jika ya, tentukan posisi snapshot dan pertahankan perubahan setelah posisi tersebut untuk mencakup jendela snapshot.
- Bagaimana skema berevolusi? Bisakah konsumen lama mengabaikan field yang baru ditambahkan? Apakah field yang dihapus atau diubah tipenya memerlukan dual read/write, versi event baru, atau rebuild?
- Apakah rebuild harus tanpa downtime (zero-downtime)? Jika ya, tulis ke indeks baru, alihkan alias secara atomik, dan pertahankan titik replay untuk konsumen lama.
Kerangka Jawaban 30 Detik
"Saya akan memperlakukan database utama sebagai sumber kebenaran dan menangkap operasi insert, update, dan delete yang telah di-commit dari log-nya. Setiap event membawa kunci, operasi, LSN sumber, ID transaksi, versi skema, serta nilai sebelum/sesudah. Pemuatan awal dimulai dari snapshot yang konsisten sambil mencatat posisi log-nya; event setelah posisi tersebut dilanjutkan melalui aliran data (stream) replayable yang sama, dan konsumen menulis secara idempoten berdasarkan kunci produk.
Pengiriman bersifat at-least-once. Checkpoint hanya dimajukan setelah efek samping penulisan pada indeks berhasil, dan event duplikat ditolak oleh kondisi kunci ditambah versi atau LSN. Konsumen yang terhenti akan melanjutkan proses dari checkpoint-nya. Saya akan mengekspos metrik lag, umur event tertua, retensi slot, dan sampel versi database-ke-indeks. Proses rebuild menulis stream yang sama ke indeks baru, menunggu hingga mengejar ketertinggalan (catch up), lalu mengalihkan alias secara atomik."
Pembahasan Mendalam Langkah demi Langkah
Langkah 1: Tentukan kontrak event dan batasan penangkapan
CDC berbasis log membaca perubahan database yang telah di-commit dan mempertahankan urutan sumber atau posisi log. Di PostgreSQL, logical decoding mengekstrak perubahan dari WAL, dan replication slot merepresentasikan stream yang dapat diputar ulang sesuai urutan asalnya. Slot mempertahankan WAL yang dibutuhkan, sehingga retensi slot harus dipantau; konektor yang macet dapat menghabiskan ruang disk database utama.
Setiap event harus menyertakan entity_id, operation, source_position, transaction_id, schema_version, before, dan after. Gunakan source_position untuk audit dan deduplikasi, bukan waktu kedatangan pesan sebagai urutan bisnis. Jika satu transaksi mengubah beberapa produk, putuskan apakah indeks boleh mengeksposnya satu per satu atau apakah stream harus menggabungkannya pada batas transaksi.
Langkah 2: Hubungkan snapshot dan stream dengan satu posisi
Tumpang tindih yang berbahaya terjadi ketika snapshot membaca baris lama sementara stream mengirimkan event yang lebih baru untuk kunci yang sama. Catat posisi log P0 saat snapshot dimulai. Dokumen snapshot merepresentasikan status pada awal proses; event setelah P0 tetap tersedia dan diterapkan setelah hasil snapshot selesai.
P0 = captureSourcePosition()
startStreaming(after=P0)
for row in consistentSnapshot():
indexUpsert(row, version=P0)
for event in stream:
if event.position > indexedVersion[event.key]:
applyIdempotently(event)
checkpoint(event.position) # only after index write succeedsKonektor di dunia nyata dapat menggunakan jendela snapshot, chunk primary-key, dan buffer untuk menyelesaikan tabrakan antara event READ dan UPDATE. Dalam wawancara, jelaskan bahwa ini mencegah baris snapshot lama menimpa update yang sudah di-commit; "memulai stream setelah snapshot selesai" tidaklah cukup.
Langkah 3: Perjelas pengurutan, idempotensi, dan pemulihan
Lakukan partisi berdasarkan entity_id agar event dari satu produk mempertahankan urutan sumber sementara produk yang berbeda berjalan secara paralel. Gunakan versi eksternal, conditional write, atau dokumen berversi sehingga suatu event hanya dapat menimpa posisi yang lebih lama. DELETE menuliskan tombstone atau penghapusan berversi dan mempertahankan metadata yang cukup untuk mencegah UPDATE yang terlambat membangkitkan kembali dokumen tersebut.
Checkpoint berarti "efek samping untuk event ini telah selesai secara persisten." Jangan lakukan commit checkpoint tepat setelah menarik pesan atau mengirim permintaan HTTP. Kegagalan sistem (crash) setelah penulisan indeks tetapi sebelum checkpoint akan menyebabkan duplikasi, sehingga penulisan target harus idempoten. Jika checkpoint dimajukan sebelum penulisan indeks, data akan hilang; tentukan batas commit yang dapat diverifikasi atau gunakan proses indeks replayable ditambah rekonsiliasi.
Langkah 4: Tangani replay, evolusi skema, dan rebuild
Berikan setiap konsumen slot independen atau pelacakan progres yang setara, daripada membiarkan konsumen bersaing memperebutkan satu kursor konsumen tunggal. Sebelum replay, bekukan atau beri label kebijakan versi pada indeks target, batasi rentang replay, dan pastikan event lama hanya dapat menulis versi yang lebih lama. Tentukan aturan kompatibilitas: konsumen lama sering kali dapat mengabaikan field opsional yang baru ditambahkan, sementara field yang dihapus atau diubah tipenya mungkin memerlukan versi event baru, dual read/write, atau reindexing.
Jangan mengosongkan indeks aktif untuk proses rebuild. Buat indeks baru dan lakukan replay dari posisi snapshot yang sama hingga posisi penerapannya mencapai ambang cutover. Alihkan alias secara atomik dan lanjutkan konsumsi dari stream yang sama. Jika cutover gagal, pertahankan alias lama dan progres indeks baru, perbaiki masalahnya, lalu kejar ketertinggalan lagi; jangan menebak-nebak titik awal baru.
Langkah 5: Buktikan keandalan dengan metrik dan rekonsiliasi
Lacak latensi baca CDC, backlog partisi, umur event tertua, retensi WAL pada slot, checkpoint setiap konsumen, kegagalan penulisan indeks, percobaan ulang (retry), dead letter, dan perbedaan versi dari sampel primary key di database dan indeks. Operasi penghapusan harus memiliki penghitung tombstone dan dokumen residual tersendiri.
Uji dengan menghentikan konsumen, menduplikasi pengiriman, mengubah urutan pesan lintas partisi, memperbarui kunci selama snapshot, mengirimkan delete yang terlambat, mengubah skema, dan melakukan failover database utama. Alat rekonsiliasi harus membaca ulang versi database saat ini, memutar ulang stream ke posisi yang dipilih, dan mengeluarkan sampel inkonsistensi terkecil. Antrean yang kosong saja tidak membuktikan bahwa tidak ada event yang terlewat atau tidak ada penulisan indeks yang gagal.
Contoh Jawaban Berkualitas Tinggi
"Pertama-tama saya akan mendefinisikan kontraknya: database bersifat otoritatif dan indeks dapat dibangun ulang; targetnya adalah data dapat dicari dalam lima detik setelah commit, dengan urutan sumber dipertahankan per produk tanpa pengurutan global di seluruh produk. Event membawa kunci, insert/update/delete, LSN, ID transaksi, versi skema, dan nilai sebelum/sesudah.
Saya akan menggunakan CDC berbasis log. Pada awal snapshot, saya mencatat P0 dan terus mengonsumsi setelah P0. Operasi READ snapshot dapat bertabrakan dengan UPDATE stream, sehingga jendela snapshot atau aturan versi kunci yang setara harus membuang READ yang basi; sekadar memulai stream setelah snapshot selesai akan meninggalkan celah data. Konsumen melakukan partisi berdasarkan kunci dan menggunakan versi eksternal atau conditional write. Penghapusan mempertahankan versi tombstone sehingga update yang terlambat tidak dapat membangkitkan kembali dokumen.
Checkpoint hanya dimajukan setelah efek samping penulisan pada indeks berhasil. Oleh karena itu, crash akan menghasilkan replay at-least-once, yang harus ditoleransi oleh target secara idempoten. Saat konektor down, saya memantau WAL yang ditahan oleh slot; setelah pemulihan, proses dilanjutkan dari posisi aman terakhir. Untuk rebuild, saya menulis stream yang sama ke indeks baru, menunggu hingga mengejar ketertinggalan, dan mengalihkan alias secara atomik.
Penerimaan sistem memerlukan bukti lebih dari sekadar antrean kosong. Saya menyuntikkan update selama snapshot, duplikasi dan pengacakan urutan, penghapusan yang terlambat, crash konsumen, perubahan skema, dan failover utama. Kemudian saya membandingkan versi database, versi indeks, dan checkpoint berdasarkan kunci. Sinyal utamanya adalah umur event tertua, retensi WAL, lag indeks, dead letter, dan sampel inkonsisten; celah data apa pun harus dapat diputar ulang dari posisi log yang tersimpan."
Kesalahan Umum
- Melakukan polling timestamp pembaruan sebagai CDC → presisi jam, pergeseran waktu, dan transaksi panjang dapat menyembunyikan perubahan → baca commit log atau gunakan kursor yang dapat dibuktikan.
- Memulai snapshot dan stream secara terpisah → baris snapshot lama dapat menimpa event baru → catat P0 dan selesaikan tabrakan READ/UPDATE.
- Memajukan checkpoint segera setelah mengirim permintaan indeks → rentang waktu sebelum crash dapat menghilangkan data → majukan hanya setelah efek samping penulisan diverifikasi.
- Memperlakukan at-least-once sebagai exactly-once → duplikasi masih dapat terjadi → gunakan penulisan versi kondisional dan penghapusan idempoten.
- Mengurutkan berdasarkan waktu kedatangan pesan → percobaan ulang (retry) mengacaukan urutan di jaringan → partisi berdasarkan kunci dan gunakan LSN atau versi sumber.
- Menghapus dari indeks tanpa tombstone berversi → update yang terlambat membangkitkan kembali dokumen → pertahankan metadata versi penghapusan.
- Berbagi satu replication slot di antara beberapa konsumen independen → satu konsumen dapat mengonsumsi perubahan yang tidak pernah diterima konsumen lain → gunakan satu slot per konsumen atau lapisan siaran (broadcast) eksplisit.
- Mengosongkan indeks aktif untuk rebuild → replay yang gagal akan menyebabkan pemadaman (outage) pencarian besar-besaran → kejar ketertinggalan pada indeks baru lalu alihkan alias secara atomik.
- Menggunakan antrean kosong sebagai bukti keandalan → event yang terlewat atau penulisan yang gagal juga bisa meninggalkan antrean kosong → rekonsiliasi posisi, versi, dan sampel data utama.
Pertanyaan Lanjutan dan Jawaban
Pertanyaan Lanjutan 1: Bisakah indeks mengekspos transaksi yang memperbarui produk dan inventarisnya baris demi baris?
Bisa, jika bisnis dapat menerima status pencarian perantara. Jika hasil pencarian harus mencerminkan keduanya secara bersamaan, bawa batasan transaksi dan lakukan agregasi sebelum memperbarui dokumen, atau bangun satu proyeksi pencarian yang sudah di-commit. Penulisan yang 'hampir bersamaan' di seluruh indeks tidaklah atomik.
Pertanyaan Lanjutan 2: Pemadaman yang lama membuat replication slot menahan terlalu banyak WAL. Bagaimana Anda menanganinya?
Lindungi database utama terlebih dahulu: buat peringatan, batasi penulisan lebih lanjut atau turunkan kinerja konsumen, dan verifikasi bahwa slot masih memiliki posisi awal yang dapat digunakan. Jika slot tidak valid, jangan buat slot baru lalu berasumsi kontinuitas terjaga; LSN yang terlewat mungkin sudah hilang. Bangun ulang dari cadangan (backup) atau snapshot penuh, lalu rekonsiliasi celah datanya.
Pertanyaan Lanjutan 3: Stream hanya diurutkan di dalam partisi. Bagaimana Anda memberi peringkat hasil pencarian di seluruh produk?
Pencarian membaca versi indeks saat ini dan tidak boleh mengasumsikan urutan event global. Jika field pemeringkatan memerlukan waktu yang konsisten, gunakan waktu commit sumber ditambah aturan versi, atau gunakan agregator untuk menghasilkan rank key yang stabil dengan toleransi deviasi waktu (temporary-skew budget) yang eksplisit. Pengurutan global lintas partisi mengurangi throughput dan harus memiliki justifikasi kuat dari invarian produk.
Pertanyaan Lanjutan 4: Apa yang terjadi pada indeks lama ketika suatu field skema dihapus?
Pertama, terapkan konsumen yang dapat membaca kedua versi event, lalu hentikan pengiriman field lama, pastikan backlog dan jendela replay sudah bersih, dan terakhir migrasikan pemetaan (mapping) atau lakukan rebuild. Jika field tersebut mengubah otorisasi atau makna analitis, menghapus properti JSON saja tidak cukup; pertahankan event berversi dan jalur rollback.