Pool & supervisor RoadRunner
Di sinilah RoadRunner menonjol. Pool-nya punya pengawas bawaan yang bisa membunuh worker yang bocor, memutus permintaan yang menggantung, dan menambah worker saat beban naik — semuanya deklaratif.
Intisari
num_workersmenentukan konkurensi; nol berarti sejumlah CPU logis.- Supervisor mengawasi TTL, waktu menganggur, memori, dan durasi eksekusi.
- Batas lunak menunggu permintaan selesai; batas keras (
exec_ttl) memutusnya. max_queue_sizemenolak permintaan berlebih alih-alih mengantre tanpa batas.dynamic_allocatormenambah worker sementara saat lonjakan, lalu menguranginya lagi.
Konfigurasi pool lengkap
pool:
# Berapa proses PHP yang dijalankan. 0 = jumlah CPU logis.
num_workers: 8
# Restart worker setelah sekian permintaan. 0 = tanpa batas.
max_jobs: 500
# Tolak permintaan kalau antrean internal sudah sepanjang ini. 0 = tanpa batas.
max_queue_size: 100
allocate_timeout: 60s
destroy_timeout: 60s
# Menambah worker sementara saat semua sedang sibuk
dynamic_allocator:
max_workers: 25
spawn_rate: 10
idle_timeout: 10s
supervisor:
watch_tick: 5s
ttl: 0s # umur maksimum worker (lunak)
idle_ttl: 10s # lama menganggur sebelum dimatikan (lunak)
max_worker_memory: 256 # MB (lunak)
exec_ttl: 60s # durasi maksimum satu permintaan (KERAS)
Batas lunak versus keras
| Batas | Jenis | Perilaku saat terlampaui |
|---|---|---|
ttl | Lunak | Worker dimatikan setelah permintaannya selesai |
idle_ttl | Lunak | Worker yang menganggur dimatikan |
max_worker_memory | Lunak | Worker diganti setelah permintaan selesai |
exec_ttl | Keras | Permintaan diputus di tengah jalan |
exec_ttl adalah pengaman yang paling berharga di produksi. Ia memutus permintaan yang
menggantung — misalnya karena panggilan API luar tanpa timeout — sehingga worker itu kembali tersedia. Tanpa
itu, sepuluh permintaan macet pada delapan worker berarti aplikasi berhenti melayani siapa pun, dan tidak ada
apa pun di dalam PHP yang bisa memulihkannya.
max_jobs versus max_worker_memory
Keduanya menangani masalah yang sama — kebocoran memori — dengan cara berbeda. Dokumentasi RoadRunner memberi
saran yang tegas: kalau tujuanmu mengendalikan memori, pakai supervisor.max_worker_memory,
bukan pool.max_jobs.
max_jobs | max_worker_memory | |
|---|---|---|
| Pemicu | Jumlah permintaan | Pemakaian memori sesungguhnya |
| Restart yang tidak perlu | Sering — worker sehat pun ikut | Hanya yang memang membengkak |
| Melindungi dari kebocoran cepat | Kurang — bisa meledak sebelum hitungannya tercapai | Ya |
| Mudah diprediksi | Ya | Bergantung beban |
Pola yang sehat: pasang max_worker_memory sebagai pertahanan utama, dan max_jobs dengan
angka besar sebagai jaring pengaman kedua untuk kebocoran yang bukan berupa memori — misalnya file
descriptor yang tidak pernah ditutup.
Penskalaan dinamis
pool:
num_workers: 4 # selalu ada
dynamic_allocator:
max_workers: 25 # boleh naik sampai sini
spawn_rate: 10 # berapa yang dibuat sekaligus saat kekurangan
idle_timeout: 10s # dikurangi lagi setelah menganggur selama ini
Manfaatnya: kamu tidak perlu memesan memori untuk 25 worker sepanjang waktu, tapi tetap sanggup menyerap
lonjakan. Yang perlu diperhatikan — menyalakan worker PHP baru bukan operasi gratis; ia harus mem-bootstrap
aplikasi dari nol. Untuk lonjakan yang sangat tiba-tiba, menaikkan num_workers lebih dapat
diandalkan.
Berapa worker yang tepat
| Sifat beban | Saran dokumentasi |
|---|---|
| Terikat CPU | Pantau beban CPU, targetkan 90–95%; sisakan sedikit untuk GC Go |
| Terikat I/O | Sebanyak yang muat di memori — worker itu murah |
| Umum | Setara jumlah utas CPU sebagai titik awal |
| Referensi memori | Worker "hello world" memakai sekitar 26 MB RSS |
26 MB itu untuk worker kosong. Worker Laravel yang sudah mem-bootstrap seluruh aplikasi beserta
paket-paketnya jauh lebih besar — ukur sendiri dengan ./rr workers -i. Angka itulah yang harus
kamu kalikan dengan num_workers untuk memastikan muat di dalam jatah memori kontainer.
Antrean internal
pool:
max_queue_size: 100
Saat semua worker sibuk, permintaan menunggu di antrean internal. Tanpa batas, antrean itu tumbuh sampai pengguna sudah menyerah menunggu — servermu tetap mengerjakan permintaan yang tidak ada lagi yang menunggunya. Dengan batas, permintaan berlebih ditolak seketika, dan load balancer bisa mengarahkannya ke kontainer lain. Menolak cepat lebih baik daripada lambat merata.
Mode pengembangan
pool:
debug: true # tidak pre-alokasi; satu worker dibuat saat permintaan datang
Dalam mode ini, worker dibuat baru untuk tiap permintaan — artinya perubahan kodemu langsung terlihat, seperti PHP-FPM. Sangat berguna saat mengembangkan; jangan pernah dipakai di produksi, karena seluruh keuntungan worker mode hilang.
Rekomendasi produksi
- Jangan dengarkan RPC di
0.0.0.0kecuali memang perlu lintas kontainer. relay: pipes— sedikit lebih cepat daripada soket Unix.- Setel
memory_limitPHP 10–20% di bawahmax_worker_memory. opcache.enable_cli=1— worker adalah proses CLI.- Pakai endpoint health check saat berjalan di lingkungan cloud.
- Hindari image berbasis Alpine — musl tidak sepenuhnya cocok dengan biner Go RoadRunner dan sebagian ekstensi PHP.
- Koneksi keep-alive memberi peningkatan performa yang besar; pastikan load balancer memakainya.
Latihan: setel max_worker_memory: 128 dan buat rute yang sengaja mengisi array statis
sedikit demi sedikit. Panggil berulang sambil memantau ./rr workers -i, dan amati supervisor
mengganti worker saat ambang batasnya terlampaui.
Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.