1. Alarm Tengah Malam: Saat Layanan Produksi Mulai Tumbang
Pukul 02.14 WIB. PagerDuty di sebelah bantal saya berdering nyaring, memainkan melodi yang paling dihindari oleh setiap Infrastructure Engineer: panggilan darurat tingkat keparahan tinggi. Layar ponsel langsung menyala menampilkan grafik response time API utama yang mendadak melonjak vertikal dari rata-rata 80 milidetik menjadi lebih dari 12.000 milidetik. Di saat yang sama, persentase HTTP 504 Gateway Timeout dari Nginx menembus angka 45%.
Sistem e-commerce skala masif yang kami kelola sedang mengalami serangan jantung mendadak. Pelanggan tidak bisa melakukan checkout, notifikasi email transaksi mandek total, dan webhook pembayaran dari pihak ketiga berjatuhan karena server kami tidak mampu merespons dalam batas waktu yang ditentukan. Web server utama kamiโyang ditenagai oleh PHP-FPM di belakang reverse proxy Nginxโtampak sekarat, kehabisan worker pool seketika. Pertanyaannya, apa yang membuat lalu lintas normal tengah malam ini berubah menjadi mimpi buruk operasional?
Mari kita bedah apa yang sebenarnya terjadi di balik layar sebelum alarm ini berteriak, mengantar kita langsung ke dalam tumpukan log sistem yang berantakan.
2. Jejak Digital: Menelusuri Anomali Log & Lonjakan Metrik
Dengan mata masih setengah terpejam, saya membuka terminal dan langsung melompat ke server produksi menggunakan SSH. Langkah pertama seorang troubleshooter sejati bukanlah menebak-nebak, melainkan mengumpulkan bukti forensik. Saya mulai dengan memantau proses sistem menggunakan htop dan melihat kondisi load average CPU yang sudah menyentuh angka 32 pada mesin 8-core. Ini tidak masuk akal.
Saya langsung memeriksa log error PHP-FPM dan Nginx. Hasilnya langsung menunjuk pada satu tersangka utama:
[pool www] server reached max_children setting (50), consider raising it
2023/10/24 02:12:05 [error] 14232#14232: *89212 upstream timed out (110: Connection timed out) while reading response from upstream, client: 192.168.1.55, server: api.domain.com, request: "POST /v1/checkout HTTP/1.1"
Web server kehabisan proses karena setiap request checkout memaksa web server melakukan koneksi sinkron langsung ke database MySQL dan memicu antrean eksekusi tugas berat secara bersamaan. Padahal, tugas-tugas seperti mengirim email konfirmasi, memanggil API logistik eksternal, dan memperbarui analitik seharusnya tidak dikerjakan di siklus request-response HTTP utama. Tugas-tugas ini dibiarkan menumpuk tanpa manajemen background job yang proper, membuat web server bertindak sebagai buruh pabrik yang kelelahan.
[!WARNING] Jangan pernah membiarkan web server menangani proses berat secara sinkron di dalam siklus request-response HTTP. Gunakan selalu arsitektur asinkron untuk menjaga ketersediaan aplikasi web Anda.
Penelusuran berlanjut ke sistem antrean Redis yang menjadi tumpuan kita. Ternyata, memori Redis hampir penuh karena jutaan payload tugas menumpuk tanpa batas (unbounded queue), dan proses worker yang mengelolanya telah mati total akibat kehabisan memori (OOM Killer). Di sinilah peran Supervisor sebagai pengawas proses menjadi sangat krusial.
3. Membongkar Biang Kerok: Akar Masalah yang Sebenarnya
Setelah menggali lebih dalam, akar masalah dari insiden ini adalah kombinasi mematikan dari tiga hal:
- Ketiadaan Isolasi Beban Kerja: Endpoints API web melakukan enqueue tugas langsung ke database relasional utama lewat mekanisme tabel cron yang berjalan bersamaan, menciptakan race condition parah.
- Worker Daemonic yang Tidak Terkelola: Skrip worker PHP berjalan manual menggunakan perintah
nohupdi latar belakang tanpa alat manajemen proses seperti Supervisor. Ketika terjadi segmentation fault atau memory leak, worker tersebut mati selamanya tanpa ada yang menghidupkan kembali. - Lonjakan Penjadwalan Paralel: Puluhan skrip cron kustom berjalan serentak pada menit ke-0 setiap jam, memicu lonjakan ribuan query database dan membanjiri antrean Redis seketika.
Untuk mengatasi kekacauan ini, kita harus merombak total cara sistem menangani tugas latar belakang. Kita membutuhkan arsitektur yang kokoh: Redis sebagai penyedia struktur data antrean (queue broker) yang sangat cepat, dan Supervisor sebagai daemon process manager yang memastikan worker kita tidak pernah mati kelaparan atau kelelahan.
Mari kita lihat bagaimana mengonfigurasi Supervisor agar bertindak sebagai pengawas yang handal untuk worker queue kita.
4. Tindakan Darurat: Menghidupkan Kembali Layanan dalam Hitungan Menit
Sembari menyusun solusi jangka panjang, kita butuh tindakan darurat (hotfix) untuk menyelamatkan layanan malam itu juga. Eksekusi perintah terminal berikut secara cepat untuk membersihkan antrean Redis yang macet, me-restart layanan web, dan mengaktifkan kembali daemon worker:
# 1. Flush antrean Redis yang korup atau macet secara darurat
redis-cli -h 127.0.0.1 -p 6379 FLUSHDB
# 2. Hentikan seluruh proses PHP-FPM yang menggantung
sudo systemctl restart php8.2-fpm
# 3. Muat ulang konfigurasi Supervisor dan jalankan ulang worker
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl restart all
[!TIP] Pastikan Anda selalu memantau status Supervisor menggunakan perintah
sudo supervisorctl statusuntuk memastikan seluruh worker instance berada dalam statusRUNNINGsetelah insiden.
Berikut adalah contoh konfigurasi Supervisor valid yang kita terapkan untuk mengelola background worker berbasis PHP (misalnya Laravel Queue atau worker custom berbasis Redis) agar berjalan secara stabil dan daemonic:
[program:app-background-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/html/artisan queue:work redis --queue=high,default --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
user=www-data
numprocs=8
redirect_stderr=true
stdout_logfile=/var/www/html/storage/logs/worker.log
stopwaitsecs=3600
Dengan konfigurasi di atas, Supervisor akan otomatis menjalankan 8 instance worker secara paralel. Jika salah satu worker mengalami crash karena kehabisan memori atau error tak terduga, Supervisor akan langsung membangkitkannya kembali dalam hitungan milidetik. Web server utama kini bernapas lega karena beban berat telah didelegasikan sepenuhnya ke antrean Redis ini.
5. Kebijakan Retrospektif: Menambal Celah agar Tak Pernah Terulang
Insiden pukul dua pagi ini memberikan pelajaran mahal. Agar tidak terulang kembali, kita merumuskan kebijakan arsitektural yang ketat:
- Pemisahan Sumber Daya (Resource Isolation): Web server (Nginx/PHP-FPM) dan Redis/Worker Server harus dipisahkan secara fisik atau setidaknya diisolasi alokasi CPU dan memorinya melalui cgroups atau kontainerisasi Docker.
- Penerapan Backpressure & Rate Limiting: Mencegah unbounded queue dengan membatasi jumlah maksimum item di dalam antrean Redis. Jika antrean penuh, sistem harus menolak atau mencatatnya dengan anggun (graceful degradation).
- Distribusi Task yang Seimbang: Menggunakan struktur data List atau Sorted Set di Redis untuk mengelola prioritas tugas, memastikan tugas krusial seperti pembayaran diproses lebih dulu dibandingkan laporan bulanan.
Namun, mengandalkan cron job bawaan sistem operasi Linux untuk memicu tugas terjadwal sering kali menjadi bumerang ketika server mengalami lonjakan beban atau eksekusi memakan waktu lebih lama dari interval cron itu sendiri. Di sinilah kita harus menghindari race condition pada cron job paralel.
6. Pasang Alarm: Otomasi Deteksi Dini untuk Tim On-Call
Sebagai penutup dari rangkaian perbaikan infrastruktur ini, kita tidak boleh menunggu alarm PagerDuty berbunyi karena laporan pengguna. Kita memasang sistem monitoring proaktif menggunakan Prometheus dan Grafana yang dikaitkan dengan Alertmanager.
Berikut adalah aturan alerting (Prometheus Alert Rule) untuk mendeteksi dini penumpukan antrean Redis sebelum berubah menjadi bencana latensi:
groups:
- name: redis-queue-alerts
rules:
- alert: RedisQueueBacklogHigh
expr: redis_list_length{queue="default\