PHP-FPM Process Manager Türleri: Static, Dynamic ve Ondemand Karşılaştırması

Sunucu yönetiminde PHP uygulamalarının performansını etkileyen en kritik kararlardan biri, PHP-FPM’in process manager yapılandırmasıdır. Yanlış seçilmiş bir PM türü, trafiğin az olduğu saatlerde gereksiz kaynak tüketimine, yoğun dönemlerde ise site çöküşlerine yol açabilir. Bu yazıda üç farklı process manager türünü, hangisinin ne zaman kullanılması gerektiğini ve gerçek dünya senaryolarında nasıl davrandıklarını ele alacağız.

PHP-FPM Process Manager Nedir?

PHP-FPM (FastCGI Process Manager), PHP uygulamalarını çalıştırmak için kullanılan bir FastCGI implementasyonudur. Nginx veya Apache gibi web sunucularının arkasında çalışır ve PHP isteklerini işleyen worker process’leri yönetir.

Process Manager, bu worker process’lerin nasıl oluşturulacağını, kaç tanesinin bellekte hazır bekleyeceğini ve yük altında nasıl davranacağını belirler. PHP-FPM’de üç farklı PM türü bulunur:

  • static: Sabit sayıda process her zaman çalışır
  • dynamic: Process sayısı talebe göre min/max sınırlar arasında değişir
  • ondemand: İstek geldiğinde process oluşturulur, boşta kalınca öldürülür

Bu seçim, özellikle birden fazla PHP uygulaması barındıran sunucularda bellek yönetimi açısından hayati önem taşır. Hadi her birini derinlemesine inceleyelim.

Static Process Manager

Nasıl Çalışır?

Static modunda, PHP-FPM başladığında pm.max_children parametresinde belirtilen sayıda process oluşturur ve bu process’leri sürekli ayakta tutar. Trafik az olsun çok olsun, process sayısı hiç değişmez.

; /etc/php/8.2/fpm/pool.d/www.conf

[www]
pm = static
pm.max_children = 20
pm.max_requests = 500

Bu konfigürasyonda sunucu başlar başlamaz 20 PHP worker process belleğe alınır ve hiç biri kapatılmaz. Her istek bu 20 process’ten birine yönlendirilir. pm.max_requests parametresi ise bir process’in kaç istek işledikten sonra yeniden başlatılacağını belirler. Bu değer, PHP uygulamalarındaki memory leak sorunlarını frenlemek için kullanılır.

Static Modunun Avantajları

  • Sıfır ısınma süresi: Process’ler zaten hazır olduğu için ilk istek anında işlenir
  • Öngörülebilir kaynak kullanımı: Kaç process çalışacağı baştan bellidir, bellek kullanımı sabit kalır
  • Düşük CPU yükü: Process oluşturma ve yok etme işlemleri CPU’ya ciddi yük bindirirken static modda bu işlemler yaşanmaz
  • Spike trafiğe dayanıklılık: Ani trafik artışlarında process pool zaten hazır olduğundan sistem daha stabil davranır

Static Modunun Dezavantajları

  • Sabit bellek tüketimi: Gece 03:00’te hiç istek gelmese bile 20 process belleği işgal eder
  • Yanlış hesaplama riski: max_children değerini yanlış ayarlarsanız ya belleği patlatırsınız ya da kapasiteyi boşa harcarsınız

max_children Değerini Nasıl Hesaplarsınız?

Bu konuda deneyimli sysadmin’lerin kullandığı klasik formül şudur:

# Mevcut PHP-FPM process'lerinin ortalama bellek kullanımını öğrenin
ps -ylC php-fpm8.2 --sort:rss | awk '{sum += $8; count++} END {print "Ortalama:", sum/count, "KB"}'

# Toplam kullanılabilir belleği görün
free -m | awk '/^Mem:/{print $7}'

Diyelim ki her PHP process ortalama 50MB RAM kullanıyor ve sisteminizde PHP-FPM için 2GB RAM ayırdınız. Hesap şu şekilde yapılır:

