PHP-FPM ayarı: pm.max_children nasıl hesaplanır?

Semih4 dk okuma

PHP-FPM'de pm.max_children değerini tahminle değil ölçerek belirlemek. Süreç belleğini ölçme, hesap formülü, pm modları, status sayfası ve slowlog.

PHP-FPM’in ayar dosyasında bir satır var ki sitenin kaderini belirler ve çoğu sunucuda varsayılan değerinde bırakılmıştır: pm.max_children. Debian ve Ubuntu’da bu değer kutudan 5 olarak çıkar. Yani aynı anda en fazla 5 PHP isteği işlenir, altıncı ziyaretçi sıraya girer. Küçük bir blog için yeter. Kampanya günündeki bir e-ticaret sitesi için trafik sıkışmasıdır.

Tersi de sorun: değeri “ne kadar çok o kadar iyi” diyerek 200 yaparsan, trafik geldiğinde PHP süreçleri belleği bitirir ve Linux veritabanını öldürür. Doğru değer tahminle değil, ölçümle bulunur. Nasıl yapıldığını anlatayım.

Kısa cevap: pm.max_children ≈ PHP’ye ayırabileceğin bellek ÷ ortalama bir PHP-FPM sürecinin bellek kullanımı. Sonucu biraz aşağı yuvarla ve status sayfasıyla gözlemle.

Önce bir PHP isteğinin nasıl işlendiğini hatırlayalım

Nginx bir .php isteği aldığında onu PHP-FPM’e iletir. PHP-FPM’in elinde bir havuz dolusu işçi süreç (child) vardır; her işçi aynı anda tek bir istek işler. Bütün işçiler meşgulse yeni istek sırada bekler. pm.max_children, bu havuzun olabilecek en büyük boyutu.

Yani bu ayar aslında şu sorunun cevabı: aynı anda kaç PHP isteğini belleğim taşır?

1. Bir süreç ne kadar bellek kullanıyor?

Site normal trafikteyken şu komutla ortalamayı ölç (sürüm numarasını kendi PHP sürümünle değiştir):

ps --no-headers -o rss -C php-fpm8.3 | awk '{s+=$1; n++} END {printf "%.0f MB\n", s/n/1024}'

Bu değer sitenin ne yaptığına göre çok değişir. Sade bir PHP sitesinde 30-40 MB görürsün, eklentisi bol bir WordPress, WHMCS ya da büyük bir Laravel uygulamasında 80-150 MB’ı bulabilir. İnternetteki hazır tablolara değil, kendi ölçümüne güven.

Küçük bir not: rss değeri süreçlerin ortak kullandığı belleği (örneğin OPcache) her süreçte ayrı sayar. Yani ölçüm gerçek kullanımdan biraz fazla çıkar. Bu, hesabı güvenli tarafta tutan iyi bir hata.

2. PHP’ye ne kadar bellek kalıyor?

Sunucudaki toplam bellekten diğer her şeyi çıkar:

  • İşletim sistemi ve Nginx: 300-500 MB
  • MySQL veya MariaDB: innodb_buffer_pool_size değeri artı biraz pay
  • Redis, Elasticsearch, cron işleri gibi diğer servisler

3. Hesap

Örnek bir 4 GB sunucu düşünelim:

Kalem Bellek
Toplam 4096 MB
İşletim sistemi ve Nginx −500 MB
MySQL −1200 MB
PHP’ye kalan 2396 MB
Ortalama PHP süreci 60 MB
pm.max_children 2396 ÷ 60 ≈ 39

Buradan 35 gibi yuvarlak ve biraz aşağıda bir değer seçerim. Payı, arada bir çok bellek isteyen rapor sayfası ya da büyük bir dosya yüklemesi yer.

4. Hangi pm modu?

Ayar dosyası Debian ve Ubuntu’da /etc/php/8.3/fpm/pool.d/www.conf yolunda. Üç mod var:

  • dynamic: varsayılan. Belli sayıda işçi hazırda bekler, trafik artınca pm.max_children’a kadar çoğalır. Çoğu site için doğru seçim.
  • static: her zaman pm.max_children kadar işçi çalışır. Yalnızca bu siteye ayrılmış, trafiği yüksek sunucularda en hızlı yanıtı verir ama belleği sürekli tutar.
  • ondemand: istek gelmedikçe işçi açılmaz. Aynı sunucuda çok sayıda az ziyaret edilen site varsa belleği korur, ilk istekte biraz gecikme ekler.

