PHP-FPM Optimizasyonu: pm.max_children Nasıl Hesaplanır?

pm.max_children, PHP-FPM'in aynı anda çalıştırabileceği en fazla PHP süreci sayısıdır. Yaklaşık değer, PHP için ayrılabilecek RAM'in ortalama süreç belleğine bölünmesiyle bulunur. Örneğin 4 GB'lık bir sunucuda işletim sistemi, veritabanı ve önbelleğe 1,5 GB bırakılırsa ve süreç başına 60 MB ölçülürse değer yaklaşık 40 olur. Fazlası swap'a, azı kuyruğa ve 502/504 hatalarına yol açar.

Bu yazıda süreç belleğini ölçen tek satırlık komut, hesap formülü, paketlere göre örnek hesap tablosu ve değişikliğin doğru olup olmadığını gösteren durum sayfası yer alıyor. PHP havuzunu veritabanı ve önbellek ayarlarıyla birlikte ele almak isterseniz PHP ve sunucu optimizasyonu için teklif alabilirsiniz.

PHP-FPM nedir?

PHP-FPM (FastCGI Process Manager), PHP kodunu web sunucusundan ayrı, önceden başlatılmış bir süreç havuzunda çalıştıran süreç yöneticisidir. Nginx veya Apache, PHP isteğini FastCGI protokolüyle bu havuza iletir; havuzdaki boş bir süreç isteği işler ve yanıtı geri döndürür.

Her alt süreç aynı anda yalnızca bir istek işler. Bu yüzden pm.max_children, PHP belgelerinin ifadesiyle aynı anda sunulabilecek istek sayısının sınırıdır. Tüm süreçler meşgulse yeni istek, bir süreç boşalana kadar dinleme kuyruğunda bekler. Bir sunucuda birden fazla havuz (pool) olabilir; her havuzun kendi ayarları ve kendi kullanıcısı vardır.

Süreç yöneticisi modları: static, dynamic, ondemand

pm ayarı, süreç sayısının nasıl yönetileceğini belirler. Varsayılan havuz dosyalarında genellikle dynamic kullanılır.

ModNasıl çalışır?ArtısıEksisiUygun senaryo
staticHer zaman pm.max_children kadar süreç açık tutulurSüreç başlatma gecikmesi yok, davranış öngörülebilirTrafik yokken de bellek tutarPHP'ye ayrılmış, trafiği yoğun ve düzenli sunucu
dynamicBaşlangıçta pm.start_servers kadar süreç açılır; boş süreç sayısı min ve max spare arasında tutulurBellek ve hız arasında dengeYanlış spare değerleri sürekli süreç açıp kapatmaya yol açarÇoğu web sitesi
ondemandSüreç yalnızca istek gelince açılır, pm.process_idle_timeout (varsayılan 10 sn) boşta kalınca kapanırBoştayken bellek harcamazTrafik dalgasında ilk isteklere süreç başlatma gecikmesi eklenirAz trafikli çok sayıda site, test ortamları

Üç modda da üst sınır pm.max_children'dır; aşağıdaki hesap hepsi için geçerlidir.

pm.max_children nasıl hesaplanır?

Kısa cevap: PHP'ye ayırabileceğiniz RAM'i, yoğun saatte ölçtüğünüz ortalama süreç belleğine bölün ve güvenlik payı bırakın.

Süreç başına bellek ölçümü

Ölçüm, sitenin gerçek trafiği aldığı bir saatte ve PHP-FPM bir süre çalıştıktan sonra yapılmalıdır; yeni başlatılmış süreçler henüz az bellek kullanır. Aşağıdaki tek satır, tüm havuzlardaki PHP-FPM alt süreçlerinin sayısını ve ortalama RSS değerini verir. RSS (Resident Set Size), sürecin fiziksel RAM'de kapladığı alandır; ps bu değeri KB cinsinden verir.

ps -o rss= -p "$(pgrep -d, -f 'php-fpm: pool')" | awk '{s+=$1; n++} END {printf "Süreç: %d, ortalama RSS: %.0f MB\n", n, s/n/1024}'

