Scaling PHP-FPM dan Nginx untuk High Concurrency Web Apps
Scaling PHP-FPM dan Nginx untuk High Concurrency Web Apps
1. Konteks Industri & Analisis Akar Masalah
Dalam lanskap arsitektur web modern, tantangan terbesar bukanlah sekadar menulis kode aplikasi yang bersih, melainkan bagaimana infrastruktur backend mampu melayani ribuan request konkuren (high concurrency) tanpa mengalami degradasi latensi, kehabisan memori, atau koneksi terputus. Ketika sebuah aplikasi web berbasis PHP (seperti Laravel, Symfony, atau WordPress berskala besar) mengalami lonjakan trafficβbaik karena kampanye pemasaran, serangan DDoS layer 7, maupun momen 11.11βkombinasi Nginx dan PHP-FPM sering kali menjadi benteng pertahanan terakhir.
Secara default, instalasi baru Nginx dan PHP-FPM menggunakan konfigurasi out-of-the-box yang sangat konservatif. Konfigurasi ini dirancang agar dapat berjalan di server dengan spesifikasi minimum (misalnya RAM 512MB). Akibatnya, pada server produksi berkapasitas tinggi (misalnya 16 vCPU dan 32GB RAM), konfigurasi default ini akan menyebabkan bottleneck parah. Request akan menumpuk di antrean (backlog queue), koneksi FastCGI mengalami timeout, worker PHP-FPM kehabisan alokasi memori (memory leak), dan proses Nginx melempar error 502 Bad Gateway atau 504 Gateway Time-out.
Kondisi Sebelum Optimasi (Default):
- Nginx menggunakan asynchronous event-driven model, namun batas koneksi (
worker_connections) dan jumlah proses worker dibiarkan rendah. - PHP-FPM menggunakan proses manajer
dynamicatauondemanddengan alokasi proses yang sangat kecil, menyebabkan lonjakan traffic mendadak langsung memicu proses spawning baru yang lambat. - Timeout FastCGI dibiarkan pendek (60 detik), sehingga operasi database yang kompleks atau eksekusi batch job terputus di tengah jalan.
- Tidak ada pemisahan buffer, mengakibatkan respons HTTP yang besar terpecah-pecah dan membebani memori kernel.
Kondisi Sesudah Optimasi (Enterprise Grade):
- Nginx dikonfigurasi secara presisi memanfaatkan seluruh inti CPU (
worker_processes auto), memaksimalkanworker_connections, dan mengaktifkan keepalive upstream. - PHP-FPM beralih menggunakan strategi
staticuntuk menghilangkan overhead pembuatan proses saat runtime, dengan jumlah proses yang dikalkulasi secara matematis berdasarkan ketersediaan RAM. - Buffer memori dioptimalkan untuk menampung seluruh header dan body request tanpa melakukan penulisan disk I/O sementara (
temp_file). - Latensi turun hingga 70%, kapasitas throughput (RPS) meningkat 5x lipat, dan error 502/504 tereliminasi total.
2. Konsep Inti & Deep Dive Arsitektur
Untuk memahami cara melakukan tuning, kita harus memahami bagaimana Nginx dan PHP-FPM berkomunikasi di balik layar. Arsitektur ini melibatkan pemisahan antara web server (reverse proxy) dan application server (interpreter).
[ Client Browser / CDN (Cloudflare) ]
β
βΌ (HTTPS / HTTP/2 / HTTP/3)
βββββββββββββββββββ
β Nginx Master β (Event-driven, epoll)
ββββββββββ¬βββββββββ
β
Worker Process
β
βΌ (Unix Socket / TCP Loopback)
βββββββββββββββββββββββ
β PHP-FPM Master β
ββββββββββββ¬βββββββββββ
β
βββββββββββ΄ββββββββββ
βΌ βΌ
PHP-FPM Child PHP-FPM Child (Static / Dynamic Worker Pool)
β β
βΌ βΌ
[ MySQL / Redis ] [ S3 / MinIO Storage ]
Alur Eksekusi Data (Data Flow)
- Client Request: Klien mengirimkan HTTP Request melalui jaringan internet. Request ini melewati lapisan keamanan seperti Cloudflare (WAF/CDN), menembus firewall server, dan diterima oleh Nginx Master Process.
- Nginx Worker Handling: Nginx mendistribusikan koneksi ke worker process menggunakan mekanisme asynchronous I/O multiplexing (
epolldi Linux). Jika file yang diminta berupa asset statis (CSS, JS, Gambar), Nginx langsung melayaninya dari disk atau cache. - FastCGI Pass: Jika request tersebut memerlukan eksekusi kode dinamis (misalnya
.php), Nginx meneruskan request tersebut ke PHP-FPM melalui Unix Domain Socket (lebih cepat daripada TCP loopback) atau TCP port. - PHP-FPM Process Pool: PHP-FPM Master Process menerima request dan menyerahkannya ke salah satu Child Process yang sedang idle dalam pool. Child process mengeksekusi skrip PHP, melakukan query ke Database (MySQL/MariaDB) atau Caching layer (Redis).
- Response Cycle: Hasil eksekusi dikembalikan oleh PHP-FPM ke Nginx melalui FastCGI, lalu Nginx mengirimkannya kembali ke klien.
3. Perbandingan Komparatif / Analisis Pendekatan
Pemilihan Process Manager pada PHP-FPM sangat menentukan stabilitas server. Berikut adalah analisis komparatif mendalam antara tiga mode yang tersedia:
| Parameter / Aspek | Mode static |
Mode dynamic |
Mode ondemand |
|---|---|---|---|
| Alokasi Memori | Konstan dan dipesan di awal. | Berfluktuasi antara min_spare dan max_spare. |
Mulai dari 0, bertambah saat ada request. |
| Penggunaan CPU | Rendah (tidak ada overhead pembuatan proses). | Sedang (ada overhead saat spawning/killing). | Tinggi saat lonjakan traffic tiba-tiba (process creation lag). |
| Latensi (TTFB) | Sangat konsisten dan rendah. | Rendah saat load normal, bisa spiking saat scaling. | Tinggi pada request pertama (cold start). |
| Risiko OOM (Out of Memory) | Dapat dihitung secara pasti (pm.max_children * memory_per_process). |
Sulit diprediksi jika traffic melonjak drastis. | Aman dari memori idle, berbahaya saat lonjakan ekstrem. |
| Rekomendasi Penggunaan | Dedicated Server / High Concurrency Production. | Shared Hosting / Medium Traffic App. | Development Server / Low Resource Server. |
[!IMPORTANT] Untuk aplikasi production ber-traffic tinggi, selalu gunakan mode
static. Mode ini menghilangkan latensi mikro yang terjadi saat PHP-FPM harus menciptakan proses baru di tengah lonjakan beban kerja.
4. Prasyarat Sistem & Persiapan Lingkungan
Sebelum melakukan konfigurasi file, pastikan sistem operasi Linux (Ubuntu 22.04/24.04 LTS atau AlmaLinux 9) telah disetel parameter kernel-nya (sysctl) agar mampu menangani ribuan file descriptor dan koneksi jaringan.
Konfigurasi Kernel (/etc/sysctl.conf)
Tambahkan baris berikut untuk mengoptimalkan network stack:
# Meningkatkan jumlah maksimum koneksi dalam antrean listen socket
net.core.somaxconn = 65535
# Meningkatkan rentang port lokal untuk koneksi keluar
net.ipv4.ip_local_port_range = 1024 65535
# Mengaktifkan reuse TIME_WAIT sockets untuk koneksi TCP baru jika aman
net.ipv4.tcp_tw_reuse = 1
# Meningkatkan ukuran backlog jaringan maksimum
net.core.netdev_max_backlog = 10000
# Pengelolaan memori virtual untuk mencegah OOM killer prematur
vm.swappiness = 10
vm.overcommit_memory = 1
Terapkan perubahan dengan perintah:
sysctl -p
Konfigurasi Limit Sistem File (/etc/security/limits.conf)
Pastikan user nginx dan www-data dapat membuka file descriptor dalam jumlah tak terbatas:
www-data soft nofile 65535
www-data hard nofile 65535
nginx soft nofile 65535
nginx hard nofile 65535
5. Panduan Implementasi Langkah demi Langkah
Berikut adalah konfigurasi lengkap dan siap produksi untuk Nginx dan PHP-FPM.
A. Konfigurasi Nginx (/etc/nginx/nginx.conf)
user nginx;
worker_processes auto;
worker_cpu_affinity auto;
worker_rlimit_nofile 65535;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 10240;
use epoll;
multi_accept on;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'rt=$request_time uct="$upstream_connect_time" uht="$upstream_header_time" urt="$upstream_response_time"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
keepalive_requests 1000;
types_hash_max_size 2048;
server_tokens off;
# Buffer Optimization
client_body_buffer_size 128k;
client_max_body_size 64M;
client_header_buffer_size 1k;
large_client_header_buffers 4 16k;
output_buffers 1 32k;
postpone_output 1460;
# Timeout Optimization
client_header_timeout 10s;
client_body_timeout 10s;
send_timeout 10s;
# Gzip Compression
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 5;
gzip_min_length 256;
gzip_types
application/atom+xml
application/javascript
application/json
application/rss+xml
application/vnd.ms-fontobject
application/x-font-ttf
application/x-web-app-manifest+json
application/xhtml+xml
application/xml
font/opentype
image/svg+xml
image/x-icon
text/css
text/plain
text/x-component;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
B. Konfigurasi Virtual Host Nginx (/etc/nginx/sites-available/app.conf)
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
root /var/www/html/public;
index index.php index.html index.htm;
# SSL Configuration (Let's Encrypt)
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;
ssl_session_tickets off;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
error_page 404 /index.php;
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
# FastCGI Buffer Tuning
fastcgi_buffer_size 128k;
fastcgi_buffers 256 16k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
# FastCGI Timeout Tuning
fastcgi_connect_timeout 60s;
fastcgi_send_timeout 300s;
fastcgi_read_timeout 300s;
fastcgi_keepalive_on on;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
C. Konfigurasi PHP-FPM Pool (/etc/php/8.2/fpm/pool.d/www.conf)
[www]
user = nginx
group = nginx
listen = /run/php/php8.2-fpm.sock
listen.owner = nginx
listen.group = nginx
listen.mode = 0660
pm = static
pm.max_children = 120
pm.max_requests = 1000
php_admin_value[memory_limit] = 256M
php_admin_value[max_execution_time] = 300
php_admin_value[post_max_size] = 64M
php_admin_value[upload_max_filesize] = 64M
catch_workers_output = yes
decorate_workers_output = no
6. Bedah Kode & Penjelasan Detail Baris Kunci
Analisis mendalam terhadap parameter-parameter vital yang menentukan performa sistem:
-
worker_processes auto;&worker_cpu_affinity auto;(Nginx): Memastikan Nginx membuat worker process sejumlah core CPU yang tersedia dan mengikat (pinning) setiap proses worker ke core fisik tertentu. Ini mengurangi context switching antar core CPU dan mendongkrak efisiensi cache L1/L2 CPU. -
worker_connections 10240;(Nginx): Menentukan jumlah maksimum koneksi simultan yang dapat dibuka oleh setiap worker process. Dengan nilai 10240 dan 8 core CPU, Nginx secara teoritis mampu menangani lebih dari 80.000 koneksi konkuren secara bersamaan. -
pm = static&pm.max_children = 120(PHP-FPM): Formula penghitunganpm.max_childrendidasarkan pada total RAM yang didedikasikan untuk PHP dibagi dengan rata-rata konsumsi memori per proses PHP (misalnya: RAM 32GB, dikurangi 8GB untuk sistem, OS, MySQL, dan Redis, menyisakan 24GB untuk PHP-FPM. Jika satu proses PHP memakan 200MB, maka $24576 / 200 pprox 122$ proses). Kita tetapkan 120 agar aman. -
pm.max_requests = 1000(PHP-FPM): Mencegah memory leak jangka panjang. Setiap child process akan didaur ulang otomatis setelah melayani 1000 request, membebaskan memori yang mungkin bocor oleh pustaka pihak ketiga. -
fastcgi_buffers 256 16k;(Nginx): Menentukan jumlah dan ukuran buffer untuk membaca respons dari PHP-FPM. Jika respons dari aplikasi PHP melebihi ukuran buffer standar, Nginx akan menulisnya ke file temporary di disk (fastcgi_temp), yang menyebabkan lonjakan I/O disk (bottleneck). Memperbesar buffer menjaga seluruh respons tetap berada di RAM (Memory Caching).
7. Skenario Produksi & Studi Kasus Dunia Nyata
Studi Kasus: Sebuah platform e-commerce enterprise mengalami lonjakan traffic flash sale hingga 50.000 request per detik (RPS). Infrastruktur menggunakan Load Balancer (AWS ALB) mengarah ke 3 node Application Server (masing-masing 16 vCPU, 32GB RAM).
Permasalahan Awal:
Saat flash sale dimulai, server mendadak lumpuh dengan error 504 Gateway Time-out dan lonjakan penggunaan CPU hingga 100% pada wait I/O disk.
Solusi Penerapan:
- Menerapkan konfigurasi PHP-FPM mode
staticdenganpm.max_children = 140per node. - Mengonfigurasi Nginx FastCGI buffer besar (
256 16k) untuk mencegah penulisan file temporary. - Memindahkan session penyimpanan PHP dan query caching ke kluster Redis terpusat.
- Mengaktifkan Nginx upstream keepalive agar koneksi reuse ke PHP-FPM tidak membuka socket baru setiap saat.
Hasil Akhir: Sistem mampu mempertahankan latensi rata-rata (TTFB) di bawah 45ms, throughput stabil di 52.000 RPS, dan zero error rate selama 3 jam jalannya flash sale.
8. Common Pitfalls, Anti-Patterns & Solusi
-
Anti-Pattern 1: Menggunakan Mode
dynamicdenganpm.max_childrenTerlalu Besar. Dampak: Saat traffic melonjak, PHP-FPM akan spawn ratusan proses seketika, menghabiskan RAM fisik, memicu Linux OOM Killer untuk membunuh proses MySQL atau Nginx secara acak. Solusi: Gunakan modestaticdengan perhitungan memori yang ketat. -
Anti-Pattern 2: Mengabaikan Pengaturan
client_max_body_size. Dampak: Upload file berukuran besar gagal dengan error413 Request Entity Too Largetanpa penjelasan yang jelas di log aplikasi. Solusi: Sesuaikan nilai ini secara eksplisit di level Nginx block HTTP atau Server. -
Anti-Pattern 3: Menggunakan TCP Loopback (
127.0.0.1:9000) untuk Komunikasi Nginx ke PHP-FPM. Dampak: Overhead jaringan TCP stack (port allocation, checksum) padahal Nginx dan PHP berada di mesin fisik yang sama. Solusi: Selalu gunakan Unix Domain Socket (unix:/run/php/php-fpm.sock) untuk performa komunikasi inter-process yang optimal.
9. Benchmark, Metrik Kinerja & Tuning Performa
Lakukan pengujian beban menggunakan tool modern seperti k6 atau wrk untuk mengukur ketahanan infrastruktur.
Skrip Benchmark k6 (load-test.js)
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
stages: [
{ duration: '1m', target: 500 }, // Ramp-up ke 500 users dalam 1 menit
{ duration: '3m', target: 2000 }, // Pertahankan 2000 concurrent users selama 3 menit
{ duration: '1m', target: 0 }, // Ramp-down ke 0
],
};
export default function () {
const res = http.get('https://example.com/');
check(res, {
'status is 200': (r) => r.status === 200,
'response time < 200ms': (r) => r.timings.duration < 200,
});
sleep(1);
}
Cara Menjalankan Benchmark
k6 run load-test.js
Interpretasi Hasil:
- Perhatikan metrik
http_req_duration(p95 dan p99). Jika p99 melonjak tinggi sementara CPU masih longgar, indikasi utamanya adalah kurangnya worker PHP-FPM atau antreanlisten queueNginx yang penuh. - Pantau penggunaan sumber daya secara real-time menggunakan
htop,vmstat 1, dannginxstubstatusmodule.
10. Checklist Penerapan Produksi & Kesimpulan
Sebelum merilis konfigurasi ini ke lingkungan produksi live, pastikan seluruh checklist berikut telah terpenuhi:
- Parameter kernel
sysctl.conf(somaxconn,netdev_max_backlog) sudah disesuaikan. - Limit file descriptor (
nofile) sistem operasi dan service telah ditingkatkan menjadi minimal65535. - PHP-FPM menggunakan mode
staticdengan perhitunganpm.max_childrenberdasarkan alokasi RAM yang akurat. - Komunikasi Nginx ke PHP-FPM menggunakan Unix Domain Socket dengan permission
0660dan kepemilikan user yang sesuai. - Buffer Nginx dan FastCGI (
fastcgi_buffers,client_body_buffer_size) telah diperbesar untuk menghindari disk I/O temporary. - Log rotasi telah dikonfigurasi untuk mencegah disk penuh akibat lonjakan access log.
- Monitoring metrik (Prometheus + Grafana / New Relic) terpasang untuk memantau error 502/504 secara real-time.
Dengan menerapkan arsitektur dan konfigurasi tingkat lanjut ini, aplikasi PHP Anda bertransformasi menjadi sistem high concurrency yang tangguh, siap menghadapi lonjakan traffic enterprise apa pun tanpa kompromi terhadap stabilitas dan keamanan.