Örnek dynamic ayarı:

pm = dynamic
pm.max_children = 35
pm.start_servers = 8
pm.min_spare_servers = 4
pm.max_spare_servers = 12
pm.max_requests = 500

pm.max_requests ayrıca önemli: her işçi 500 istekten sonra kapanıp yenisiyle değişir. Böylece bir eklentideki küçük bir bellek sızıntısı günler içinde büyüyüp sunucuyu yiyemez.

Değişiklikten sonra ayarı test et ve servisi yeniden yükle:

sudo php-fpm8.3 -t
sudo systemctl reload php8.3-fpm

5. Gözlemle: status sayfası

Hesap bir başlangıç noktası, gerçek cevap trafikte ortaya çıkar. PHP-FPM’in kendi durum sayfasını aç:

pm.status_path = /fpm-status

Nginx’te bu adresi yalnızca sunucunun kendisine aç, dışarıya değil:

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;
}

curl http://127.0.0.1/fpm-status çıktısında üç satıra bak:

  • max children reached: sıfırdan büyükse havuz en az bir kez doldu ve istekler bekledi.
  • listen queue: şu anda sırada bekleyen istek sayısı. Sürekli sıfırın üstündeyse işçi yetmiyor.
  • active processes: o anda çalışan işçi sayısı. Hiçbir zaman sınıra yaklaşmıyorsa değeri gereğinden yüksek tutuyorsun.

Havuz doluyor ama bellek de yetmiyorsa, pm.max_children’ı artırmak çözüm değil. O durumda ya süreçleri hafifletmen (OPcache açık mı, gereksiz eklenti var mı?) ya da sunucuyu büyütmen gerekir.

6. Yavaş istekleri yakala: slowlog

Bazen sorun işçi sayısı değil, işçileri uzun süre meşgul eden birkaç yavaş sayfadır. PHP-FPM, belli bir süreyi aşan isteklerin o anki çağrı yığınını kaydedebilir:

request_slowlog_timeout = 5s
slowlog = /var/log/php8.3-fpm-slow.log

Log dosyası, isteğin hangi fonksiyonda takılı kaldığını satır numarasıyla gösterir. Çoğu zaman karşına ya indekssiz bir sorgu ya da cevap vermeyen bir dış servis çağrısı çıkar. Dış servis çağrılarına mutlaka zaman aşımı ekle. Karşı taraf yanıt vermediğinde senin işçin 60 saniye boyunca rehin kalmasın.

Özet

  1. Ortalama süreç belleğini ps ile ölç.
  2. Diğer servislerin payını çıkar, kalan belleği süreç boyutuna böl.
  3. Sonucu biraz aşağı yuvarla, pm.max_requests ekle.
  4. Status sayfasında max children reached ve listen queue değerlerini izle.
  5. Yavaş istekleri slowlog ile yakala.

Sunucu yavaşladığında sorunun PHP-FPM’de olduğunu nasıl anlayacağını bakılacak 10 komut yazısında anlattım. PHP tarafını güvenli tutmak için de PHP güvenlik önlemleri yazısına göz atabilirsin.

Kitapçıkta devamı

  1. 4 dk okuma

    Sunucu yavaşladı: panik yapmadan önce bakılacak 10 Linux komutu

    Site yavaşladığında Linux sunucuda sorunun CPU, bellek, disk, ağ ya da uygulama kaynaklı olduğunu beş dakikada ayırt etmeyi sağlayan 10 komut.

  2. 5 dk okuma

    Yeni bir Linux sunucuda ilk 30 dakika: güvenlik kontrol listesi

    Yeni açılan bir Ubuntu veya Debian sunucuda ilk yarım saatte yapılacaklar. SSH anahtarı, güvenlik duvarı, fail2ban, otomatik güncelleme, swap ve yedek.

Şans

Aklında bir proje mi var? Kutuyu açalım: ne yapmak istediğini anlat, sana kapsamı ve yol haritasını içeren bir teklif hazırlayayım.

Teklif iste

ya da doğrudan yaz: e-posta adresi