Komut Ubuntu/Debian ve AlmaLinux/Rocky'de aynı şekilde çalışır, çünkü alt süreçlerin komut satırı her iki ailede de php-fpm: pool havuz-adı biçimindedir; ana süreç (master) bu yüzden hesaba katılmaz. Tek bir havuzu ölçmek için desenin sonuna havuz adını ekleyin, örneğin 'php-fpm: pool www'. En büyük süreci görmek de yararlıdır:

ps -o rss= -p "$(pgrep -d, -f 'php-fpm: pool')" | sort -n | tail -n 1

RSS, OPcache gibi süreçler arasında paylaşılan belleğin bir kısmını her süreçte ayrı sayar. Bu nedenle toplam gerçek kullanımdan biraz yüksek çıkar; hesapta bu fark güvenlik payı işlevi görür.

Formül

pm.max_children ≈ (Toplam RAM − diğer bileşenlere bırakılan bellek) ÷ ortalama süreç RSS

"Diğer bileşenler" şunlardır: işletim sistemi ve web sunucusu, aynı sunucudaysa veritabanı (buffer pool artı bağlantı başına bellek), Redis gibi önbellek servisleri ve dosya sistemi önbelleği için bir miktar boşluk. Birden fazla havuz varsa hesapladığınız toplam değeri havuzlar arasında paylaştırın; havuzların pm.max_children toplamı bu sınırı aşmamalıdır.

Örnek: 4 GB, 8 GB ve 16 GB sunucu

Aşağıdaki tablo genel başlangıç değerleridir; kendi ölçümünüzle ayarlayın. RAM değerleri Bulutzone TR Cloud VDS paketlerinden alınmıştır; süreç bellekleri örnek değerdir ve sizin uygulamanızda farklı olacaktır. Sonuçlar 5'in katına aşağı yuvarlanmıştır.

Sunucu ve rolDiğer bileşenlere bırakılanPHP'ye ayrılanOrtalama RSSHesapBaşlangıç değeri
4 GB (TR Cloud v2), web + veritabanı aynı sunucuda1,5 GB2.560 MB60 MB2.560 ÷ 60 ≈ 4240
4 GB (TR Cloud v2), web + veritabanı, ağır eklentili site1,5 GB2.560 MB90 MB2.560 ÷ 90 ≈ 2825
8 GB (TR Cloud v4), web + veritabanı aynı sunucuda4 GB4.096 MB60 MB4.096 ÷ 60 ≈ 6865
8 GB (TR Cloud v4), veritabanı ayrı sunucuda1,5 GB6.656 MB90 MB6.656 ÷ 90 ≈ 7470
16 GB (TR Cloud v5), web + veritabanı aynı sunucuda9 GB7.168 MB60 MB7.168 ÷ 60 ≈ 119115

Bu sayılar bellek açısından üst sınırdır. PHP istekleriniz ağırlıklı olarak CPU harcıyorsa, çekirdek sayısının çok üzerindeki eş zamanlı süreç yalnızca CPU için sıra bekler. Yoğun anda load average sürekli çekirdek sayısını aşıyorsa değeri düşürün; yorum için load average rehberine bakabilirsiniz. Sunucunun toplam belleğini planlamak için VDS RAM seçimi yazısı süreç başına bellek hesabını paket seçimine bağlar.

Diğer önemli ayarlar

pm.max_children tavanı belirler; aşağıdaki ayarlar sürecin ömrünü ve boşta kaç süreç bekleyeceğini yönetir. Havuz dosyası Ubuntu/Debian'da /etc/php/8.3/fpm/pool.d/www.conf, AlmaLinux/Rocky'de /etc/php-fpm.d/www.conf yolundadır (PHP sürümünü kendi sisteminize göre değiştirin).

pm = dynamic
pm.max_children = 40
pm.start_servers = 8
pm.min_spare_servers = 4
pm.max_spare_servers = 12
pm.max_requests = 500
request_terminate_timeout = 60s
request_slowlog_timeout = 5s
slowlog = /var/log/php-fpm-www-slow.log
pm.status_path = /fpm-status

