Skip to main content
BlogBackend

NATS JetStream vs Kafka untuk Tim yang Tidak Butuh Skala Kafka

Kafka adalah jawaban refleks untuk "kami butuh message log," tetapi untuk beban di bawah sejuta pesan per detik, NATS JetStream memberi Anda stream tahan-lama dan jaminan pengiriman solid dengan sebagian kecil dari biaya operasional.

Matthews Wong

Software Engineer

Juli 20269 menit baca
NATS JetStream vs Kafka untuk Tim yang Tidak Butuh Skala Kafka

Foto oleh D Gore via Wikimedia Commons (CC BY-SA 2.0)

Ringkasan Utama

Untuk tim yang memproses ribuan pesan per detik alih-alih jutaan, NATS JetStream memberikan stream tahan-lama, consumer push dan pull, serta pengiriman at-least-once atau exactly-once dari satu binary mandiri. Kafka unggul di throughput masif dan retensi panjang, tetapi perencanaan partisi dan beban operasionalnya berlebihan untuk sebagian besar backend.

Setiap beberapa bulan sebuah tim memilih Kafka karena itu adalah jawaban default untuk "kami butuh message log." Lalu mereka menghabiskan satu sprint untuk jumlah partisi, rebalancing consumer group, penyetelan retensi, dan menyambungkan stack observability sebelum satu pun event bisnis mengalir. Saya sudah menyaksikan ini terjadi pada layanan yang puncaknya hanya beberapa ribu pesan per detik. Itu bukan wilayah asli Kafka, dan membayar pajak operasional Kafka untuk berada di sana adalah pertukaran yang buruk.

NATS JetStream adalah lapisan persistensi yang tertanam di dalam server NATS. Jika Anda sudah memahami model subject NATS, Anda mendapatkan stream tahan-lama, riwayat yang bisa diputar ulang, dan jaminan pengiriman hanya dengan membalik satu flag konfigurasi. Tulisan ini membahas stream, consumer, dan realitas operasional menjalankan keduanya, lengkap dengan tabel perbandingan agar Anda bisa memutuskan untuk beban kerja Anda sendiri.

Apa itu JetStream sebenarnya

NATS inti bersifat fire-and-forget pub/sub: jika tidak ada subscriber yang mendengarkan, pesan itu hilang. JetStream menambahkan lapisan penyimpanan di atas server yang sama, sehingga pesan yang dipublikasikan ke sebuah subject ditangkap ke dalam sebuah stream dan bisa diputar ulang sesuai permintaan. Tidak ada proses terpisah, tidak ada cluster terpisah, dan tidak ada library klien terpisah. Anda mengaktifkannya dengan satu flag dan tetap memakai model koneksi serta subject yang sudah Anda gunakan.

# Enable JetStream in the server config file
# nats-server.conf
jetstream {
  store_dir: "/data/jetstream"
  max_memory_store: 1G
  max_file_store: 10G
}

# Or just a flag for local dev
nats-server -js

Sebuah stream mendefinisikan subject apa yang ditangkapnya dan bagaimana ia menyimpan data. Tiga kebijakan retensi ini penting karena langsung memetakan ke pola backend yang umum.

  • Limits — simpan pesan sampai batas usia, ukuran, atau jumlah tercapai. Ini adalah log yang bisa diputar ulang bergaya Kafka.
  • Work Queue — sebuah pesan dihapus setelah satu consumer mengonfirmasinya. Sempurna untuk antrean pekerjaan di mana setiap tugas dijalankan tepat sekali.
  • Interest — pesan disimpan hanya selama ada consumer aktif yang tertarik pada subject tersebut. Jalan tengah yang menghindari pertumbuhan tak terbatas.

Consumer: push, pull, dan konfirmasi

Consumer adalah tampilan berkeadaan (stateful) ke dalam sebuah stream yang melacak pesan mana yang sudah dilihat sebuah klien. Pull consumer adalah default modern: klien meminta satu batch saat siap, yang memberi Anda backpressure alami dan penskalaan horizontal tanpa perlu mendefinisikan partisi. Beberapa worker bisa berbagi satu pull consumer layaknya queue group, dan server menyeimbangkan beban di antara mereka.

