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:

AspekBatch LayerSpeed Layer
Cakupan bacaanseluruh sejarah logevent setelah batch terakhir
Latensi hasiljamdetik sampai menit
Sifat hasilfinal dan akuratsementara, digantikan batch
Pola biayamahal per run, jarang jalanmurah per event, jalan terus
Kelemahantertinggalrawan 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:

python
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:

python
# --- 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:

text
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: True

Mari kita telaah baris-baris kode di atas:

  1. 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.
  2. Blok kedua, baris 1-8 (batch_view): filter waktu_event <= BATCH_TERAKHIR — batch layer membaca seluruh sejarah lalu menghitung ulang; empat event lolos filter pada contoh ini.
  3. Blok kedua, baris 10-17 (speed_view): hanya enam event setelah pukul 08:00 yang dikerjakan; inilah yang membuat hasilnya selalu segar.
  4. Blok kedua, baris 19-27 (serving_view): FULL OUTER JOIN dengan coalesce menjumlahkan 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:

python
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:

text
== Setelah batch jam 11:00 mengejar ==
batch_view memuat seluruh event; speed_view kosong: True
hasil serving tetap identik dengan recompute penuh: True

Mekanisme 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.