pm.start_servers, pm.min_spare_servers, pm.max_spare_servers

Yalnızca dynamic modda kullanılır. pm.start_servers açılışta başlatılan süreç sayısıdır; belirtilmezse varsayılanı (min_spare + max_spare) ÷ 2'dir. Spare değerleri boşta bekleyen süreç sayısını sınırlar. Trafik dalgalıysa aradaki farkı biraz geniş tutmak, sürekli süreç açılıp kapanmasını önler.

pm.max_requests

Bir alt sürecin kaç istekten sonra yeniden başlatılacağını belirler; varsayılan 0'dır, yani süreç hiç yenilenmez. Eklenti veya kütüphanelerdeki bellek sızıntıları zamanla süreçleri büyütüyorsa 500–1000 arası bir değer süreçleri düzenli olarak yeniler. Ölçtüğünüz ortalama RSS gün içinde sürekli artıyorsa bu ayar etkilidir.

request_terminate_timeout

Tek bir isteğin en fazla ne kadar süreceğini belirler; süre aşılırsa süreç sonlandırılır. Varsayılan 0'dır (kapalı). PHP'nin max_execution_time sınırı, beklenen bazı durumlarda betiği durdurmayabileceği için bu ayar ikinci bir güvenlik katmanıdır. Değeri, Nginx'teki fastcgi_read_timeout (varsayılan 60 saniye) ile uyumlu seçin; aksi halde kullanıcı 504 alırken PHP işi arka planda sürdürür. request_slowlog_timeout ise belirtilen süreyi aşan isteklerin yığın izini (backtrace) slowlog dosyasına yazar ve süreçleri hangi kodun meşgul ettiğini gösterir.

Belirtiler: max_children uyarısı, 502 ve 504 hataları

Yanlış bir pm.max_children değeri günlüklerde ve kullanıcı tarafında belirli izler bırakır. PHP-FPM günlüğü Ubuntu/Debian'da /var/log/php8.3-fpm.log, AlmaLinux/Rocky'de /var/log/php-fpm/error.log dosyasıdır; Nginx hataları /var/log/nginx/error.log dosyasına yazılır.

BelirtiGünlükte görülenOlası nedenNe yapılmalı?
Yavaşlama, zaman zaman hataserver reached pm.max_children setting (PHP-FPM)Tüm süreçler dolu, istekler kuyruktaRAM elveriyorsa değeri artırın; süreçler yavaş sorgu bekliyorsa önce onu çözün
502 Bad Gatewayconnect() to unix:/run/php/... failed (11: Resource temporarily unavailable)Dinleme kuyruğu (listen.backlog) dolduSüreç sayısı ve yavaş istekler
502 Bad Gatewayconnect() ... failed (2: No such file or directory) veya (111: Connection refused)PHP-FPM çalışmıyor ya da soket yolu yanlışsystemctl status ile servisi ve soket yolunu kontrol edin
502 Bad Gatewayupstream prematurely closed connectionSüreç istek sırasında sonlandı (request_terminate_timeout, çökme veya OOM killer)slowlog ve dmesg -T çıktısını inceleyin
504 Gateway Timeoutupstream timed out ... while reading response headerPHP yanıtı fastcgi_read_timeout içinde gelmediYavaş isteği slowlog ile bulun; süreyi uzatmak son çare
Genel yavaşlık, yüksek iowaitvmstat'ta si/so sürekli sıfırdan büyükpm.max_children RAM'e göre fazla, swap başladıDeğeri düşürün veya RAM artırın

Tüm süreçlerin dolu olması her zaman süreç sayısının az olduğu anlamına gelmez. Süreçler yavaş bir veritabanı sorgusunu bekliyorsa sayıyı artırmak yalnızca daha çok sürecin beklemesine yol açar. Darboğazın yerini bulmak için darboğaz tespiti akışını izleyebilirsiniz.

Sık sorulan sorular