Kebijakan konfirmasi adalah tempat Anda menyetel jaminan pengiriman. Explicit ack berarti setiap pesan harus dikonfirmasi atau akan dikirim ulang setelah timeout — inilah jaminan at-least-once Anda. JetStream juga menawarkan exactly-once menggunakan ID pesan publisher untuk deduplikasi ditambah double-ack saat konsumsi. Bandingkan dengan Kafka, di mana exactly-once membutuhkan transaksi dan idempotent producer yang dikonfigurasi dengan benar di seluruh pipeline.

// TypeScript, using the nats.js client with JetStream
import { connect, AckPolicy } from "nats";

const nc = await connect({ servers: "localhost:4222" });
const jsm = await nc.jetstreamManager();

// Create a durable, file-backed stream
await jsm.streams.add({
  name: "ORDERS",
  subjects: ["orders.>"],
  retention: "limits",
  storage: "file",
  num_replicas: 3,
});

// Create a durable pull consumer with explicit ack
await jsm.consumers.add("ORDERS", {
  durable_name: "order-workers",
  ack_policy: AckPolicy.Explicit,
  max_deliver: 5,
  ack_wait: 30_000_000_000, // 30s in nanoseconds
});

const js = nc.jetstream();
const consumer = await js.consumers.get("ORDERS", "order-workers");
const messages = await consumer.consume({ max_messages: 100 });

for await (const m of messages) {
  await handleOrder(m.data);
  m.ack();
}

Setel max_deliver ke angka terbatas dan pasangkan stream dengan strategi dead-letter. Tanpa batas pengiriman, pesan yang selalu membuat handler Anda melempar error akan dikirim ulang selamanya, diam-diam membakar satu worker dalam loop. Ini adalah padanan JetStream dari poison-pill Kafka dan sering menggigit tim yang mengira pengiriman ulang itu gratis.

Realitas operasional

Kafka 4.0, yang dirilis Maret 2025, menghapus ZooKeeper sepenuhnya dan menggantinya dengan KRaft, lapisan metadata berbasis Raft milik Kafka sendiri. Itu penyederhanaan yang nyata — satu sistem alih-alih dua, dan cluster yang menskala hingga jutaan partisi. Tetapi KRaft tidak menghilangkan bagian yang benar-benar menyita waktu Anda: perencanaan partisi, rebalancing consumer group, penyetelan retensi dan segment, serta memahami semantik log terdistribusi sebelum Anda bisa men-debug lonjakan lag.

JetStream hadir sebagai satu binary Go tanpa JVM untuk disetel dan tanpa heap untuk diukur. Di VPS yang saya jalankan, deployment NATS tiga-node ber-cluster dengan JetStream aktif muat dengan nyaman dalam memori yang bahkan dianggap penghinaan oleh satu broker Kafka. Replikasi berbasis Raft per stream, monitoring adalah endpoint HTTP bawaan, dan CLI nats yang sama untuk publish juga memeriksa stream dan consumer. Semuanya adalah satu model mental.

Jangan membaca "ringan" sebagai "tak terbatas." JetStream tidak dibangun untuk retensi berskala petabyte atau ekosistem konektor pihak ketiga yang luas seperti yang diberikan Kafka Connect. Jika Anda perlu menyebar ke puluhan data warehouse dan lake, atau Anda benar-benar mendorong jutaan pesan per detik dengan retensi sebulan penuh, Kafka pantas dengan kcompleksitasnya. Sesuaikan alat dengan beban sebenarnya, bukan beban yang Anda bayangkan.

Perbandingan langsung

DimensiNATS JetStreamApache Kafka 4.0
DeploymentSatu binary Go, satu flag untuk mengaktifkan, tanpa JVMBroker berbasis JVM, controller KRaft, penyesuaian memori
Unit penskalaanConsumer di atas subject, tanpa perencanaan partisiPartisi per topic, direncanakan di awal
Jaminan pengirimanAt-least-once secara default, exactly-once via ID pesan plus double-ackAt-least-once, exactly-once via transaksi dan idempotent producer
Model retensiLimits, Work Queue, Interest — per streamRetensi log berbasis waktu atau ukuran, plus compaction
Throughput puncakNyaman di ribuan hingga jutaan rendah pesan/detikDirancang khusus untuk jutaan pesan/detik berkelanjutan
EkosistemRamping, berbasis subject, ramah edge dan multi-tenantLuas — Kafka Connect, Streams, Schema Registry