max_children = kullanılabilir_ram / ortalama_process_boyutu
max_children = 2048MB / 50MB = ~40

Ama bunu direkt kullanmayın. Sisteminizde başka servisler de (MySQL, Redis, Nginx) RAM kullandığından, hesaplanan değerin %70-80’ini alın. Pratikte bu değeri belirledikten sonra mutlaka yük testi yaparak doğrulayın.

Static Mod Ne Zaman Kullanılmalı?

Static mod, aşağıdaki durumlarda ideal seçimdir:

  • Yalnızca tek bir uygulama barındıran, yüksek trafikli production sunucuları
  • Trafiğin gün içinde görece sabit seyrettiği sistemler
  • Yanıt süresinin kritik öneme sahip olduğu uygulamalar (e-ticaret, finans)
  • Sunucunun tüm RAM’ini PHP-FPM’e ayırabildiğiniz durumlar

Dynamic Process Manager

Nasıl Çalışır?

Dynamic mod, PHP-FPM’in varsayılan ve en yaygın kullanılan modudur. Bu modda process sayısı talebe göre belirlenen sınırlar içinde otomatik olarak ayarlanır.

; /etc/php/8.2/fpm/pool.d/www.conf

[www]
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 3
pm.max_spare_servers = 10
pm.max_requests = 1000
pm.process_idle_timeout = 10s

Bu parametrelerin ne anlama geldiğini tek tek açıklayalım:

  • pm.max_children: Aynı anda çalışabilecek maksimum process sayısı. Bu sınır aşıldığında yeni istekler kuyruğa alınır
  • pm.start_servers: PHP-FPM başladığında oluşturulacak process sayısı
  • pm.min_spare_servers: Her zaman hazırda beklemesi gereken minimum boşta process sayısı. Bu sayının altına düşüldüğünde yeni process’ler oluşturulur
  • pm.max_spare_servers: Boşta bekleyebilecek maksimum process sayısı. Bu sayının üzerine çıkıldığında fazladan process’ler kapatılır
  • pm.max_requests: Bir process’in kaç istek işledikten sonra yeniden başlatılacağı
  • pm.process_idle_timeout: Bu parametre dynamic modda etkisizdir, ondemand moduna özgüdür

Dynamic mod şu şekilde çalışır: Sistem başladığında start_servers kadar process açılır. İstekler gelip min_spare_servers‘ın altına düşüldükçe yeni process’ler doğar. Trafik azaldığında max_spare_servers sınırını aşan process’ler öldürülür. Ancak process sayısı hiçbir zaman min_spare_servers‘ın altına inmez.

Dynamic Modun Avantajları

  • Esnek kaynak kullanımı: Az trafikte az kaynak, çok trafikte çok kaynak kullanır
  • Orta yol çözümü: Static modun katılığı ile ondemand modun yavaşlığı arasında denge kurar
  • Birden fazla pool yönetimi: Farklı uygulamalar için ayrı pool’lar tanımlandığında belleği daha verimli kullanır

Dynamic Modun Dezavantajları

  • Konfigürasyon karmaşıklığı: Dört farklı parametre arasındaki dengeyi doğru kurmak dikkat gerektirir
  • Process spawn maliyeti: Ani trafik artışlarında yeni process’ler oluşturulurken gecikme yaşanabilir
  • Yanlış parametre tuzağı: min_spare_servers > start_servers gibi hatalı konfigürasyonlar PHP-FPM’in başlamasını engelleyebilir

Gerçek Dünya Senaryosu: Çoklu Uygulama Sunucusu

Bir müşterimizin sunucusunda üç farklı WordPress sitesi ve bir Laravel uygulaması çalışıyordu. Başlangıçta hepsi static modla konfigüre edilmişti ve toplam 80 PHP process sürekli bellekte duruyordu. Sunucu 8GB RAM’e sahipti, bu process’ler tek başına yaklaşık 4GB RAM tüketiyordu.

