FrankenPHP vs RoadRunner — mana untuk enterprise
Keduanya cepat, keduanya matang, dan keduanya didukung Octane secara resmi. Perbedaan sesungguhnya bukan pada angka benchmark, melainkan pada arsitektur — dan pada berapa banyak bagian yang harus kamu operasikan.
Intisari
- FrankenPHP: satu proses berisi web server + PHP. Lebih sedikit bagian, TLS dan HTTP/3 bawaan, konkurensi berbasis utas.
- RoadRunner: server Go + proses PHP terpisah. Isolasi lebih kuat, kendali pool lebih detail, ekosistem plugin luas.
- Untuk aplikasi web Laravel biasa, FrankenPHP adalah default yang lebih sederhana.
- Pilih RoadRunner kalau kamu butuh gRPC, Temporal, antrean terkelola server, atau ekstensi PHP yang tidak thread-safe.
- Keputusan terbesar bukan di antara keduanya — melainkan apakah kamu siap untuk worker mode sama sekali.
Perbedaan arsitektur, dan akibatnya
FRANKENPHP
satu proses
├── Caddy: TLS, HTTP/1.1, HTTP/2, HTTP/3, berkas statis, kompresi
└── PHP tertanam (ZTS) — satu utas per permintaan
ROADRUNNER
proses Go proses PHP terpisah
├── plugin http ←→ worker #1
├── plugin jobs ←→ worker #2
├── plugin metrics ←→ worker #3
└── … (dihubungkan lewat pipa)
| Aspek | FrankenPHP | RoadRunner |
|---|---|---|
| Satuan konkurensi | Utas dalam satu proses | Proses terpisah |
| Butuh PHP thread-safe (ZTS) | Ya | Tidak |
| Isolasi antar permintaan | Baik | Lebih kuat — satu crash tidak menyentuh yang lain |
| Memori per unit konkurensi | Lebih kecil | Lebih besar (satu proses PHP penuh) |
| Web server | Termasuk (Caddy) | Perlu di depannya untuk TLS & statis |
| TLS otomatis | Bawaan | Tidak |
| HTTP/3 | Bawaan | Ada di plugin http |
| Kendali pool | Utas, worker, kolam per rute | Sangat detail — TTL, memori, antrean, alokator dinamis |
| Ekosistem plugin | Modul Caddy | Jobs, gRPC, Temporal, KV, Centrifuge |
| Berkas konfigurasi | Caddyfile | .rr.yaml |
| Biner mandiri berisi aplikasi | Ya | Tidak |
| Dukungan Octane | Resmi | Resmi |
| Saran soal Alpine | Hindari (musl lambat untuk ZTS) | Hindari (musl tidak sepenuhnya kompatibel) |
Soal benchmark
Jangan memilih berdasarkan angka benchmark orang lain. Keduanya menghapus biaya bootstrap yang sama, dan setelah itu waktu permintaanmu didominasi query database serta panggilan jaringan — bagian yang identik di kedua runtime. Perbedaan throughput di antara keduanya pada aplikasi Laravel nyata biasanya jauh lebih kecil daripada perbedaan yang dihasilkan satu index yang hilang. Ukur dengan aplikasimu sendiri, dengan beban yang menyerupai lalu lintas aslimu.
Kapan FrankenPHP lebih tepat
| Situasi | Kenapa |
|---|---|
| Aplikasi web Laravel biasa | Satu proses, satu konfigurasi, lebih sedikit yang bisa rusak |
| Ingin mengganti Nginx + PHP-FPM | Bisa dipakai sebagai pengganti langsung, tanpa mengubah kode |
| Butuh TLS otomatis atau HTTP/3 | Bawaan, tanpa komponen tambahan |
| Kontainer dengan memori terbatas | Utas lebih hemat daripada proses |
| Situs yang banyak melayani berkas statis | File server Caddy memang kuat |
| Ingin mendistribusikan aplikasi sebagai satu biner | Fitur yang tidak ada di tempat lain |
| Tim kecil | Permukaan operasional paling sempit |
Kapan RoadRunner lebih tepat
| Situasi | Kenapa |
|---|---|
| Butuh gRPC atau Temporal | Plugin kelas satu; tidak ada padanannya di FrankenPHP |
| Antrean dikelola server yang sama | Plugin jobs — satu proses melayani HTTP dan antrean |
| Ada ekstensi PHP yang tidak thread-safe | RoadRunner memakai proses, bukan utas |
| Butuh kendali pool yang sangat rinci | exec_ttl, max_worker_memory, max_queue_size, alokator dinamis |
| Kode warisan yang rawan crash | Isolasi proses membatasi kerusakan |
| Sudah ada Nginx atau ALB yang mengurus TLS | Web server bawaan jadi tidak memberi nilai tambah |
Rekomendasi
Untuk aplikasi Laravel skala enterprise yang berupa aplikasi web — termasuk yang bertrafik tinggi — mulai dari FrankenPHP. Alasannya operasional, bukan performa: ia satu proses, satu berkas konfigurasi, dan satu hal yang perlu dipantau. Di lingkungan kontainer, setiap komponen tambahan adalah sesuatu yang harus dibangun, di-deploy, dipantau, dan diperbaiki pada pukul dua pagi. FrankenPHP memberi hasil yang setara dengan bagian bergerak yang paling sedikit.
Pindah ke RoadRunner ketika ada kebutuhan konkret yang menariknya — gRPC, Temporal, antrean yang dikelola server, atau ekstensi yang tidak thread-safe. Itu bukan pilihan kedua; itu pilihan yang tepat untuk masalah yang berbeda. Karena keduanya diakses lewat Octane, berpindah nanti berarti mengubah satu opsi, konfigurasi deployment, dan menjalankan ulang uji beban — bukan menulis ulang aplikasi.
Keputusan yang sebenarnya lebih besar
Sebelum memilih di antara keduanya, jawab dulu pertanyaan ini: apakah aplikasimu siap untuk worker mode? Ia menuntut sesuatu yang tidak dituntut PHP-FPM — kode yang tidak menyimpan state antar permintaan, dan disiplin untuk mempertahankannya seiring bertambahnya orang yang menyentuh kode itu.
| Pertanyaan | Kalau jawabannya "tidak" |
|---|---|
| Sudah tidak ada singleton yang menyimpan data permintaan? | Perbaiki dulu — ini risiko kebocoran data |
| Semua paket pihak ketiga mendukung worker mode? | Periksa satu per satu; yang tidak jelas, uji beban panjang |
| Ada pemantauan memori per kontainer? | Pasang dulu — kebocoran harus terlihat |
| Pipeline deploy me-restart worker? | Tambahkan; tanpa itu kode lama tetap jalan |
| Query dan index sudah beres? | Kerjakan itu dulu. Dampaknya lebih besar dan risikonya nol |
Urutan yang menghasilkan perbaikan terbesar per satuan risiko: (1) perbaiki N+1 dan index;
(2) pasang cache HTTP dan CDN untuk halaman yang sama bagi semua orang; (3) php artisan optimize
dan OPcache; (4) skalakan mendatar dengan menambah kontainer; (5) baru worker mode. Banyak aplikasi
yang mengira butuh worker mode sebenarnya butuh langkah kedua — dan langkah kedua tidak menambah satu pun
kelas bug baru.
Jalur adopsi yang aman
- Selesaikan langkah 1–4 di atas. Ukur, dan catat angkanya.
- Jalankan FrankenPHP dalam mode klasik sebagai pengganti Nginx + PHP-FPM. Tidak ada perubahan kode, dan kamu sudah mendapat HTTP/3 serta satu proses yang lebih sederhana.
- Bereskan daftar periksa state dari materi jebakan state.
- Nyalakan worker mode di staging, jalankan uji beban panjang, pantau memorinya.
- Rilis ke produksi untuk sebagian lalu lintas dulu, dengan alarm memori dan 5xx yang siap.
- Baru setelah stabil, setel
num_threads,max_threads, dan sisanya.
Latihan: jalankan uji beban yang sama pada tiga konfigurasi — PHP-FPM, FrankenPHP mode klasik, dan FrankenPHP worker mode — dengan aplikasimu sendiri. Catat throughput, p95, dan pemakaian memori masing-masing. Tabel hasilnya adalah dasar keputusan yang jauh lebih baik daripada rekomendasi siapa pun, termasuk halaman ini.
Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.