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.
| Mod | Nasıl çalışır? | Artısı | Eksisi | Uygun senaryo |
|---|---|---|---|---|
| static | Her zaman pm.max_children kadar süreç açık tutulur | Süreç başlatma gecikmesi yok, davranış öngörülebilir | Trafik yokken de bellek tutar | PHP'ye ayrılmış, trafiği yoğun ve düzenli sunucu |
| dynamic | Başlangıçta pm.start_servers kadar süreç açılır; boş süreç sayısı min ve max spare arasında tutulur | Bellek ve hız arasında denge | Yanlış spare değerleri sürekli süreç açıp kapatmaya yol açar | Çoğu web sitesi |
| ondemand | Süreç yalnızca istek gelince açılır, pm.process_idle_timeout (varsayılan 10 sn) boşta kalınca kapanır | Boştayken bellek harcamaz | Trafik dalgasında ilk isteklere süreç başlatma gecikmesi eklenir | Az 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 rol | Diğer bileşenlere bırakılan | PHP'ye ayrılan | Ortalama RSS | Hesap | Başlangıç değeri |
|---|---|---|---|---|---|
| 4 GB (TR Cloud v2), web + veritabanı aynı sunucuda | 1,5 GB | 2.560 MB | 60 MB | 2.560 ÷ 60 ≈ 42 | 40 |
| 4 GB (TR Cloud v2), web + veritabanı, ağır eklentili site | 1,5 GB | 2.560 MB | 90 MB | 2.560 ÷ 90 ≈ 28 | 25 |
| 8 GB (TR Cloud v4), web + veritabanı aynı sunucuda | 4 GB | 4.096 MB | 60 MB | 4.096 ÷ 60 ≈ 68 | 65 |
| 8 GB (TR Cloud v4), veritabanı ayrı sunucuda | 1,5 GB | 6.656 MB | 90 MB | 6.656 ÷ 90 ≈ 74 | 70 |
| 16 GB (TR Cloud v5), web + veritabanı aynı sunucuda | 9 GB | 7.168 MB | 60 MB | 7.168 ÷ 60 ≈ 119 | 115 |
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.
| Belirti | Günlükte görülen | Olası neden | Ne yapılmalı? |
|---|---|---|---|
| Yavaşlama, zaman zaman hata | server reached pm.max_children setting (PHP-FPM) | Tüm süreçler dolu, istekler kuyrukta | RAM elveriyorsa değeri artırın; süreçler yavaş sorgu bekliyorsa önce onu çözün |
| 502 Bad Gateway | connect() to unix:/run/php/... failed (11: Resource temporarily unavailable) | Dinleme kuyruğu (listen.backlog) doldu | Süreç sayısı ve yavaş istekler |
| 502 Bad Gateway | connect() ... 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 Gateway | upstream prematurely closed connection | Süreç istek sırasında sonlandı (request_terminate_timeout, çökme veya OOM killer) | slowlog ve dmesg -T çıktısını inceleyin |
| 504 Gateway Timeout | upstream timed out ... while reading response header | PHP yanıtı fastcgi_read_timeout içinde gelmedi | Yavaş isteği slowlog ile bulun; süreyi uzatmak son çare |
| Genel yavaşlık, yüksek iowait | vmstat'ta si/so sürekli sıfırdan büyük | pm.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_timeoutsü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.