Dynamic moda geçince şu konfigürasyonu uyguladık:

; WordPress siteleri için (yoğun trafik)
[wordpress_site1]
pm = dynamic
pm.max_children = 15
pm.start_servers = 3
pm.min_spare_servers = 2
pm.max_spare_servers = 5
pm.max_requests = 500

; Laravel uygulaması için (backend API, düşük ama kritik trafik)
[laravel_api]
pm = dynamic
pm.max_children = 20
pm.start_servers = 5
pm.min_spare_servers = 4
pm.max_spare_servers = 8
pm.max_requests = 1000

Gece saatlerinde RAM kullanımı 4GB’den 1.5GB’e düştü. Gündüz yoğun saatlerde ise sistem ihtiyaç duyduğu kadar process açıp kapattı. MySQL’e kalan bellek arttı ve genel performans iyileşti.

start_servers Değeri İçin Pratik Kural

start_servers = (min_spare_servers + max_spare_servers) / 2

Bu formül PHP-FPM’in kendi dokümantasyonunda da önerilen değerdir. Yukarıdaki WordPress örneğinde: (2 + 5) / 2 = 3.5, yani 3 veya 4 olarak ayarlanabilir.

Ondemand Process Manager

Nasıl Çalışır?

Ondemand mod en “lazy” yaklaşımdır. PHP-FPM başladığında hiç process oluşturmaz. İstek geldiğinde bir process doğar, o isteği işler ve pm.process_idle_timeout süresi boyunca bekler. Bu süre dolduğunda process öldürülür.

; /etc/php/8.2/fpm/pool.d/www.conf

[www]
pm = ondemand
pm.max_children = 50
pm.process_idle_timeout = 10s
pm.max_requests = 200

Bu modda parametre listesi diğerlerine göre oldukça sadedir:

  • pm.max_children: Maksimum eş zamanlı process sayısı
  • pm.process_idle_timeout: Bir process’in boşta ne kadar süre bekleyeceği. Varsayılan 10 saniyedir
  • pm.max_requests: Her process’in kaç istek işleyeceği

Ondemand Modunun Avantajları

  • Minimum boşta kaynak kullanımı: Hiç istek yoksa hiç process çalışmaz
  • Çok sayıda düşük trafikli site barındırma: 50-100 düşük trafikli siteyi tek sunucuda tutmak için idealdir
  • Basit konfigürasyon: Sadece iki veya üç parametre ayarlamak yeterlidir

Ondemand Modunun Dezavantajları

  • İlk istek gecikmesi (cold start): Process oluşturma süresi ek gecikme getirir. PHP ve Composer autoloading ile bu gecikme 100-500ms arasında olabilir
  • Tutarsız yanıt süreleri: İlk kullanıcı yavaş yanıt alırken sonrakiler normal alır, bu UX sorunlarına yol açar
  • Cron ve arka plan görevler için sorunlu: Düzenli çalışan scriptler process’i sürekli öldürüp oluşturur
  • Monitoring zorluğu: Process’ler gelip gittiğinden anlık izleme grafikleri dalgalı görünür

Gerçek Dünya Senaryosu: Hosting Ortamı

Ondemand modunun gerçekten parladığı yer, shared hosting veya ajans tipi ortamlardır. Diyelim ki 80 farklı küçük müşteri sitesini tek bir sunucuda barındırıyorsunuz. Bu sitelerin yüzde doksanı günde sadece birkaç yüz ziyaretçi alıyor.

Static veya dynamic modda her site için en az 3-5 process ayırsanız, boşta 400 process tutmuş olursunuz. Ondemand modunda ise aktif trafik olmayan siteler sıfır process kullanır:

; Her müşteri için ayrı pool
[musteri_sitesi_001]
pm = ondemand
pm.max_children = 5
pm.process_idle_timeout = 30s
pm.max_requests = 100

[musteri_sitesi_002]
pm = ondemand
pm.max_children = 5
pm.process_idle_timeout = 30s
pm.max_requests = 100

