Dashboard operasional menuntut angka yang segar, sementara laporan keuangan menuntut angka yang final dan bisa diaudit. Kedua tuntutan tersebut bertabrakan pada satu platform: recompute penuh akurat tetapi lambat, sedangkan pemrosesan increment cepat tetapi hasilnya sementara. Lambda architecture, diperkenalkan Nathan Marz dalam buku Big Data, menyelesaikan benturan dengan menjalankan dua kecepatan sekaligus: batch layer yang menghitung ulang seluruh sejarah, dan speed layer yang hanya mengolah event terbaru. Serving layer kemudian menjumlahkan keduanya sehingga pengguna mendapat angka yang sekaligus segar dan benar.
Dua Kecepatan, Satu Kebenaran #
Lambda membangun seluruh sistem di atas satu log event yang hanya bertambah (append-only) — konsep yang sudah kita kenal di chapter Apache Kafka. Batch layer membaca seluruh log dan menghitung ulang batch view secara berkala; hasilnya tertinggal beberapa jam tetapi selalu benar karena dihitung dari data lengkap. Speed layer hanya mengolah event yang tiba setelah batch terakhir berjalan; hasilnya segar dalam hitungan detik, tetapi bersifat sementara sampai batch berikutnya menyerapnya.
Perbandingan karakteristik kedua layer:
| Aspek | Batch Layer | Speed Layer |
|---|---|---|
| Cakupan bacaan | seluruh sejarah log | event setelah batch terakhir |
| Latensi hasil | jam | detik sampai menit |
| Sifat hasil | final dan akurat | sementara, digantikan batch |
| Pola biaya | mahal per run, jarang jalan | murah per event, jalan terus |
| Kelemahan | tertinggal | rawan keliru saat logika berubah |
Simulasi Tiga Layer dengan DuckDB #
Kita simulasikan Lambda dengan DuckDB: sepuluh event penjualan dari tiga kota mengalir ke satu log, dan batch terakhir selesai pukul 08:00. Baris pencetakan statistik dipangkas dari tampilan; inti ketiga layer berikut:
import duckdb
con = duckdb.connect()
# --- Log event yang hanya bertambah (immutable, append-only) ---
con.execute("""
CREATE TABLE event_log AS
SELECT * FROM (VALUES
('2026-01-15 06:05', 'jakarta', 120000),
('2026-01-15 06:40', 'bandung', 60000),
('2026-01-15 07:15', 'surabaya', 90000),
('2026-01-15 07:50', 'jakarta', 75000),
('2026-01-15 08:05', 'bandung', 110000),
('2026-01-15 08:30', 'jakarta', 45000),
('2026-01-15 09:10', 'surabaya', 130000),
('2026-01-15 09:45', 'bandung', 55000),
('2026-01-15 10:05', 'jakarta', 200000),
('2026-01-15 10:55', 'surabaya', 80000)
) AS t(waktu_event, kota, nilai)
""")
BATCH_TERAKHIR = "2026-01-15 08:00"Ketiga layer Lambda kemudian didefinisikan sebagai tiga objek SQL — batch view, realtime view, dan serving view:
# --- Batch layer: recompute dari seluruh sejarah <= 08:00 ---
con.execute(f"""
CREATE TABLE batch_view AS
SELECT kota, count(*) AS jumlah_event, sum(nilai) AS pendapatan
FROM event_log
WHERE waktu_event <= '{BATCH_TERAKHIR}'
GROUP BY kota
""")
# --- Speed layer: hanya event setelah batch terakhir ---
con.execute(f"""
CREATE TABLE speed_view AS
SELECT kota, count(*) AS jumlah_event, sum(nilai) AS pendapatan
FROM event_log
WHERE waktu_event > '{BATCH_TERAKHIR}'
GROUP BY kota
""")
# --- Serving layer: gabungan batch + speed ---
con.execute("""
CREATE VIEW serving_view AS
SELECT coalesce(b.kota, s.kota) AS kota,
coalesce(b.jumlah_event, 0) + coalesce(s.jumlah_event, 0) AS jumlah_event,
coalesce(b.pendapatan, 0) + coalesce(s.pendapatan, 0) AS pendapatan
FROM batch_view b
FULL OUTER JOIN speed_view s ON b.kota = s.kota
""")Output yang Dihasilkan:
total event di log : 10
batch layer memproses : 10 baris (seluruh sejarah), 4 lolos filter <= 2026-01-15 08:00
speed layer memproses : 6 baris (hanya event setelah 2026-01-15 08:00)
== Serving layer (batch + speed) vs recompute penuh ==
kota batch+speed recompute
bandung 3 225,000 3 225,000
jakarta 4 440,000 4 440,000
surabaya 3 300,000 3 300,000
hasil identik: TrueMari kita telaah baris-baris kode di atas:
- Blok pertama, baris 6-22 (
CREATE TABLE event_log): satu log append-only untuk semua event; kedua layer membaca sumber yang sama dengan filter berbeda, bukan dua jalur ingestion terpisah. - Blok kedua, baris 1-8 (
batch_view): filterwaktu_event <= BATCH_TERAKHIR— batch layer membaca seluruh sejarah lalu menghitung ulang; empat event lolos filter pada contoh ini. - Blok kedua, baris 10-17 (
speed_view): hanya enam event setelah pukul 08:00 yang dikerjakan; inilah yang membuat hasilnya selalu segar. - Blok kedua, baris 19-27 (
serving_view):FULL OUTER JOINdengancoalescemenjumlahkan kedua view per kota; kota yang hanya ada di salah satu sisi tetap terhitung dengan benar.
Baris hasil identik: True pada output adalah verifikasi paling penting: gabungan batch dan speed menghasilkan angka yang sama persis dengan recompute penuh atas seluruh log.
Ketika Batch Mengejar #
Keindahan Lambda tampak saat batch berikutnya selesai. Batch pukul 11:00 menghitung ulang seluruh sejarah hingga mencakup semua event, dan speed layer tinggal dikosongkan — hasil serving tidak berubah sedikit pun:
con.execute(f"""
CREATE OR REPLACE TABLE batch_view AS
SELECT kota, count(*) AS jumlah_event, sum(nilai) AS pendapatan
FROM event_log
WHERE waktu_event <= '2026-01-15 11:00'
GROUP BY kota
""")
con.execute("DELETE FROM speed_view")Output yang Dihasilkan:
== Setelah batch jam 11:00 mengejar ==
batch_view memuat seluruh event; speed_view kosong: True
hasil serving tetap identik dengan recompute penuh: TrueMekanisme ini sekaligus menjadi jalur perbaikan: bila logika speed layer sempat keliru, kesalahan tersebut hidup paling lama selama satu interval batch. Setelah batch mengejar, angka final menggantikan angka sementara tanpa intervensi manual — pola yang serumpun dengan Pemrosesan Ulang Data pada section Data Pipeline Engineering.
Harga yang Dibayar Lambda #
Lambda menyelesaikan pertukaran kesegaran versus keakuratan, tetapi memindahkannya ke kompleksitas operasional. Satu definisi bisnis — misalnya “pendapatan per kota” — harus diimplementasikan dua kali: sekali di batch layer, sekali di speed layer, sering kali dengan teknologi berbeda pula (Spark untuk batch, Flink atau Kafka Streams untuk speed).
Rujukan klasik Lambda adalah buku Nathan Marz dan James Warren, Big Data (Manning), yang memperkenalkan istilah batch layer, speed layer, dan serving layer.
Kompleksitas dua codebase tersebut memancing pertanyaan dari Jay Kreps, salah satu pencipta Kafka: bila log event bisa disimpan lama dan diputar ulang dari awal, mengapa kita masih membutuhkan jalur batch terpisah? Chapter Kappa Architecture membahas jawabannya.