pm.max_children ne olmalı?

Tek doğru sayı yoktur; sunucunun RAM'ine, aynı makinede çalışan diğer servislere ve uygulamanızın süreç başına belleğine bağlıdır. Formülü ölçtüğünüz RSS ile uygulayın, çıkan sayıyı güvenlik payıyla aşağı yuvarlayın ve yoğun saatte swap ile max_children uyarısını izleyin.

static mi, dynamic mi?

Sunucu yalnızca bir uygulamaya hizmet veriyor ve trafik gün boyu yoğunsa static, süreç başlatma gecikmesini ortadan kaldırır. Trafiği dalgalı sitelerde dynamic, çok sayıda az trafikli sitenin bulunduğu sunucularda ondemand daha verimlidir. Her üç modda da bellek hesabı pm.max_children üzerinden yapılır.

pm.max_requests ne işe yarar?

Süreçleri belirli sayıda istekten sonra yeniden başlatarak bellek sızıntılarının birikmesini önler. Varsayılan 0 süreçlerin hiç yenilenmemesi demektir; süreç belleği gün içinde büyüyorsa 500–1000 arası bir değer denenebilir.

Birden fazla site varsa hesap nasıl yapılır?

Her sitenin ayrı havuzu varsa tüm havuzların pm.max_children toplamı, PHP'ye ayırdığınız belleğin ortalama süreç belleğine bölümünü aşmamalıdır. Trafiği az olan havuzlarda ondemand kullanmak, boştaki süreçlerin bellek tutmasını önler.

Değişikliği doğrulama: status sayfası ve loglar

Değişikliğin doğru olup olmadığını PHP-FPM'in durum sayfası ve günlükler gösterir. pm.status_path ayarını açtıktan sonra sayfayı, yalnızca sunucunun kendisinden erişilebilecek şekilde Nginx'in varsayılan (default_server) server bloğuna ekleyin. Soket yolunu kendi sisteminize göre değiştirin; AlmaLinux/Rocky'de genellikle /run/php-fpm/www.sock olur:

location = /fpm-status {
    allow 127.0.0.1;
    deny all;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
    fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}

Sözdizimini test edip servisleri yeniden yükleyin: sudo php-fpm8.3 -t (AlmaLinux/Rocky'de sudo php-fpm -t), ardından sudo nginx -t, PHP-FPM ve Nginx için systemctl reload. Sonra durum sayfasını okuyun:

curl -s http://127.0.0.1/fpm-status

Yoğun saatte izlenecek alanlar:

  • active processes / total processes: aktif süreç sayısı sürekli pm.max_children'a eşitse havuz doludur.
  • max children reached: havuzun sınıra kaç kez dayandığını sayar; değişiklikten sonra artmaya devam etmemelidir.
  • listen queue / max listen queue: boş süreç bekleyen istek sayısıdır; sürekli sıfırdan büyükse istekler kuyrukta bekliyordur.
  • slow requests: request_slowlog_timeout süresini aşan istek sayısıdır.

Döngü her zaman aynıdır: yoğun saatte ortalama RSS'i ve durum sayfasını kaydedin, tek bir değeri değiştirin, bir sonraki yoğun dönemde aynı değerleri ve vmstat'taki swap hareketini tekrar ölçün. PHP-FPM'in yeri ve diğer katmanlarla ilişkisi için Linux sunucu optimizasyonu rehberine bakabilirsiniz.

Ölçümü ve ayarı birlikte yapmak isterseniz, PHP havuzunu veritabanı ve önbellek ayarlarıyla birlikte ele alan tek seferlik sunucu optimizasyonu hizmeti için teklif alabilirsiniz. Ayarların zaman içinde izlenmesini istiyorsanız servis kontrolü ve log analizi içeren sunucu yönetimi paketlerine göz atabilirsiniz.

Kaynaklar

Sunucu Optimizasyonu konusundaki hizmetlerimiz için sunucu optimizasyonu hizmeti sayfasına göz atabilirsiniz.

İncele

İlgili rehberler