Böyle bir yapıda 80 site için toplam kullanılan process sayısı, anlık aktif site sayısıyla orantılı olur. Yoğun saatlerde 20 site aktifse 100 process, gece 03:00’te hiç istek yoksa 0 process çalışır.

process_idle_timeout Optimizasyonu

Bu değeri ne kadar küçük tutarsanız bellek o kadar hızlı serbest kalır, ama cold start problemi o kadar sık yaşanır. Genellikle önerilen değer aralığı 10-60 saniyedir. Aşağıdaki gibi bir yaklaşım kullanabilirsiniz:

  • Sık ziyaret edilen siteler: 30-60 saniye
  • Ara sıra ziyaret edilen siteler: 10-15 saniye
  • Cron ile sadece belirli saatlerde çalışan scriptler: 5 saniye

PHP-FPM Durum Sayfası ile İzleme

Hangi PM modunu kullandığınızdan bağımsız olarak, PHP-FPM’in durum sayfasını aktifleştirmenizi kesinlikle tavsiye ederim. Bu sayfa process yönetimi kararlarınızı verirken inanılmaz yardımcı olur.

; www.conf içinde
pm.status_path = /php-fpm-status

Nginx konfigürasyonunda bu yolu sadece local erişime açın:

server {
    listen 127.0.0.1:80;
    
    location /php-fpm-status {
        access_log off;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
    }
}

Durum sayfasını sorgulamak için:

# Özet bilgi
curl -s http://127.0.0.1/php-fpm-status

# Tüm process detayları
curl -s "http://127.0.0.1/php-fpm-status?full"

# JSON formatında (monitoring araçlarıyla entegrasyon için)
curl -s "http://127.0.0.1/php-fpm-status?json"

Bu çıktıdan dikkat etmeniz gereken metrikler:

  • active processes: Şu anda istek işleyen process sayısı
  • idle processes: Boşta bekleyen process sayısı
  • max active processes: Şimdiye kadar görülen en yüksek aktif process sayısı
  • max children reached: Bu sayı sıfırdan büyükse max_children değerinizi artırmalısınız

Gerçek Zamanlı Monitoring Script’i

Prodüksiyonda şunu kullanıyorum, basit ama işlevsel:

#!/bin/bash
# php-fpm-monitor.sh
# Her 5 saniyede PHP-FPM durumunu loglar

LOGFILE="/var/log/php-fpm-monitor.log"
STATUS_URL="http://127.0.0.1/php-fpm-status?json"

while true; do
    TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
    STATUS=$(curl -s "$STATUS_URL" 2>/dev/null)
    
    if [ -n "$STATUS" ]; then
        ACTIVE=$(echo $STATUS | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['active processes'])")
        IDLE=$(echo $STATUS | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['idle processes'])")
        TOTAL=$(echo $STATUS | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['total processes'])")
        MAX_CHILDREN=$(echo $STATUS | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['max children reached'])")
        
        echo "$TIMESTAMP | Active: $ACTIVE | Idle: $IDLE | Total: $TOTAL | MaxChildrenReached: $MAX_CHILDREN" >> "$LOGFILE"
    fi
    
    sleep 5
done

Hangi PM Modunu Seçmelisiniz?

Bu sorunun cevabı büyük ölçüde sunucu kullanım senaryonuza bağlıdır. Şöyle bir karar çerçevesi oluşturabilirsiniz:

Static Mod İçin İdeal Senaryolar

  • Tek uygulama, yüksek trafik: Yalnızca bir uygulamaya adanmış sunucularda, tüm RAM’i PHP’ye verebilirsiniz
  • E-ticaret ve fintech: Yanıt süresindeki küçük farklılıklar bile dönüşüm oranını etkilediğinde
  • Sabit trafik profili: Analitik verileriniz trafiğin gün içinde çok az değiştiğini gösteriyorsa
  • Kısıtlı sunucu sayısı: Load balancer arkasında az sayıda güçlü sunucu çalışıyorsa

