Masalah utama saat insiden queue dan worker bukan sekadar “antrian panjang”, tetapi bagaimana membedakan sinyal yang benar-benar menjelaskan bottleneck dari noise yang terlihat sibuk namun tidak relevan. Banyak tim bereaksi pada metrik yang mudah dilihat—misalnya CPU rata-rata, memory usage, atau queue depth—padahal akar masalah sering ada pada retry storm, timeout yang tidak selaras, lock contention, hot key cache, atau lag antar komponen.
Artikel ini fokus pada cara memisahkan sinyal dari noise saat insiden queue dan worker dengan pendekatan operasional yang praktis. Intinya: jangan menilai kesehatan sistem dari satu angka tunggal. Anda perlu menghubungkan backlog, processing latency, retry rate, duplicate execution, cache behavior, locking, dan consistency lag agar diagnosis tidak salah arah.
Mengapa metrik dangkal sering menipu
Dalam sistem asynchronous, metrik yang terlihat sederhana sering gagal menjelaskan kondisi sebenarnya:
- CPU rata-rata rendah tidak berarti worker sehat. Worker bisa idle karena menunggu I/O, terblokir lock, atau gagal mengambil job.
- Panjang queue tinggi tidak selalu buruk. Bisa jadi ada lonjakan trafik yang masih dalam kapasitas drain normal.
- Error rate rendah tidak berarti aman. Job bisa diam-diam di-retry, timeout, atau dieksekusi ganda tanpa terhitung sebagai error aplikasi.
- Cache hit ratio tinggi juga bisa menipu bila satu hot key menyebabkan bottleneck pada lock atau stampede.
Analogi yang berguna: seperti menilai kualitas sistem dari satu indikator permukaan, padahal masalah sebenarnya baru terlihat saat kita melihat hubungan antar-sinyal, bukan angka yang berdiri sendiri.
Sinyal inti yang perlu dilihat saat insiden queue dan worker
1. Backlog yang dinormalisasi oleh throughput
Queue depth mentah jarang cukup. Yang lebih penting adalah berapa lama backlog akan habis pada throughput saat ini.
Gunakan pertanyaan seperti:
- Berapa jumlah job yang menunggu?
- Berapa job per detik yang benar-benar selesai?
- Jika laju masuk lebih besar dari laju selesai, berapa cepat backlog bertambah?
Rumus mental sederhana:
drain_time ≈ backlog / effective_throughputJika backlog 100.000 job terdengar besar, tetapi worker menyelesaikan 5.000 job per menit, masalahnya berbeda dibanding backlog 10.000 job dengan throughput hanya 50 job per menit.
2. Queueing latency, bukan hanya queue depth
Queueing latency adalah waktu dari job dibuat sampai mulai diproses. Ini lebih dekat ke pengalaman sistem nyata dibanding panjang queue saja.
Dua sistem bisa punya queue depth yang sama, tetapi:
- Sistem A: sebagian besar job mulai diproses dalam hitungan detik.
- Sistem B: job menunggu berpuluh menit.
Yang perlu dilihat adalah distribusi latency, terutama p95 dan p99, bukan hanya rata-rata.
3. Processing time dan service time per jenis job
Kelompokkan worker berdasarkan jenis pekerjaan. Satu queue campuran sering menyamarkan fakta bahwa hanya satu tipe job yang melambat.
Contoh sinyal yang penting:
- Durasi eksekusi job per handler atau task type
- Persentase job yang melewati target SLA internal
- Perubahan mendadak pada durasi setelah deploy atau perubahan dependency
Jika queue depth naik tetapi processing time per job stabil, mungkin kapasitas kurang. Jika processing time melonjak, kemungkinan ada bottleneck downstream seperti database, API eksternal, cache, atau lock.
4. Retry rate dan retry storm
Retry rate adalah sinyal penting yang sering diabaikan. Banyak insiden terlihat seperti kekurangan kapasitas, padahal sebenarnya worker sibuk memproses ulang job yang sama.
Perhatikan korelasi ini:
- Backlog naik
- Latency naik
- Retry rate naik
- Throughput selesai turun atau terlihat datar
Pola tersebut biasanya menandakan sistem tidak produktif: worker aktif, tetapi output bersih rendah karena banyak kerja ulang.
5. Visibility timeout dan duplicate job
Pada banyak sistem queue, job yang tidak selesai sebelum visibility timeout akan dianggap tersedia lagi dan dapat diambil ulang. Jika timeout lebih pendek dari durasi kerja nyata, Anda bisa melihat:
- Job yang sama diproses oleh lebih dari satu worker
- Duplicate side effect
- Peningkatan lock contention
- Retry atau redelivery yang tampak seperti lonjakan load
Masalah ini sering disalahartikan sebagai “worker kurang banyak”, padahal akar masalahnya adalah konfigurasi timeout dan idempotensi.
6. Lag antar komponen
Queue dan worker jarang berdiri sendiri. Ada komponen lain seperti database primer-replika, cache, search indexer, event bus, atau lock store. Insiden sering muncul karena lag antar komponen, misalnya:
- Worker menulis status ke database utama, tetapi pembaca memakai replika yang tertinggal
- Job selesai, tetapi invalidasi cache terlambat
- Outbox event belum terkirim, sehingga konsumen lain membaca state lama
Jika queue tampak sehat tetapi user melihat data lama atau job berulang, cek apakah masalahnya sebenarnya consistency lag.
Gejala yang menipu dan cara membacanya
CPU rendah, backlog tinggi
Ini sering terjadi saat worker menunggu sumber daya eksternal:
- Koneksi database habis
- Rate limit API pihak ketiga
- Lock contention tinggi
- Worker polling dengan interval tidak tepat
CPU rendah bukan berarti aman. Lihat jumlah thread aktif, waktu tunggu I/O, pool connection, dan waktu tunggu lock.
Queue pendek, latency tinggi
Queue depth rendah bisa terjadi bila:
- Job cepat diambil worker, tetapi lama selesai
- Concurrency terlalu tinggi sehingga semua worker sibuk pada job lambat
- Job dipindahkan ke retry/delay queue
Dalam kondisi ini, queue depth produksi utama terlihat normal, tetapi end-to-end latency tetap memburuk.
Error rate rendah, duplicate execution tinggi
Jika duplicate job tidak dihitung sebagai error aplikasi, dashboard bisa terlihat “hijau” padahal side effect sudah ganda. Ini umum pada job yang tidak idempotent, misalnya:
- Mengirim email atau notifikasi berulang
- Mendebit saldo dua kali
- Membuat record yang sama berkali-kali
Karena itu, metrik error harus dilengkapi dengan dedup hit rate, job redelivery count, atau idempotency conflict count.
Cache hit tinggi, tetapi sistem tetap lambat
Cache dapat menjadi sumber noise jika Anda hanya melihat hit ratio global. Dua masalah umum:
- Hot key: satu key sangat sering diakses sehingga node cache atau lock di sekitarnya menjadi bottleneck.
- Cache stampede: banyak worker serentak meregenerasi nilai yang sama saat cache kedaluwarsa.
Dalam kasus ini, hit ratio mungkin tetap tinggi secara keseluruhan, tetapi tail latency memburuk karena sebagian kecil key sangat dominan.
Korelasi yang paling berguna saat triage
Saat insiden terjadi, fokuslah pada hubungan antar-metrik berikut:
- Backlog vs throughput selesai
Apakah antrian tumbuh karena input naik atau karena output turun? - Queueing latency vs processing time
Apakah waktu habis untuk menunggu giliran, atau habis saat eksekusi? - Retry rate vs downstream errors/timeouts
Apakah retry dipicu kegagalan nyata atau timeout yang salah konfigurasi? - Visibility timeout vs p99 processing time
Apakah timeout lebih pendek dari durasi kerja normal pada tail latency? - Duplicate job vs lock contention
Apakah duplikasi menyebabkan rebutan lock dan memperparah backlog? - Cache hot key vs latency outlier
Apakah sebagian kecil key menjelaskan mayoritas perlambatan? - Write success vs read freshness
Apakah job selesai, tetapi hasilnya belum terlihat karena replication lag atau cache stale?
Contoh arsitektur dan titik observasi
Arsitektur yang sering ditemui:
Producer/API -> Queue -> Worker Pool -> DB/External API -> Cache Invalidation/Event Bus -> Consumer Read PathTitik observasi minimum yang sebaiknya tersedia:
- Producer: rate job masuk, ukuran payload, jenis job, idempotency key
- Queue: depth, oldest message age, visible vs in-flight message count, redelivery count
- Worker: concurrency aktif, processing time per job type, success/failure/retry count, timeout count
- DB: query latency, lock wait, deadlock, connection pool saturation, replication lag
- Cache: hit/miss per key pattern, hot key frequency, lock time saat refresh, eviction burst
- Lock store: contention rate, wait time, lease expiry, orphan lock
- Read path: freshness lag, stale read count, mismatch antara status internal dan tampilan user
Jika salah satu titik ini hilang, tim cenderung mengganti observasi nyata dengan asumsi, dan itu yang melahirkan noise.
Checklist triage saat insiden queue dan worker
Langkah 1: Bedakan masalah kapasitas vs masalah produktivitas
- Apakah laju job masuk naik tajam?
- Apakah throughput selesai turun?
- Apakah worker sibuk menghasilkan output, atau sibuk retry/timeout?
Jika worker aktif tetapi throughput bersih rendah, ini bukan sekadar masalah autoscaling.
Langkah 2: Cek oldest message age dan p95 queueing latency
- Jika age naik terus, backlog benar-benar memburuk.
- Jika depth stabil tetapi age naik, ada starvation atau unfair scheduling.
Langkah 3: Bandingkan p99 processing time dengan visibility timeout
- Jika p99 mendekati atau melewati timeout, curigai redelivery dan duplicate execution.
- Jangan hanya melihat rata-rata durasi job.
Langkah 4: Cek retry, timeout, dan dependency downstream
- Timeout ke database, cache, atau API eksternal
- Rate limit
- Koneksi pool habis
- Deadlock atau lock wait panjang
Langkah 5: Cek cache dan lock
- Apakah ada hot key?
- Apakah banyak worker menunggu lock yang sama?
- Apakah lease lock kedaluwarsa sebelum job selesai?
Langkah 6: Cek consistency lag
- Apakah job sudah selesai tetapi status belum terbaca di sisi pengguna?
- Apakah ada replication lag atau event propagation delay?
Query, log, dan data yang perlu dicek
Nama metrik dan sintaks akan berbeda antar stack, tetapi pola pencariannya relatif sama.
Contoh field log yang sebaiknya ada pada worker
timestamp=2026-08-25T10:15:00Z level=info job_type=send_invoice job_id=abc123 attempt=3
queue=payments worker_id=w-17 started_at=... finished_at=...
processing_ms=18450 queue_wait_ms=92000 visibility_timeout_s=30
idempotency_key=inv-778 lock_wait_ms=2400 cache_key=customer:42
result=timeout downstream=dbField seperti attempt, queue_wait_ms, processing_ms, lock_wait_ms, dan downstream jauh lebih berguna saat triage dibanding log generik “job failed”.
Contoh pertanyaan yang diterjemahkan ke query observability
- Job type mana yang paling banyak retry dalam 15 menit terakhir?
- Adakah korelasi antara retry dan timeout dependency tertentu?
- Apakah duplicate execution meningkat setelah processing time melewati visibility timeout?
- Key cache apa yang paling sering disentuh worker bermasalah?
- Apakah lock wait time meningkat sebelum backlog naik?
- Apakah event write sukses tetapi read side masih stale?
Contoh kueri SQL yang praktis
Untuk melihat lock atau query lambat, sesuaikan dengan database yang dipakai. Secara umum, yang dicari adalah:
-- Cari query aktif yang berjalan lama atau menunggu lock
SELECT
now() AS observed_at,
state,
wait_event,
query
FROM active_queries
WHERE runtime_seconds > 5
ORDER BY runtime_seconds DESC;Untuk tabel job internal aplikasi:
-- Lihat distribusi retry dan umur job
SELECT job_type,
COUNT(*) AS total,
SUM(CASE WHEN attempt > 1 THEN 1 ELSE 0 END) AS retried,
MAX(queue_wait_ms) AS max_queue_wait_ms,
AVG(processing_ms) AS avg_processing_ms
FROM job_execution_log
WHERE created_at >= NOW() - INTERVAL '15 minutes'
GROUP BY job_type
ORDER BY retried DESC, max_queue_wait_ms DESC;Ini bukan sintaks universal, tetapi menunjukkan jenis data yang seharusnya tersedia untuk diagnosis.
Anti-pattern observability yang sering membuat diagnosis salah
1. Hanya mengandalkan rata-rata
Rata-rata menyembunyikan tail latency. Insiden queue sering muncul di p95/p99, bukan di mean.
2. Dashboard global tanpa breakdown per job type
Agregasi global menutupi fakta bahwa satu jenis job sedang merusak seluruh pool worker.
3. Tidak ada korelasi antar-sinyal
Grafik CPU, queue depth, dan error rate yang terpisah sering tidak membantu. Anda butuh dashboard yang menaruh backlog, queueing latency, retry, timeout, dan throughput pada rentang waktu yang sama.
4. Tidak menyimpan attempt number dan idempotency key
Tanpa dua field ini, duplicate job sulit dibedakan dari job baru yang sah.
5. Alert berdasarkan queue depth statis
Queue depth 10.000 mungkin normal di jam tertentu dan kritis di jam lain. Alert yang lebih baik menggunakan kombinasi:
- oldest message age
- drain time
- retry rate
- throughput drop
6. Tidak membedakan sukses teknis dan sukses bisnis
Sebuah job bisa dianggap sukses karena proses selesai tanpa exception, tetapi hasil bisnisnya gagal karena duplicate side effect, data stale, atau event lanjutan tidak terkirim.
Langkah perbaikan agar alert lebih akurat
Gunakan alert berbasis gejala yang bermakna
Lebih baik alert pada kombinasi sinyal seperti:
- oldest message age naik terus selama beberapa interval
- drain time melebihi ambang SLA
- retry rate meningkat bersamaan dengan timeout downstream
- duplicate execution meningkat setelah p99 processing time mendekati visibility timeout
- lock wait time meningkat sebelum throughput turun
Tambahkan metrik turunan
Beberapa metrik turunan lebih berguna daripada metrik mentah:
- effective_throughput: job sukses unik per detik
- duplicate_ratio: eksekusi total dibanding job unik
- retry_amplification: total attempt per job sukses
- freshness_lag: selisih waktu antara write selesai dan read side melihat hasil
- lock_contention_rate: proporsi job yang menunggu lock
Selaraskan timeout, lease, dan retry policy
Aturan praktisnya:
- Visibility timeout harus mempertimbangkan p99 processing time plus buffer yang masuk akal.
- Retry perlu backoff dan jitter agar tidak menciptakan retry storm.
- Lease lock tidak boleh lebih pendek dari operasi kritis normal, tetapi juga tidak terlalu panjang hingga memperlambat recovery saat worker mati.
Nilai persisnya bergantung pada beban dan karakter job, jadi ukur dari data nyata, bukan asumsi.
Terapkan idempotensi pada job yang punya side effect
Jika duplicate execution mungkin terjadi, idempotensi bukan fitur tambahan, tetapi mekanisme keselamatan. Simpan idempotency key, status pemrosesan, atau constraint unik pada operasi yang relevan.
Pisahkan queue atau pool worker berdasarkan karakteristik job
Jangan biarkan job berat, job I/O lambat, dan job ringan berebut worker yang sama jika perilakunya sangat berbeda. Pemisahan ini membantu:
- observability per kelas workload
- pengaturan concurrency yang tepat
- isolasi kegagalan
Contoh tindakan perbaikan berdasarkan pola insiden
Pola: backlog naik, CPU rendah, lock wait tinggi
Kemungkinan akar masalah: contention pada resource bersama, bukan kurang worker.
Tindakan:
- Kurangi concurrency pada job yang berebut lock yang sama
- Shard lock berdasarkan entitas jika memungkinkan
- Perkecil critical section
- Audit apakah duplicate job memperparah contention
Pola: retry naik, throughput datar, timeout downstream meningkat
Kemungkinan akar masalah: dependency melambat atau timeout terlalu agresif.
Tindakan:
- Naikkan timeout hanya jika dependency memang masih layak ditunggu
- Tambahkan circuit breaker atau throttling
- Gunakan exponential backoff dan jitter
- Prioritaskan job yang belum pernah dicoba daripada yang sudah berkali-kali gagal, bila model bisnis memungkinkan
Pola: queue depth normal, user melihat data lama
Kemungkinan akar masalah: consistency lag atau invalidasi cache yang terlambat.
Tindakan:
- Ukur freshness lag end-to-end
- Cek replication lag
- Audit alur invalidasi cache dan pengiriman event
- Pastikan status sukses worker benar-benar berarti data sudah dapat dibaca dari jalur konsumsi yang dipakai user
Pola: duplicate job meningkat setelah lonjakan durasi job
Kemungkinan akar masalah: visibility timeout terlalu pendek atau lease lock kedaluwarsa terlalu cepat.
Tindakan:
- Selaraskan visibility timeout dengan p99 processing time
- Pastikan job idempotent
- Tambahkan heartbeat atau mekanisme lease renewal jika platform mendukung
- Investigasi mengapa durasi job naik: query lambat, API eksternal, hot key cache, atau lock
Penutup
Memisahkan sinyal dari noise saat insiden queue dan worker berarti berhenti mengandalkan indikator tunggal yang terlihat mudah, lalu beralih ke hubungan sebab-akibat antar-metrik. Queue depth, CPU, dan error rate tetap berguna, tetapi nilainya baru kuat jika dibaca bersama queueing latency, throughput efektif, retry, visibility timeout, duplicate execution, lock contention, hot key cache, dan lag antar komponen.
Jika Anda hanya mengingat satu hal, ingat ini: insiden asynchronous jarang dijelaskan oleh satu grafik. Diagnosis yang baik datang dari korelasi. Alert yang baik juga demikian.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!