Real-time Analytics Pipeline — Data Engineering

Real-time Analytics Pipeline Untuk use case yang membutuhkan analitik dalam hitungan detik (live dashboard, alerting, fraud detection), kamu butuh database…

Real-time analytics pipeline adalah jalur yang membawa tiap kejadian di aplikasi sampai jadi angka di dashboard dalam hitungan detik, bukan besok pagi. Bayangin papan skor di GOR waktu pertandingan bulutangkis. Tiap poin langsung muncul di papan, karena ada petugas yang menonton lapangan dan menambah angkanya saat itu juga. Rekap resmi pertandingan baru keluar setelah selesai. Kalau petugas papan skor ragu apakah poin tadi sudah dia catat, lalu mencatatnya lagi, skornya salah di depan semua penonton. Pipeline real-time adalah petugas papan skor itu, dan pelajaran ini membahas cara supaya dia gak mencatat dua kali.

🧪 Tebakan cepat: Sabtu 10:15:30 Siti membeli 1 Bumi Manusia (pesanan 15). Consumer menyimpan event-nya ke tabel dashboard, lalu mati sebelum sempat commit offset Kafka. Setelah hidup lagi, "Terjual hari ini" bilang 1 atau 2? Tebak dulu, jawabannya ada di bagian "At-least-once dan sink yang idempoten".

Dari checkout ke dashboard

Pertanyaan pemilik kali ini beda: bukan "paling laku per minggu", tapi "berapa buku terjual hari ini, sekarang?". Jalurnya menyambung pelajaran-pelajaran sebelumnya:

Tahap Tugasnya Di Toko Buku
Sumber aplikasi menulis pesanan MySQL, tabel order_items
CDC membaca tiap perubahan dari binlog Debezium 3.7 (pelajaran CDC)
Broker menyimpan event berurutan topic Kafka tokobuku.toko_buku.order_items (pelajaran Kafka)
Stream processor menghitung terus-menerus consumer kecil, atau Flink, Kafka Streams, RisingWave, Materialize
Serving store tempat dashboard bertanya Postgres; untuk data besar ClickHouse, Druid, Pinot
Dashboard menampilkan angkanya Metabase, Superset, Grafana

Di Lab, 22 event mengalir lewat jalur ini: 19 baris pesanan (op = c, insert), lalu tiga perubahan hari Sabtu dari pelajaran CDC: item 9 yang dobel dihapus jam 09:00 (d), harga item 16 dibetulkan (u), dan item 20 milik Siti masuk jam 10:15:30 (c).

Stream processor: siapa yang menghitung

Stream processor adalah program yang nyala terus, membaca event begitu datang, dan memperbarui hasil hitungannya. Pilihan yang dipakai orang per Oktober 2026:

-- RisingWave atau Materialize: order_items di sini tabel yang diisi dari CDC
CREATE MATERIALIZED VIEW terjual_harian AS
SELECT CAST(created_at AS DATE) AS tanggal, SUM(qty) AS buku
FROM order_items
GROUP BY CAST(created_at AS DATE);

Di PostgreSQL biasa, materialized view yang sama baru berubah kalau kamu menjalankan REFRESH MATERIALIZED VIEW. Di database streaming, insert, update, dan delete dari CDC langsung mengubah angkanya.

Pilihan paling sederhana, dan yang dimodelkan Lab: consumer kecil (misalnya Python dengan kafka-python dari pelajaran Kafka) yang menulis tiap event ke tabel Postgres, lalu dashboard menjalankan SELECT.

Jendela menurut waktu pesanan

Stream gak pernah selesai, jadi "jumlahkan semuanya" gak bisa. Windowing artinya mengelompokkan event menurut rentang waktu (tiap 5 menit, tiap jam, tiap hari) lalu menjumlah per rentang itu. "Hari ini" adalah jendela tumbling 1 hari dari pelajaran Streaming vs Batch: potongan tetap, tiap pesanan masuk tepat satu hari. Yang menentukan harinya adalah event time, yaitu created_at pesanan, bukan jam event sampai di consumer. Hasil dashboard setelah 22 event, dari SQLite di Lab:

tanggal buku
2026-09-28 3
2026-10-01 3
2026-10-09 1
2026-10-10 1

(8 hari lain dipendekkan; 3 Oktober gak muncul karena gak ada penjualan.) Sebelum Sabtu, 1 Oktober tertulis 5: item 9 yang dobel ikut terhitung. Event hapus jam 09:00 hari Sabtu membetulkan jendela 1 Oktober, bukan jendela Sabtu, karena barisnya milik pesanan 1 Oktober. Stream dari CDC bukan cuma tambahan: ada update dan delete yang mengubah jendela lama.

