L
JavaScript β€’ Literally Web ID

Scaling PHP-FPM dan Nginx untuk High Concurrency Web Apps

⏱️ 15 menit baca β€’ πŸ“… 12 Oct 2026 β€’ πŸ‘οΈ 1 views
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 dynamic atau ondemand dengan 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), memaksimalkan worker_connections, dan mengaktifkan keepalive upstream.
  • PHP-FPM beralih menggunakan strategi static untuk 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)

  1. 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.
  2. Nginx Worker Handling: Nginx mendistribusikan koneksi ke worker process menggunakan mekanisme asynchronous I/O multiplexing (epoll di Linux). Jika file yang diminta berupa asset statis (CSS, JS, Gambar), Nginx langsung melayaninya dari disk atau cache.
  3. 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.
  4. 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).
  5. 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:

  1. 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.

  2. 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.

  3. pm = static & pm.max_children = 120 (PHP-FPM): Formula penghitungan pm.max_children didasarkan 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.

  4. 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.

  5. 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:

  1. Menerapkan konfigurasi PHP-FPM mode static dengan pm.max_children = 140 per node.
  2. Mengonfigurasi Nginx FastCGI buffer besar (256 16k) untuk mencegah penulisan file temporary.
  3. Memindahkan session penyimpanan PHP dan query caching ke kluster Redis terpusat.
  4. 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 dynamic dengan pm.max_children Terlalu 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 mode static dengan perhitungan memori yang ketat.

  • Anti-Pattern 2: Mengabaikan Pengaturan client_max_body_size. Dampak: Upload file berukuran besar gagal dengan error 413 Request Entity Too Large tanpa 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 antrean listen queue Nginx yang penuh.
  • Pantau penggunaan sumber daya secara real-time menggunakan htop, vmstat 1, dan nginxstubstatus module.

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 minimal 65535.
  • PHP-FPM menggunakan mode static dengan perhitungan pm.max_children berdasarkan alokasi RAM yang akurat.
  • Komunikasi Nginx ke PHP-FPM menggunakan Unix Domain Socket dengan permission 0660 dan 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.

🏷️ Tags: #Nginx #High Concurrency #Performance #Sysadmin #Web Server