Static modu tercih ettiğinizde mutlaka şu hesabı yapın:

# PHP-FPM process'lerinin gerçek zamanlı ortalama belleğini ölçün
watch -n 2 'ps -ylC php-fpm8.2 --sort:rss | tail -n +2 | awk "{sum+=$8} END {printf "Toplam: %.0f MB | Ortalama: %.0f MB | Adet: %dn", sum/1024, sum/NR/1024, NR}"'

Dynamic Mod İçin İdeal Senaryolar

  • Dalgalı trafik profili: Gündüz yoğun, gece sakin olan kurumsal uygulamalar
  • Birden fazla uygulama: Aynı sunucuda birkaç farklı web uygulaması çalışıyorsa
  • Orta ölçekli ortamlar: Ne hosting’deki kadar çok site ne de enterprise’daki kadar yüksek trafik
  • Karma servis ortamları: Aynı sunucuda PHP yanında MySQL, Redis gibi servisler de çalışıyorsa

Ondemand Mod İçin İdeal Senaryolar

  • Çok sayıda düşük trafikli site: 50 veya üzeri küçük site barındırma
  • Geliştirme ve staging ortamları: RAM’i verimli kullanmak önemli ama milisaniye yanıt süresi kritik değil
  • Mikro servis mimarileri: Her servis kendi pool’unu kullanıyorsa ve bazıları nadiren tetikleniyorsa
  • Gece batch işlemleri: Sadece belirli saatlerde çalışan arka plan işlemleri

PHP-FPM Log Analizi ile Kararınızı Destekleyin

PM türü seçmeden önce mutlaka mevcut sisteminizin loglarını analiz edin:

# PHP-FPM slow log'u aktifleştirin (www.conf içinde)
; request_slowlog_timeout = 5s
; slowlog = /var/log/php-fpm-slow.log

# Mevcut pool'un child process'leri ne sıklıkla oluşturulup yok ediliyor?
grep -c "child .* exited" /var/log/php8.2-fpm.log

# "max children reached" hatalarını sayın - bu değer yüksekse max_children artırın
grep -c "max_children" /var/log/php8.2-fpm.log

# Son 100 "max children" uyarısının zaman dağılımı
grep "max_children" /var/log/php8.2-fpm.log | tail -100 | awk '{print $1, $2}' | cut -d: -f1

Eğer loglarınızda “server reached pm.max_children setting” mesajı sıkça geçiyorsa, seçili PM türünden bağımsız olarak max_children değerini artırmanız gerekir. Bu mesaj, gelen isteklerin mevcut process kapasitesini aştığını ve bazı isteklerin kuyrukta beklediğini gösterir.

Yapılandırma Doğrulama ve Yeniden Başlatma

Konfigürasyon değişikliklerini test etmeden uygulamak production ortamında risklidir:

# Sözdizimi kontrolü
php-fpm8.2 -t

# Başarılı çıktı şöyle görünmeli:
# [02-Jan-2024 10:00:00] NOTICE: configuration file /etc/php/8.2/fpm/php-fpm.conf test is successful

# Graceful reload (mevcut istekler tamamlanır, yenileri yeni konfigürasyonla işlenir)
systemctl reload php8.2-fpm

# Tam yeniden başlatma (sadece zorunlu hallerde)
systemctl restart php8.2-fpm

# Reload sonrası durumu kontrol edin
systemctl status php8.2-fpm

reload komutu tercih edilmelidir çünkü mevcut bağlantıları kesmez. restart ise tüm process’leri anında öldürür ve aktif istekler yarıda kalabilir.

Gelişmiş Konfigürasyon: Emergency Durum Yönetimi

Production ortamında ani trafik artışlarına karşı hazırlıklı olmak için şu yaklaşımı kullanabilirsiniz:

; Acil durum için yedek konfigürasyon - www_emergency.conf
[www]
pm = dynamic
pm.max_children = 100
pm.start_servers = 20
pm.min_spare_servers = 15
pm.max_spare_servers = 30
pm.max_requests = 200