Bagaimana saya memutuskan

  1. Perkirakan throughput puncak sebenarnya. Jika di bawah beberapa ratus ribu pesan per detik, JetStream hampir pasti sudah cukup.
  2. Periksa kebutuhan retensi Anda. Pemutaran ulang berhari-hari hingga berminggu-minggu cocok di penyimpanan file JetStream; riwayat berbulan-bulan berskala petabyte condong ke Kafka.
  3. Hitung konektor Anda. Jika Anda hidup di Kafka Connect dan Schema Registry, tetap di ekosistem itu lebih bernilai daripada memangkas biaya operasional.
  4. Timbang siapa yang mengoperasikannya. Tim kecil tanpa platform engineer khusus akan merilis lebih cepat dan tidur lebih nyenyak dengan JetStream.

Aturan saya sederhana: pilih Kafka ketika Anda bisa menyebutkan fitur Kafka spesifik yang Anda butuhkan — Connect, throughput masif berkelanjutan, atau riwayat ter-compact yang panjang. Jika jawaban jujur Anda adalah "saya butuh message log tahan-lama yang bisa diputar ulang dengan jaminan pengiriman yang baik," JetStream memberikan itu dengan sebagian kecil dari beban operasional, dan Anda selalu bisa naik kelas nanti jika bebannya benar-benar datang.

FAQ

Pertanyaan Umum

Jawaban singkat untuk pertanyaan yang paling sering diajukan pembaca tentang topik ini.

Apakah NATS JetStream benar-benar pengganti Kafka?

Untuk mayoritas backend, ya. JetStream menyediakan stream tahan-lama yang bisa diputar ulang, consumer push dan pull, serta pengiriman at-least-once atau exactly-once. Ia bukan pengganti ketika Anda secara spesifik membutuhkan ekosistem konektor Kafka Connect, throughput jutaan pesan per detik yang berkelanjutan, atau retensi jangka panjang berskala petabyte.

Bagaimana JetStream mencapai pengiriman exactly-once?

Publisher melampirkan ID pesan unik yang digunakan server untuk deduplikasi pesan dalam jendela yang dapat dikonfigurasi, mencegah publish ganda. Di sisi consumer, double-acknowledgment mengonfirmasi bahwa pesan telah diterima dan diproses. Bersama-sama keduanya memberikan semantik exactly-once tanpa koordinasi transaksi yang dibutuhkan Kafka.

Apa perbedaan consumer push dan pull di JetStream?

Consumer push membuat server mengirim pesan secara otomatis ke sebuah subject, yang sederhana tetapi menawarkan kontrol aliran lebih sedikit. Consumer pull membiarkan klien meminta batch saat siap, memberikan backpressure alami dan penskalaan horizontal. Consumer pull adalah default yang direkomendasikan untuk sebagian besar beban pemrosesan tahan-lama.

Apakah Kafka 4.0 masih membutuhkan ZooKeeper?

Tidak. Kafka 4.0, yang dirilis Maret 2025, menghapus ZooKeeper sepenuhnya dan menggantinya dengan KRaft, lapisan metadata berbasis Raft milik Kafka sendiri. Ini menyederhanakan arsitektur menjadi satu sistem dan menskala hingga jutaan partisi, tetapi tidak menghilangkan perencanaan partisi atau penyetelan consumer group.

Berapa banyak infrastruktur yang dibutuhkan JetStream untuk berjalan?

JetStream tertanam di dalam satu binary Go nats-server dan diaktifkan dengan satu blok konfigurasi atau flag. Tidak ada JVM untuk disetel, tidak ada ZooKeeper atau controller KRaft terpisah, dan monitoring adalah endpoint HTTP bawaan. Deployment tiga-node ber-cluster berjalan nyaman di sumber daya VPS yang sederhana.