NATS vs RabbitMQ vs Kafka untuk Satu VPS
Bandingkan jaminan pengiriman, biaya memori dan disk, perilaku saat restart, cara memeriksa backlog, serta kapan Postgres lebih tepat untuk satu VPS.
Jawaban singkat untuk satu server
Message queue pada satu VPS merupakan keputusan tentang jaminan pengiriman, bukan tentang kecepatan. Pada satu server, broker jarang menjadi bottleneck karena kode aplikasi, database, dan satu disk Anda biasanya mencapai batasnya lebih dahulu. Pilih tool dengan perilaku saat terjadi kegagalan yang dapat Anda terima, lalu ukur server yang benar-benar Anda gunakan.
Empat opsi berikut disusun berdasarkan urutan yang sebaiknya dipertimbangkan oleh sebagian besar pembaca.
- Gunakan database yang sudah Anda jalankan. Postgres dengan
SELECT ... FOR UPDATE SKIP LOCKEDmerupakan job queue yang dapat digunakan dan tidak menambahkan proses baru yang harus dipantau. - Gunakan RabbitMQ jika setiap message merupakan unit kerja yang harus diakui, dicoba ulang dalam jumlah terbatas, lalu dipindahkan ke tempat yang dapat diperiksa oleh manusia.
- Gunakan NATS jika message merupakan event yang ditangani oleh beberapa bagian sistem Anda. Aktifkan JetStream untuk event yang harus tetap tersedia setelah restart.
- Gunakan Kafka jika tool downstream hanya mendukung protokol Kafka. Pada satu server, hal ini hampir menjadi satu-satunya alasan untuk memilihnya.
Bagian selanjutnya menjelaskan alasannya: biaya setiap opsi dalam penggunaan memory dan disk pada VPS kecil, perilakunya saat server reboot, serta command yang tepat untuk menampilkan backlog sebelum pengguna Anda merasakannya.
Apa arti jaminan pengiriman sebenarnya
Paling banyak sekali berarti broker menyerahkan pesan lalu melupakannya. Jika tidak ada consumer yang terhubung, atau consumer berhenti di tengah proses, pesan hilang dan tidak ada yang melaporkannya.
Setidaknya sekali berarti consumer mengirim acknowledgement (ack) setelah proses berhasil. Sebelum ack tersebut diterima, broker menyimpan pesan dan akan mengirimkannya lagi. Pengiriman ulang adalah alasan handler harus idempotent: memproses pesan yang sama dua kali tidak boleh membebankan biaya ke kartu dua kali. Pemrosesan tepat satu kali dari ujung ke ujung bukan sesuatu yang diberikan oleh broker. Jaminan tersebut berasal dari kunci unik di database Anda sendiri.
Replay adalah properti yang berbeda. Queue membuang pesan setelah pesan tersebut di-acknowledge. Log menyimpan pesan selama periode retensi, sehingga consumer baru dapat memulai dari awal dan membaca seluruh riwayat. Kafka dan NATS JetStream adalah log. RabbitMQ adalah queue. Perbedaan ini memengaruhi lebih banyak arsitektur daripada throughput.
Dead lettering terjadi pada pesan yang terus gagal diproses. Tanpa mekanisme ini, poison message akan berulang tanpa batas, dan perulangan tersebut terlihat seperti worker yang sibuk, bukan worker yang rusak.
Mulai dengan Postgres dan biarkan broker membuktikan keandalannya
Sebagian besar workload satu aplikasi hanya memproses beberapa ribu job latar belakang per hari. Jumlah itu dapat ditangani dalam satu tabel.
CREATE TABLE job (
id bigserial PRIMARY KEY,
payload jsonb NOT NULL,
run_after timestamptz NOT NULL DEFAULT now(),
attempts int NOT NULL DEFAULT 0
);
CREATE INDEX job_ready_idx ON job (run_after, id);Worker mengambil satu job di dalam transaksi.
BEGIN;
SELECT id, payload
FROM job
WHERE run_after <= now()
ORDER BY id
FOR UPDATE SKIP LOCKED
LIMIT 1;
-- run the work, then remove the row
DELETE FROM job WHERE id = $1;
COMMIT;FOR UPDATE SKIP LOCKED adalah inti mekanismenya. Perintah ini mengunci baris yang dikembalikannya dan melewati baris yang sudah dikunci oleh transaksi lain. Dengan demikian, dua worker tidak akan mengambil job yang sama. Jika worker mengalami crash, Postgres membatalkan transaksinya, kunci dilepaskan, dan baris tersebut dapat dilihat oleh worker berikutnya. Anda mendapatkan pengiriman setidaknya sekali, percobaan ulang dengan menaikkan attempts, serta tabel dead letter, semuanya dengan durabilitas yang sudah Anda bayar. Backlog dapat diperiksa melalui satu query: SELECT count(*) FROM job WHERE run_after <= now();
Batasannya. Setiap pengambilan dan penghapusan job adalah operasi tulis. Karena itu, laju job yang tinggi meninggalkan versi baris yang sudah tidak berlaku, dan tabel queue adalah kasus klasik ketika bloat tumbuh lebih cepat daripada kemampuan autovacuum membersihkannya. Job yang berjalan lama memperburuk keadaan karena transaksi yang tetap terbuka selama proses berlangsung juga menahan vacuum horizon untuk seluruh database. Polling menambah latensi, sedangkan LISTEN dengan NOTIFY menghilangkan polling, tetapi tidak menghilangkan operasi tulis. Jika tabel job menjadi tabel tersibuk yang Anda miliki, atau service kedua memerlukan event yang sama, pindahkan pekerjaan tersebut ke luar database. Pilihan ini berkaitan dengan cara database itu sendiri di-deploy. Karena itu, tentukan apakah database berjalan di Docker atau pada host sebelum menambahkan broker di sebelahnya.
Redis adalah opsi lain yang mungkin sudah Anda jalankan. Redis Streams menyediakan consumer group dengan XADD dan XREADGROUP, daftar pending untuk setiap group, serta XAUTOCLAIM untuk mengambil kembali pekerjaan dari consumer yang mati. Redis berukuran kecil dan cepat. Namun, ada batasan penting pada satu mesin: dengan pengaturan appendfsync everysec yang umum digunakan, kehilangan daya dapat menyebabkan sekitar satu detik operasi tulis hilang. Hal itu sesuai untuk invalidasi cache, tetapi tidak sesuai untuk pembayaran. Jika aplikasi Anda adalah satu proses yang dibangun berdasarkan SQLite di production pada VPS, pola pengambilan dan penghapusan yang sama tetap dapat digunakan. Namun, SQLite tidak memiliki padanan SKIP LOCKED, dan setiap worker harus menunggu secara bergantian pada satu-satunya write lock.
NATS core: perutean subject tanpa penyimpanan
docker run -d --name nats \
-p 4222:4222 -p 127.0.0.1:8222:8222 \
nats:2.14 -m 8222Per Agustus 2026, lini server saat ini adalah 2.14. -m 8222 mengaktifkan port pemantauan HTTP. Port ini dinonaktifkan secara default dan tidak memiliki autentikasi, jadi ikat ke localhost seperti di atas.
Core NATS menggunakan pengiriman paling banyak satu kali dan tidak menyimpan pesan. Publisher mengirim pesan ke subject seperti orders.created, lalu setiap subscriber yang filternya cocok menerima salinan. Jika tidak ada subscriber, pesan dibuang dan publisher tidak menerima error karena tugas publisher berakhir saat server menerima byte tersebut. Queue group, yaitu beberapa subscriber yang menggunakan nama grup yang sama, membuat server memilih satu anggota untuk setiap pesan. Mekanisme ini membagi pekerjaan tanpa menyimpan antrean.
Jejak penggunaan terdiri atas status subscription dan buffer tulis untuk setiap koneksi. Karena itu, penggunaan lebih bergantung pada jumlah koneksi daripada volume pesan, dan tidak ada data yang menumpuk di disk. Perilaku setelah restart mengikuti model ini: pesan yang sedang diproses hilang, client terhubung kembali secara mandiri, dan tidak ada langkah pemulihan yang perlu ditunggu.
Tidak ada backlog untuk dipantau, jadi pantau kehilangan pesan. Jika subscriber membaca socket lebih lambat daripada server menulis ke socket tersebut, buffer server untuk client itu akan penuh. Jika client belum mengejar ketertinggalan sampai batas waktu penulisan tercapai, server menutup seluruh koneksi dan menaikkan sebuah counter.
curl -s http://localhost:8222/varz | jq '.slow_consumers, .connections, .in_msgs, .out_msgs'Nilai slow_consumers yang terus meningkat berarti pesan sedang dibuang. Karena itu, buat alert berdasarkan nilai tersebut, bukan hanya membacanya sekali. Core NATS cocok untuk pesan yang nilainya cepat kedaluwarsa, seperti metrik, pembaruan status kehadiran, atau invalidasi cache yang akan digantikan oleh event berikutnya.
NATS JetStream: stream durable dan replay dalam proses yang sama
JetStream bukan produk kedua. JetStream adalah subsistem dalam binary yang sama dan diaktifkan dengan satu flag.
docker run -d --name nats \
-p 4222:4222 -p 127.0.0.1:8222:8222 \
-v nats-data:/data \
nats:2.14 -js -sd /data -m 8222-sd /data menetapkan direktori penyimpanan. Jika opsi ini dihilangkan, JetStream menyimpan datanya di /tmp, yang tingkat ketahanannya sesuai dengan namanya. Buat stream dengan CLI yang tersedia dalam image nats-box.
docker run --rm -it --network host natsio/nats-box:latest \
nats stream add ORDERS \
--subjects 'orders.>' \
--storage file \
--retention limits \
--max-age 72h \
--max-bytes=1073741824 \
--discard old \
--defaultsSetiap batas di sana diperlukan pada server kecil. --storage file menentukan data yang tetap tersedia setelah crash, karena memory stream tidak memiliki ketahanan tersebut. --max-bytes=1073741824 membatasi stream hingga 1 GiB berdasarkan jumlah byte yang ditulis, dan --discard old menghapus message paling lama saat batas tercapai, bukan menolak penulisan baru. Jika batas tidak ditetapkan, satu publisher yang tidak terkendali dapat memenuhi disk. Akibatnya, database juga berhenti karena menggunakan disk yang sama.
Consumer durable menyimpan posisinya sendiri dalam stream dan mempertahankannya setelah restart. Tetapkan --max-deliver pada consumer agar message yang selalu gagal tidak terus-menerus dikirim ulang. Setelah message kehabisan jumlah pengiriman, JetStream menerbitkan advisory pada $JS.EVENT.ADVISORY.CONSUMER.MAX_DELIVERIES.>. Subscribe ke subject tersebut adalah cara untuk membangun jalur dead letter yang disediakan RabbitMQ sebagai fitur. Jalur itu harus Anda buat sendiri.
Untuk melihat backlog, jalankan nats stream report guna melihat jumlah message yang tersimpan dan nats consumer report ORDERS guna melihat acknowledgement yang belum diterima serta message yang belum diproses pada setiap consumer. Jumlah message yang belum diproses adalah metrik yang harus dipantau. Penggunaan disk dapat dilihat dengan du -sh terhadap direktori penyimpanan, dan akan terus bertambah sampai batas retention menghapus sebagian data.
RabbitMQ: akui setiap pesan, parkirkan pesan yang gagal
docker run -d --name rabbitmq \
-p 5672:5672 -p 127.0.0.1:15672:15672 \
-v rabbitmq-data:/var/lib/rabbitmq \
rabbitmq:4-managementPer Agustus 2026, seri saat ini adalah 4.3. Port 5672 adalah AMQP (advanced message queuing protocol), sedangkan 15672 adalah antarmuka manajemen. Pertahankan antarmuka pada localhost dan akses melalui tunnel SSH.
Deklarasikan queue dengan set argumen x-queue-type ke quorum; nilai defaultnya masih classic. Quorum queue selalu durable dan menulis data ke disk sebelum melakukan hal lain. Dengan demikian, pada satu node, Anda mendapatkan perilaku yang jelas, bukan kombinasi berbagai opsi durable dan transient. Tetapkan target dead letter dengan policy.
docker exec rabbitmq rabbitmqctl set_policy DLX ".*" \
'{"dead-letter-exchange":"my-dlx", "dead-letter-routing-key":"my-routing-key"}' \
--apply-to queues --priority 7Pesan menjadi dead letter karena empat alasan: consumer menolaknya dengan basic.reject atau basic.nack dan requeue disetel ke false, TTL (time to live) per pesan kedaluwarsa, queue melewati batas panjang, atau pesan melebihi batas pengiriman quorum queue. Batas tersebut secara default adalah 20 sejak RabbitMQ 4.0. Jadi, handler yang melempar exception lalu melakukan nack akan mencoba ulang sebanyak 20 kali, kemudian menyerahkan pesan ke dead letter exchange, bukan terus mengulang.
Penggunaan memori sering menimbulkan masalah pada RabbitMQ di VPS kecil. Batas tinggi default adalah 0.6 dari RAM yang tersedia. Saat node melewati batas tersebut, RabbitMQ memblokir setiap koneksi yang melakukan publish. Aplikasi Anda tidak menerima error. Aplikasi menerima operasi publish yang tidak pernah selesai. Di dalam kode Anda, kondisi ini terlihat seperti hang. Log startup mencetak nilai yang dihitung oleh node:
Memory high watermark set to 1024 MiB (1073741824 bytes) of 8192 MiB (8589934592 bytes) totalAlarm disk juga memblokir publisher dengan cara yang sama saat ruang kosong turun di bawah 50 MB secara default. Quorum queue menambahkan perhitungan tersendiri: dokumentasi mengalokasikan setidaknya 32 byte metadata dalam memori untuk setiap pesan, sekitar 1 MB untuk setiap 30,000 pesan, serta merekomendasikan RAM minimal tiga kali ukuran write-ahead log efektif. Batas WAL secara default adalah 512 MiB. Jadi, rekomendasi tersebut saja membutuhkan 1.5 GB. Pada server 2 GB, turunkan nilainya di rabbitmq.conf daripada berharap nilai default sesuai.
raft.wal_max_size_bytes = 64000000
vm_memory_high_watermark.relative = 0.5Backlog terdiri atas dua angka. Pasangan angka tersebut menunjukkan jenis kegagalan yang terjadi.
docker exec rabbitmq rabbitmqctl list_queues name messages messages_ready messages_unacknowledgedmessages_ready sedang menunggu consumer. messages_unacknowledged telah dikirim tetapi tidak pernah di-ack. Jumlah pesan yang belum di-ack yang meningkat, disertai jumlah pesan ready yang tetap, berarti worker Anda telah mengambil pekerjaan tetapi berhenti menyelesaikannya. Ini adalah bug yang berbeda dari queue yang hanya tertinggal.
Kafka pada satu mesin, dan kapan penggunaannya mulai tidak masuk akal
KAFKA_CLUSTER_ID="$(bin/kafka-storage.sh random-uuid)"
bin/kafka-storage.sh format --standalone -t $KAFKA_CLUSTER_ID -c config/server.properties
bin/kafka-server-start.sh config/server.propertiesItulah quickstart untuk Kafka 4.3.1, yang berlaku per Agustus 2026, dan berjalan dalam mode KRaft (Kafka Raft, controller bawaan yang menggantikan ZooKeeper pada Kafka 4.0). Padanan berbasis container adalah apache/kafka:4.3.1.
Skrip start menetapkan export KAFKA_HEAP_OPTS="-Xmx1G -Xms1G" jika Anda belum menetapkannya sendiri. Akibatnya, broker mencadangkan heap Java sebesar 1 GB sebelum menyimpan satu pesan pun. Broker juga memerlukan RAM kosong di luar jumlah tersebut untuk page cache yang digunakan saat membaca data. Pada VPS 2 GB, aplikasi Anda harus berbagi sisa RAM dengan JVM.
Retention adalah kejutan berikutnya. Nilai default log.retention.hours adalah 168, yaitu tujuh hari. Nilai default log.retention.bytes adalah -1, yang berarti tidak ada batas ukuran. Kafka menyimpan pesan selama seluruh periode tersebut, terlepas dari apakah setiap consumer sudah membacanya. Itulah fitur yang Anda perlukan. Namun, pada satu disk kecil, fitur ini juga dapat menyebabkan kegagalan. Karena itu, tetapkan batas dalam byte untuk setiap topic sebelum Anda mengalaminya sendiri.
Sekarang bagian yang sebenarnya. Satu broker berarti replication factor 1. Jadi, acks=all hanya menghasilkan satu fsync pada satu disk. Anda mendapatkan durability dari satu mesin, dengan biaya operasional broker JVM dan satu controller. Partition memberikan paralelisme di antara broker yang tidak Anda miliki. Replication, rack awareness, dan fitur lain untuk fleet tidak digunakan. JetStream menyediakan replay durable yang sama pada mesin yang sama dengan penggunaan memori yang jauh lebih kecil. Dua alasan masih dapat membenarkan penggunaan Kafka di sini: tool downstream hanya mendukung protokol Kafka (misalnya change data capture dengan Debezium atau pemuat analitik), atau Anda sedang mereproduksi topologi produksi dalam skala kecil. Rencana untuk berkembang menjadi cluster berarti Anda berencana membeli lebih banyak mesin. Sampai saat itu, pertukarannya sama seperti menjalankan k3s pada satu node, yaitu Anda menanggung kompleksitas cluster demi reliability satu node.
Backlog di Kafka disebut consumer lag.
bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 --describe --group my-groupBaca kolom LAG. Nilainya adalah LOG-END-OFFSET dikurangi CURRENT-OFFSET untuk setiap partition. Jika lag meningkat pada satu partition sementara partition lain tetap datar, kemungkinan terdapat distribusi key yang tidak merata. Semua pesan dengan key yang sama masuk ke partition yang sama, dan satu consumer menanganinya sendiri.
Yang terjadi saat server dimulai ulang
Core NATS kehilangan semua data yang sedang diproses dan kembali aktif seketika karena tidak ada data yang perlu dipulihkan. JetStream memuat ulang stream dan posisi consumer dari direktori penyimpanan, sehingga consumer melanjutkan dari offset sebelumnya. RabbitMQ memulihkan quorum queue dari disk, sedangkan transient queue klasik dan pesan apa pun yang diterbitkan tanpa delivery mode persistent akan hilang. Kafka memutar ulang segmen log saat startup. Setelah shutdown yang tidak bersih, pemindaian pemulihan tersebut dapat memerlukan waktu beberapa menit pada disk kecil sebelum broker menerima koneksi.
Ada dua hal yang sebaiknya ditetapkan sekali. Berikan container restart policy (restart: unless-stopped) atau aktifkan unit systemd agar broker kembali aktif setelah reboot akibat upgrade kernel tanpa perlu intervensi manual. Selanjutnya, atur urutannya. Broker yang siap dua puluh detik setelah aplikasi akan menolak koneksi pertama, dan beberapa client library akan keluar alih-alih mencoba lagi. Tahan startup aplikasi hingga broker siap dengan Compose healthcheck yang menunda service dependen hingga broker siap.
Biaya pada VPS Anda, diukur sendiri, bukan berdasarkan angka yang dikutip
Angka throughput yang dipublikasikan diukur pada perangkat keras yang tidak Anda miliki, biasanya server multi-core dengan NVMe lokal. Anggap angka tersebut sebagai batas atas, lalu ukur VPS Anda sendiri.
docker stats --no-stream
free -m
sudo du -sh /var/lib/docker/volumes/*/_dataJalankan pengujian tersebut saat broker tidak sibuk, lalu ulangi saat menangani trafik aktual Anda. Selisih antara kedua hasil tersebut menentukan apakah broker dapat berjalan berdampingan dengan aplikasi Anda. Untuk perkiraan batas bawah throughput, gunakan load generator bawaan setiap proyek, bukan artikel blog orang lain: nats bench pub test --msgs 100000 --clients 2 untuk NATS, bin/kafka-producer-perf-test.sh untuk Kafka, dan PerfTest untuk RabbitMQ. Menjalankan generator pada VPS yang sama mengukur broker dan generator secara bersamaan. Hal ini dapat diterima selama Anda menyatakannya saat melaporkan hasil pengukuran.
Satu batas berlaku untuk semuanya. Setiap opsi durable di sini menunggu fsync. Karena itu, pada VPS dengan storage yang terhubung melalui jaringan, disk menjadi faktor pembatas dan mengganti broker tidak akan mengubahnya.
Tiga workload dan message queue yang dibutuhkan masing-masing
- Background job untuk satu aplikasi web, seperti mengirim email, mengubah ukuran gambar, atau mengirim webhook. Mulai dengan Postgres dan
SKIP LOCKED. Gunakan RabbitMQ dengan quorum queue jika Anda memerlukan acknowledgment per pesan, batas pengiriman, dan dead-letter queue yang dapat diperiksa tanpa menulis logika tersebut sendiri, atau jika tabel job telah menjadi tabel yang paling sibuk dalam database. - Event yang ditanggapi oleh beberapa service internal, ketika pesan yang hilang segera digantikan oleh pesan yang lebih baru. Gunakan Core NATS, dengan subject sebagai skema routing dan queue group saat Anda memerlukan pembagian pekerjaan. Tambahkan stream JetStream untuk sejumlah kecil subject yang harus tetap ada setelah restart, dan simpan sisanya di memory.
- Log event yang dibaca consumer sejak awal, untuk audit trail, membangun ulang read model, atau memasok data ke analytics di kemudian hari. Gunakan JetStream dengan file storage dan batas byte yang ditetapkan secara eksplisit. Pilih Kafka hanya jika tool downstream memerlukan protokol Kafka, dan terima penggunaan heap JVM sebagai biaya kompatibilitas tersebut.
Biaya dari pilihan yang salah pada satu server bukan throughput. Biayanya adalah proses recovery pada pukul tiga pagi, ketika Anda perlu mengetahui apakah pesan masih ada. Pilih berdasarkan hal itu.
FAQ
Dapatkah saya menjalankan Kafka pada VPS 2 GB?
Kafka dapat dijalankan, tetapi kapasitasnya akan sangat terbatas. bin/kafka-server-start.sh menetapkan KAFKA_HEAP_OPTS="-Xmx1G -Xms1G" jika Anda belum menggantinya, sehingga JVM menggunakan 1 GB sebelum menyimpan pesan apa pun. Kafka juga memerlukan memori bebas di luar kapasitas tersebut untuk page cache. Jika aplikasi dan database dijalankan pada server yang sama, sistem akan mulai menggunakan swap. Anda juga mendapatkan replication factor 1. Artinya, acks=all hanya berupa satu fsync pada satu disk. Dengan demikian, Anda menanggung biaya operasional Kafka tanpa model durability-nya. NATS JetStream menyediakan pemutaran ulang yang durable pada perangkat keras yang sama dengan penggunaan memori yang jauh lebih rendah.
Apakah saya memerlukan message queue jika sudah menjalankan Postgres?
Sering kali tidak. Tabel job yang dibaca dengan SELECT ... FOR UPDATE SKIP LOCKED di dalam transaksi menyediakan pengiriman at-least-once, worker konkuren yang aman, retry, dan tabel dead letter, tanpa service tambahan yang harus dimonitor serta dengan backup yang memang sudah Anda lakukan. Indikasi untuk memindahkan beban kerja ke sistem lain bersifat spesifik: tabel queue menjadi beban penulisan terberat dan autovacuum tertinggal, job yang berjalan lama menahan transaksi tetap terbuka dan menghambat vacuum untuk seluruh database, atau service kedua perlu menggunakan event yang sama secara independen.
Sebaiknya saya menggunakan NATS JetStream atau RabbitMQ untuk job latar belakang?
Gunakan RabbitMQ jika Anda memerlukan acknowledgement per pesan, batas pengiriman, dan dead letter routing sebagai perilaku bawaan. Quorum queue selalu durable. Batas pengiriman secara default adalah 20 sejak RabbitMQ 4.0. Policy dapat mengirim pesan yang telah mencapai batas tersebut ke dead letter exchange yang dapat Anda kosongkan dan periksa. Gunakan JetStream jika event yang sama juga perlu diputar ulang oleh consumer lain di kemudian hari, karena stream tetap menyimpan pesan setelah acknowledgement, sedangkan queue tidak. Dengan JetStream, Anda menetapkan --max-deliver dan membangun jalur dead letter sendiri dari advisory $JS.EVENT.ADVISORY.CONSUMER.MAX_DELIVERIES.>.
Bagaimana cara mengetahui seberapa jauh consumer saya tertinggal?
Setiap broker memiliki satu command untuk pemeriksaan ini. Pada RabbitMQ, rabbitmqctl list_queues name messages messages_ready messages_unacknowledged memisahkan pekerjaan yang masih menunggu consumer dari pekerjaan yang sudah dikirim tetapi belum pernah di-acknowledge. Pada JetStream, nats consumer report <stream> menampilkan pesan yang belum diproses dan acknowledgement yang masih tertunda untuk setiap consumer. Pada Kafka, kafka-consumer-groups.sh --bootstrap-server localhost:9092 --describe --group <group> menampilkan kolom LAG untuk setiap partition. Core NATS tidak memiliki backlog untuk dibaca karena tidak menyimpan apa pun. Karena itu, pantau counter slow_consumers pada http://localhost:8222/varz. Counter tersebut menghitung koneksi yang ditutup server karena tertinggal, yang berarti terjadi kehilangan pesan.