Belajar Debezium - Change Event Handling Patterns
Episode 18 of 23

Belajar Debezium - Change Event Handling Patterns

Episode ini membahas memodelkan insert, update, dan delete di sistem downstream, menangani event out-of-order dan konsumen idempotent, compaction, deduplikasi, dan pola upsert, serta membangun materialized views dan sistem CQRS.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

Mengonsumsi event CDC adalah satu hal; memodelkannya dengan benar di sistem downstream adalah hal lain. Event dengan op yang sama bisa berarti hal berbeda tergantung state sistem penerima. Episode 18 ini membahas pola penanganan event: insert, update, delete, urutan yang kacau, duplikasi, dan cara membangun tampilan terkini dari aliran perubahan.

Inti masalahnya adalah ini: Kafka menjamin urutan per partisi, bukan at-least-once delivery. Artinya konsumen harus siap menghadapi event duplikat dan event yang sama dibaca lebih dari sekali. Semua pola di episode ini berakar pada kenyataan tersebut.

Memodelkan Insert, Update, dan Delete di Downstream

Setiap op memiliki makna dan aksi yang berbeda:

  • c — insert: tambahkan record baru.
  • u — update: timpa record yang ada.
  • d — delete: hapus record, dan perhatikan tombstone.
  • r — read: hasil snapshot, perlakukan seperti upsert.

Untuk delete, Debezium mengirim dua event: yang pertama value berisi op: d dengan before, lalu tombstone dengan value null pada key yang sama. Tombstone diperlukan untuk mendukung kompaksi topic. Konsumen harus siap menerima value null dan tidak crash saat itu terjadi.

Membaca tombstone di topic
docker exec -it kafka /opt/kafka/bin/kafka-console-consumer.sh \
  --bootstrap-server localhost:9092 \
  --topic dbserver1.inventory.customers \
  --property print.value=false

Konsumen yang benar memperlakukan op: d sebagai hapus, lalu mengabaikan tombstone null yang menyusul.

Menangani Event Out-of-Order dan Konsumen Idempotent

Karena konsumen bisa membaca event lebih dari sekali, operasi tulis harus idempotent: menjalankan operasi yang sama dua kali memberi hasil yang sama. Dua strategi dasar:

  • Upsert dengan primary key: menulis dengan INSERT ... ON CONFLICT ... DO UPDATE sehingga update ganda aman.
  • Versioning: simpan source.ts_ms atau posisi log di record target dan tolak event yang lebih lama.

Untuk event yang datang tidak berurutan lintas partisi, kunci perbandingan source.ts_ms menentukan urutan logis. Sink JDBC dengan insert.mode: upsert dan pk.fields otomatis memenuhi prinsip idempotensi ini.

Compaction, Deduplikasi, dan Upsert

Log compaction adalah fitur Kafka yang menjaga nilai terakhir untuk setiap key. Aktifkan pada topic yang mewakili state, bukan aliran kejadian:

Mengaktifkan compaction pada topic
docker exec -it kafka /opt/kafka/bin/kafka-topics.sh \
  --bootstrap-server localhost:9092 \
  --alter --topic dbserver1.inventory.customers \
  --config cleanup.policy=compact

Dengan cleanup.policy=compact, Kafka menyimpan nilai terbaru per key dan membuang yang lama saat segmen di-compact. Tombstone yang dikirim Debezium ikut menghapus key saat compaction, sehingga state tersimpan akurat.

Gabungkan compaction dengan pola upsert untuk membangun state store yang selalu sinkron dengan database sumber.

Membangun Materialized Views dan CQRS

Materialized view adalah representasi state yang diperbarui terus menerus dari event. Ada dua pendekatan:

  • Aggregasi streaming: ksqlDB atau Kafka Streams mengagregasi event menjadi tampilan terkini.
  • State store: konsumen menerapkan event ke state lokal yang bisa di-query.
PythonMaterialized view dengan ksqlDB
CREATE TABLE customer_state AS
  SELECT id, LATEST_BY_OFFSET(first_name) AS first_name,
               LATEST_BY_OFFSET(email) AS email
  FROM customers_stream
  GROUP BY id
  EMIT CHANGES;

Tabel customer_state menampilkan state terakhir setiap customer. Pola ini juga menjadi dasar CQRS: sisi command menulis ke database sumber, event CDC mengalir, dan sisi query membaca dari materialized view — pemisahan beban baca dan tulis yang bersih.

Menangani Snapshot Ulang dan Event Berulang

Saat incremental snapshot dijalankan ulang (episode 4), konsumen akan menerima kembali event op: r untuk data yang sudah ada. Karena alasan inilah konsumen harus memperlakukan event snapshot seperti upsert, bukan insert polos. Menerapkan op: r dengan INSERT ... ON CONFLICT DO UPDATE menjaga state tetap konsisten tanpa duplikasi.

PythonUpsert yang aman untuk event snapshot
INSERT INTO customers (id, first_name, email)
VALUES (?, ?, ?)
ON CONFLICT (id) DO UPDATE
SET first_name = EXCLUDED.first_name,
    email = EXCLUDED.email;

Query ON CONFLICT (id) DO UPDATE di atas bekerja untuk event c, u, dan r sekaligus. Dengan satu bentuk penulisan, konsumen tidak perlu memilah-milah jenis operasi untuk aksi tulis.

Menguji Ketahanan Konsumen

Pola penanganan event tidak berguna jika tidak diuji. Latihan yang disarankan:

  • Kirim event duplikat dan pastikan hasil akhir tetap sama.
  • Kirim event out-of-order dan pastikan versioning menolak yang lebih lama.
  • Hapus record dan pastikan tombstone diproses tanpa error.
  • Picu snapshot ulang dan pastikan tidak ada duplikasi di state store.

Jadikan skenario ini bagian dari test pipeline sehingga perubahan kode tidak merusak perilaku yang sudah benar.

Penutup

Episode 18 membahas pola penanganan event yang benar: memetakan op ke aksi downstream, menghadapi tombstone dan duplikasi dengan konsumen idempotent, memakai compaction untuk state, dan membangun materialized views serta CQRS dari aliran perubahan.

Inti yang harus dibawa pulang:

  • Insert, update, delete, dan read memetakan ke aksi downstream yang berbeda.
  • Tombstone dengan value null menyertai delete dan dibutuhkan untuk kompaksi.
  • Konsumen harus idempotent karena delivery Kafka bersifat at-least-once.
  • Log compaction menjaga nilai terakhir per key pada topic state.
  • Materialized views dan CQRS memisahkan jalur tulis dan baca secara alami.

Di episode 19 selanjutnya kita akan membahas operational readiness dan runbooks — menyusun runbook untuk kegagalan connector, snapshot restart, dan data replay, incident response untuk lag dan schema issues, serta backup konfigurasi dan offset.

Belajar Debezium - Change Event Handling Patterns | Belajar Debezium