Jendela lain dari pelajaran itu tetap berlaku. Sliding 24 jam terakhir pada Sabtu 10:16 berisi 2 buku (pesanan 14 hari Jumat 10:30 masih masuk). Dan event yang datang telat tetap masalah: di pelajaran Streaming vs Batch, minggu 28 September keluar 12 buku tanpa waktu tunggu watermark, 13 dengan waktu tunggu 12 jam.

Serving store: tempat dashboard bertanya

At-least-once dan sink yang idempoten

Consumer di Lab commit offset tiap 5 event. Setelah event ke-22 (offset 21), commit terakhir ada di offset 19. Kalau consumer mati di sini, penggantinya membaca ulang offset 20 dan 21. Ini at-least-once dari pelajaran Kafka: event bisa datang dua kali, gak ada yang hilang. Yang menentukan hasilnya adalah sink, cara consumer menulis ke serving store.

Sink yang menambah:

INSERT INTO terjual_harian (tanggal, buku) VALUES ('2026-10-10', 1)
ON CONFLICT (tanggal) DO UPDATE SET buku = buku + excluded.buku;

Sink yang menulis satu baris per item (upsert), lalu dashboard menjumlah:

INSERT INTO item_live (item_id, tanggal, qty) VALUES (20, '2026-10-10', 1)
ON CONFLICT (item_id) DO UPDATE SET tanggal = excluded.tanggal, qty = excluded.qty;
-- event d: DELETE FROM item_live WHERE item_id = 9;

SELECT tanggal, SUM(qty) AS buku FROM item_live GROUP BY tanggal ORDER BY tanggal;

Hasil setelah consumer mati dan event offset 20 dan 21 dibaca ulang: sink yang menambah bilang 2 buku hari ini, upsert bilang 1. Itu jawaban tebakannya: tergantung sink-nya, dan yang benar cuma yang idempoten.

Exactly-once artinya tiap event berpengaruh tepat sekali. Flink mencapainya di dalam dirinya dengan checkpoint: state dan offset Kafka disimpan bersama, dan setelah crash keduanya dikembalikan bersama. Kafka Streams punya processing.guarantee=exactly_once_v2, tapi itu berlaku untuk tulis ke Kafka sendiri. Begitu hasilnya ditulis ke database lain, baris yang sudah masuk sesudah checkpoint terakhir bisa tertulis lagi. Jadi sampai ke dashboard, exactly-once butuh sink transaksional atau sink yang idempoten. Yang kedua jauh lebih sederhana.

Biaya, dan apakah Toko Buku butuh ini

Jujur: belum. Toko Buku punya 1 sampai 3 pesanan sehari. Jalur di atas berarti Kafka, Kafka Connect dengan Debezium, dan prosesor yang semuanya nyala 24 jam, dimonitor, di-upgrade, dan dibayar tiap bulan, untuk angka yang berubah tiga kali sehari. Pertanyaan pemilik bisa dijawab dengan satu query ke read replica (salinan database yang khusus dibaca), dijalankan dashboard tiap beberapa menit:

SELECT COALESCE(SUM(oi.qty), 0) AS terjual_hari_ini
FROM order_items oi
JOIN orders o ON o.id = oi.order_id
WHERE o.created_at >= CURDATE();

Real-time layak kalau ada keputusan yang harus diambil dalam detik: menahan pembayaran yang mencurigakan, mengunci stok saat flash sale, membunyikan alarm saat checkout gagal beruntun. Atau kalau query langsung ke database sudah terlalu berat karena datanya besar.

⚠️ Jebakan yang sering ketemu

TL;DR: Pipeline real-time Toko Buku: MySQL, Debezium (CDC), Kafka, stream processor, serving store, dashboard. Prosesornya bisa consumer kecil, Flink 2.3 (state + checkpoint), Kafka Streams (library di Kafka 4.3), atau database streaming RisingWave 3.1 dan Materialize yang memperbarui CREATE MATERIALIZED VIEW tiap event. Serving store-nya Postgres untuk data kecil, ClickHouse, Druid, atau Pinot untuk data besar. "Hari ini" adalah jendela tumbling 1 hari menurut waktu pesanan (event time), dan event d membetulkan jendela lamanya (1 Oktober dari 5 jadi 3). Kafka memberi at-least-once, jadi event bisa datang dua kali: sink yang menambah bilang 2, upsert per item_id yang idempoten tetap 1. Exactly-once Flink berlaku di dalam Flink; sampai ke database perlu sink idempoten atau transaksional. Untuk 1 sampai 3 pesanan sehari, query ke read replica tiap beberapa menit sudah cukup.

Yang akan kamu pelajari