; Emergency timeout değerleri
request_terminate_timeout = 30s
request_slowlog_timeout = 10s

Ve bunu hızlıca devreye almak için:

#!/bin/bash
# php-fpm-emergency.sh
# Yoğun trafik anında geçici olarak daha agresif PM ayarlarına geçer

POOL_CONF="/etc/php/8.2/fpm/pool.d/www.conf"
BACKUP_CONF="/etc/php/8.2/fpm/pool.d/www.conf.backup"
EMERGENCY_CONF="/etc/php/8.2/fpm/emergency/www.conf"

echo "Mevcut konfigürasyon yedekleniyor..."
cp "$POOL_CONF" "$BACKUP_CONF"

echo "Emergency konfigürasyon devreye alınıyor..."
cp "$EMERGENCY_CONF" "$POOL_CONF"

php-fpm8.2 -t && systemctl reload php8.2-fpm

echo "PHP-FPM emergency modda. Normale döndürmek için: ./php-fpm-restore.sh"

Sık Yapılan Hatalar

Yıllar içinde gördüğüm yaygın hataları şöyle özetleyebilirim:

max_children değerini çok yüksek ayarlamak: RAM hesabı yapmadan “ne kadar çok olsa o kadar iyi” diye düşünmek, sistemi bellek baskısına sokar ve tüm servisleri olumsuz etkiler.

Tüm uygulamalara aynı PM türünü uygulamak: E-ticaret siteniz ve şirket blogunuz aynı sunucudaysa, e-ticaret sitesi static veya dynamic, blog ise ondemand kullanabilir.

pm.max_requests değerini atlamak: Özellikle bellek sızıntısı olan PHP uygulamalarında bu değeri ayarlamamak, uzun süre çalışan process’lerin giderek daha fazla bellek tüketmesine yol açar.

Reload yerine restart kullanmak: Konfigürasyon değişikliklerinde restart alışkanlığı, özellikle yoğun saatlerde aktif kullanıcıların oturumlarının kesilmesine neden olabilir.

Ondemand modunu yüksek trafikli sitelerde kullanmak: Ondemand modunun getirdiği cold start gecikmesi, saniyede 100 üzeri istek alan sitelerde fark edilir hale gelir ve kullanıcı deneyimini bozar.

Sonuç

PHP-FPM process manager seçimi, tek seferlik bir karar değil, uygulamanızın büyümesiyle birlikte yeniden değerlendirmeniz gereken bir konfigürasyondur.

Başlangıç noktası olarak şunu önerebilirim: Yeni bir sunucu kuruyorsanız ve trafik profilinizi henüz bilmiyorsanız, dynamic modla başlayın. Makul varsayılan değerler atayın, durum sayfasını aktifleştirin ve gerçek trafik verisi toplayın. Birkaç hafta sonra logları analiz edin.

Eğer aktif process sayısı sürekli max_children sınırına yaklaşıyorsa, ya bu değeri artırın ya da static moda geçmeyi düşünün. Eğer boşta bekleyen process sayısı aktif process sayısının üç-dört katıysa, bellekten tasarruf etmek için ondemand veya daha agresif dynamic değerler kullanın.

Her PM türünün anlamlı olduğu bir senaryo vardır. Doğru soruyu sormak gerekirse şudur: Uygulamam ne kadar trafiğe maruz kalıyor ve bu trafik ne kadar öngörülebilir? Bu sorunun cevabı, process manager seçiminizi büyük ölçüde belirleyecektir.

Son olarak, monitoring olmadan yapılan herhangi bir optimizasyon kör uçuştur. PHP-FPM durum sayfasını Prometheus, Grafana veya en basitinden bir shell script ile düzenli aralıklarla izleyin. Sorunlar yaşanmadan önce ortaya çıkan sinyalleri yakalamak, gece yarısı acil müdahalelerinden çok daha değerlidir.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir