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_childrendeğ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_serversgibi 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_childrendeğ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.
