Menguasai cara data masuk ke platform: perbedaan full load vs incremental load, Change Data Capture (CDC) dengan Debezium yang membaca perubahan dari database transaction log, teknik ingestion via API, dan praktik mengalirkan CDC dari database ke warehouse

Semua pipeline dimulai dari satu pertanyaan: bagaimana data masuk ke platform? Di episode 5 kalian menarik data dari API dengan Python, dan di episode 11 dari event stream. Episode ini membawa ingestion ke level profesional: kapan memakai full load, kapan incremental, dan bagaimana Change Data Capture (CDC) memungkinkan data dari database produksi hadir di warehouse hampir seketika.
Mengapa topik ini penting? Karena metode ingestion menentukan latency, beban pada sumber, dan biaya. Memuat ulang 2 juta baris setiap 5 menit hanya untuk 100 baris yang berubah adalah pemborosan — dan di sisi lain, melewatkan perubahan yang tidak terdeteksi adalah kehilangan data. Data engineer yang baik memilih metode yang tepat per sumber.
Memuat seluruh data dari sumber setiap kali. Karakteristiknya:
Hanya memuat data yang berubah sejak ekstraksi terakhir. Membutuhkan penanda (watermark) untuk melacak posisi. Tiga pendekatan umum:
| Pendekatan | Cara | Kelebihan | Kekurangan |
|---|---|---|---|
| Timestamp-based | Ambil baris dengan updated_at > last_run | Sederhana | Sumber harus punya kolom waktu update |
| CDC (transaction log) | Baca perubahan dari WAL/binlog | Lengkap & real-time | Perlu hak akses log |
| Diff/hash | Bandingkan hash seluruh baris | Menangkap perubahan apa pun | Mahal untuk tabel besar |
-- Simpan state watermark di tabel kecil
CREATE TABLE IF NOT EXISTS etl_state (
source TEXT PRIMARY KEY,
last_run TIMESTAMP
);
INSERT INTO staging.orders_inc
SELECT * FROM public.orders
WHERE updated_at > COALESCE(
(SELECT last_run FROM etl_state WHERE source = 'orders'),
'1970-01-01'
);
UPDATE etl_state SET last_run = now() WHERE source = 'orders';Pendekatan timestamp punya dua kelemahan serius: data yang dihapus tidak terdeteksi, dan kolom updated_at sering tidak akurat. CDC menyelesaikan keduanya dengan cara yang berbeda — ia membaca transaction log database (WAL di PostgreSQL, binlog di MySQL) yang mencatat setiap perubahan: insert, update, dan delete.
Keuntungan CDC:
updated_at.Debezium adalah platform CDC open-source yang membaca transaction log dan menerbitkan setiap perubahan sebagai event ke Kafka. Topologi klasiknya:
Menjalankan Debezium untuk PostgreSQL dengan Kafka Connect:
version: "3"
services:
connect:
image: quay.io/debezium/connect:3.0
environment:
BOOTSTRAP_SERVERS: kafka:9092
GROUP_ID: 1
CONFIG_STORAGE_TOPIC: connect_configs
OFFSET_STORAGE_TOPIC: connect_offsets
STATUS_STORAGE_TOPIC: connect_status
ports:
- "8083:8083"curl -i -X POST http://localhost:8083/connectors \
-H "Content-Type: application/json" \
-d '{
"name": "pg-orders-connector",
"config": {
"connector.class": "io.debezium.connector.postgresql.PostgresConnector",
"database.hostname": "postgres",
"database.port": "5432",
"database.user": "debezium",
"database.password": "dbz",
"database.dbname": "de_lab",
"topic.prefix": "debezium",
"plugin.name": "pgoutput",
"slot.name": "debezium_slot"
}
}'Setiap perubahan pada tabel orders kini muncul sebagai event JSON di topic debezium.public.orders — lengkap dengan metadata operasi:
{
"op": "u",
"before": { "order_id": 42, "status": "pending", "amount": 25000 },
"after": { "order_id": 42, "status": "completed", "amount": 25000 }
}Field op menandai operasi: c (create), u (update), d (delete). before/after memuat nilai lama dan baru. Inilah bahan mentah untuk sinkronisasi incremental yang akurat.
Warning
Debezium pada PostgreSQL memakai replication slot — slot yang tidak dikonsumsi akan membuat WAL membengkak dan memenuhi disk. Pastikan ada monitoring slot (pembahasan lengkap di episode 20) dan kebijakan clean-up yang jelas sebelum menjalankan di produksi.
Consumer membaca event CDC dan menerapkannya ke tabel warehouse — biasanya dengan MERGE di lakehouse (episode 10):
from confluent_kafka import Consumer
import json, psycopg2
c = Consumer({
"bootstrap.servers": "localhost:9092",
"group.id": "cdc-warehouse",
"auto.offset.reset": "earliest",
})
c.subscribe(["debezium.public.orders"])
conn = psycopg2.connect(host="localhost", user="de", password="secret", dbname="de_lab")
while True:
msg = c.poll(1.0)
if msg is None:
continue
evt = json.loads(msg.value())
op, after = evt.get("op"), evt.get("after")
if op == "c":
with conn.cursor() as cur:
cur.execute(
"INSERT INTO silver.orders VALUES (%s,%s,%s,%s)",
(after["order_id"], after["status"], after["amount"], after["created_at"]),
)
conn.commit()
elif op == "d":
with conn.cursor() as cur:
cur.execute("DELETE FROM silver.orders WHERE order_id = %s", (evt["before"]["order_id"],))
conn.commit()Kerangka keputusan yang bisa kalian pakai:
updated_at yang andal → incremental berbasis timestamp.Full load untuk tabel besar. Biaya dan beban sumber tidak sebanding dengan manfaatnya. Pindah ke incremental.
Timestamp watermark tanpa update kolom. Jika aplikasi tidak mengupdate updated_at, baris berubah tapi tak terdeteksi. Verifikasi integritas watermark.
CDC tanpa penanganan delete. Hanya mengerjakan insert/update tapi mengabaikan op: d membuat data warehouse menahan data yang sudah dihapus di sumber.
Replication slot terlupakan. WAL membengkak, disk penuh, database produksi berhenti. Monitor slot sejak hari pertama.
Di episode 12 ini kalian telah menguasai ingestion profesional:
op/before/after.Di episode 13 selanjutnya kita naik level orkestrasi: orkestrasi & scheduling lanjutan — Airflow advanced (sensors, retries, backfills), perbandingan dengan Dagster dan Prefect, dan praktik membangun pipeline production-grade. Sampai jumpa di episode 13!