Site Hızı & Performans

    PHP-FPM Havuz (Pool) Ayarları ve Performans

    PHP-FPM havuzlarında pm modu, max_children hesabı ve gerçek yük altında doğru ayar seçimi.

    11 dk okuma Güncellendi: 25 Ağustos 2026

    Sunucunuzda 16 GB RAM var, işlemci boşta duruyor, ama site kalabalık saatte "502 Bad Gateway" veriyor ya da sayfalar üç saniye asılı kalıp sonra açılıyor. Kaynak yetmiyor gibi görünmüyor, buna rağmen sistem tıkanıyor. Bu tabloyu her gördüğümde ilk baktığım yer PHP-FPM havuz ayarlarıdır; çünkü PHP-FPM, elindeki iş parçacığı sayısını siz söylemeden artırmaz. Varsayılan ayarlarla gelen bir sunucu genellikle beş süreçle çalışır ve altıncı eşzamanlı istek sıraya girer. RAM'in yarısı boş dururken siteniz kuyrukta bekler.

    Bu rehberde PHP-FPM havuzlarının nasıl çalıştığını, pm modlarının farkını, pm.max_children değerini tahminle değil hesapla nasıl bulacağınızı, birden fazla site için neden ayrı havuz açmanız gerektiğini ve tıkanmayı nasıl ölçeceğinizi anlatacağım. Ayrıca 502/504 hatalarının hangi ayardan kaynaklandığını ayırt etmenizi sağlayacak bir teşhis sırası vereceğim. Sonunda elinizde, kendi sunucunuzun RAM'ine ve trafiğine göre doldurabileceğiniz somut bir yapılandırma olacak.

    PHP-FPM Havuzu Nedir, İstek Nasıl İşlenir#

    PHP-FPM (FastCGI Process Manager), PHP kodunu çalıştıran ayrı bir arka plan servisidir. Nginx ya da Apache bir .php isteği aldığında kodu kendisi çalıştırmaz; isteği bir soket üzerinden PHP-FPM'e devreder, PHP-FPM boştaki bir alt sürece (child process) verir, süreç kodu çalıştırır ve HTML'i geri döner. Buradaki kritik gerçek şudur: her alt süreç aynı anda yalnızca tek bir isteği işler. Yani eşzamanlı olarak kaç PHP isteğini işleyebileceğiniz, doğrudan çalışan alt süreç sayısına eşittir.

    Havuz (pool), bu alt süreçlerin oluşturduğu grubun adıdır. Bir havuzun kendi kullanıcısı, kendi soketi, kendi süreç limitleri ve kendi PHP ayarları olabilir. Yapılandırma dosyaları genellikle şuradadır:

    # Havuz dosyalarının bulunduğu dizin (sürüme göre yol değişir)
    ls -1 /etc/php/8.3/fpm/pool.d/
    # www.conf
    
    # Servis durumu ve çalışan süreçleri gör
    systemctl status php8.3-fpm
    ps aux | grep '[p]hp-fpm' | wc -l
    

    Bir havuzun tepesinde köşeli parantez içinde adı yazar ve o dosyadaki her ayar yalnızca o havuza aittir:

    ; /etc/php/8.3/fpm/pool.d/www.conf
    [www]
    user = www-data
    group = www-data
    listen = /run/php/php8.3-fpm.sock
    listen.owner = www-data
    listen.group = www-data
    listen.mode = 0660
    

    Unix soketi ile TCP (127.0.0.1:9000) arasındaki fark tek makinede çalışırken çoğunlukla ölçülemeyecek kadar küçüktür; soket biraz daha hızlıdır ve dosya izinleriyle korunur, bu yüzden aynı sunucudaki kurulumlarda soket tercih edilir. PHP-FPM'in üstündeki katmanların isteği nasıl karşıladığını anlamak için sunucu tarafı önbellekleme katmanları yazısındaki akış şeması iyi bir tamamlayıcıdır: en iyi PHP isteği, önbellek sayesinde PHP-FPM'e hiç ulaşmayan istektir.

    pm Modları: static, dynamic, ondemand#

    pm yönergesi, PHP-FPM'in alt süreçleri nasıl yöneteceğini belirler ve üç değer alır. Seçim, sunucunun tek bir yoğun siteye mi yoksa çok sayıda sessiz siteye mi hizmet ettiğine göre değişir.

    ModDavranışUygun olduğu senaryo
    staticSabit sayıda süreci baştan açar, hiç kapatmazTek yoğun site, RAM bol, öngörülebilir yük
    dynamicAlt/üst sınır arasında süreç sayısını yükün durumuna göre değiştirirÇoğu genel amaçlı sunucu için varsayılan tercih
    ondemandSüreçleri yalnızca istek geldiğinde açar, boşta kalanı kapatırÇok sayıda düşük trafikli site, RAM kısıtlı

    static modun avantajı süreç açma maliyetinin sıfır olmasıdır: yük gelince beklemeden karşılanır. Dezavantajı, siteniz boşken bile RAM'in tamamının rezerve edilmesidir. ondemand bunun tam tersidir: boşta neredeyse hiç bellek kullanmaz ama trafiğin ilk dalgasında süreç açma gecikmesi ilk isteklere yansır. dynamic ikisinin ortasıdır ve varsayılan olarak gelmesinin sebebi budur.

    dynamic modda dört ayar birlikte anlam kazanır:

    pm = dynamic
    pm.max_children = 40      ; aynı anda çalışabilecek MUTLAK üst sınır
    pm.start_servers = 10     ; servis başlarken açılacak süreç sayısı
    pm.min_spare_servers = 6  ; boşta en az bu kadar süreç dursun
    pm.max_spare_servers = 16 ; boşta en fazla bu kadar süreç dursun
    pm.max_requests = 500     ; bir süreç bu kadar istek işleyince yeniden doğsun
    

    pm.start_servers değerinin min_spare ile max_spare arasında kalması gerekir; dışarıda kalırsa PHP-FPM başlarken uyarı verir ya da değeri kendisi düzeltir. pm.max_requests ise sızıntı sigortasıdır: uzun süre yaşayan bir PHP sürecinin belleği bir eklenti ya da eski bir uzantı yüzünden yavaşça şişebilir; süreci belirli sayıda istekten sonra yeniden doğurmak bu birikimi temizler. 500 ile 1000 arası çoğu kurulum için makul bir aralıktır.

    pm.max_children Değerini Hesaplayarak Bulmak#

    Bu, tüm yapılandırmanın en kritik satırıdır ve tahminle konulmamalıdır. Mantık basit: PHP'ye ayırabileceğiniz RAM'i, tek bir PHP sürecinin gerçek ortalama bellek kullanımına bölün.

    Önce tek bir sürecin ne kadar bellek kullandığını ölçün. Yük altındayken şu komut, PHP-FPM süreçlerinin ortalama yerleşik bellek boyutunu MB cinsinden verir:

    # PHP-FPM süreçlerinin ortalama RSS değeri (MB)
    ps -ylC php-fpm8.3 --sort:rss | awk '{sum+=$8; n++} END {printf "Ortalama: %.1f MB (%d sürec)\n", sum/n/1024, n}'
    # Ortalama: 68.4 MB (12 sürec)
    
    # En çok bellek kullanan 5 süreç
    ps -eo rss,comm --sort=-rss | grep php-fpm | head -5
    

    Sonra hesabı yapın. Diyelim ki sunucunuzda 8 GB RAM var. İşletim sistemi, MySQL ve web sunucusu için pay ayırdıktan sonra PHP'ye ayırabileceğiniz bellek 4 GB olsun ve tek süreç ortalama 68 MB kullanıyor olsun:

    Kullanılabilir PHP belleği : 4096 MB
    Süreç başına ortalama RSS  :   68 MB
    pm.max_children            : 4096 / 68 ≈ 60
    

    Sonra bu sayıya biraz güvenlik payı bırakıp yuvarlayın; 60 yerine 50 yazmak, ani bir bellek sıçramasında sunucunun takas alanına düşmesini önler. Yaygın sunucu boyutları için başlangıç noktaları şöyle görünür:

    Toplam RAMPHP'ye ayrılanOrtalama süreçmax_children (başlangıç)
    2 GB~1 GB60 MB15
    4 GB~2 GB60 MB30
    8 GB~4 GB68 MB50
    16 GB~9 GB80 MB100

    Bu tabloyu kopyalayıp geçmeyin; ortalama süreç boyutunu kendi sunucunuzda ölçün, çünkü ağır bir e-ticaret uygulaması 200 MB, sade bir kurumsal site 40 MB kullanabilir. memory_limit değeri de bu hesabı doğrudan etkiler: memory_limit = 512M yazıp max_children = 100 verirseniz teorik en kötü durumda 50 GB bellek talep etmiş olursunuz. Kural şudur: max_children × memory_limit değeri fiziksel RAM'i aşıyorsa, en kötü durumda sunucu takasa düşer ve tamamen kilitlenir.

    Çok Siteli Sunucuda Ayrı Havuzlar#

    Aynı sunucuda birden fazla site barındırıyorsanız hepsini tek www havuzuna doldurmak, sitelerden birinin diğerlerini boğmasına açık kapı bırakır. Ağır bir raporlama sayfası tüm süreçleri işgal ettiğinde, aynı havuzu paylaşan diğer siteler de 502 vermeye başlar. Doğru yaklaşım, her site için ayrı bir havuz dosyası açmaktır:

    ; /etc/php/8.3/fpm/pool.d/magaza.conf
    [magaza]
    user = magaza
    group = magaza
    listen = /run/php/magaza.sock
    listen.owner = www-data
    listen.group = www-data
    
    pm = dynamic
    pm.max_children = 25
    pm.start_servers = 6
    pm.min_spare_servers = 4
    pm.max_spare_servers = 10
    pm.max_requests = 500
    
    ; Havuza özel PHP ayarları
    php_admin_value[memory_limit] = 256M
    php_admin_value[upload_max_filesize] = 64M
    php_admin_value[open_basedir] = /var/www/magaza:/tmp
    php_admin_flag[log_errors] = on
    php_admin_value[error_log] = /var/log/php-fpm/magaza-error.log
    

    Bunun üç faydası birden vardır. Birincisi izolasyon: her sitenin süreç sayısı ayrı sınırlıdır, biri diğerini aç bırakamaz. İkincisi güvenlik: her havuz farklı bir sistem kullanıcısıyla çalışır, open_basedir ile kendi dizinine kapatılır; bir sitedeki açık diğerine sıçramaz. Üçüncüsü teşhis kolaylığı: hata günlükleri ve yavaş istek kayıtları site bazında ayrışır. Nginx tarafında her siteyi kendi soketine bağlarsınız:

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/magaza.sock;
        fastcgi_read_timeout 60s;
    }
    

    Havuzların toplamının fiziksel RAM'i aşmamasına dikkat edin: sunucuda üç havuz varsa ve her birine 50 yazarsanız, en kötü durumda 150 süreç birden ayağa kalkabilir. Toplamı hesaplayıp bellek hesabını havuz bazında değil sunucu bazında yapın.

    Tıkanmayı Ölçmek: Durum Sayfası ve Yavaş İstek Günlüğü#

    PHP-FPM kendi durumunu raporlayabilir ve bu, ayarların doğru olup olmadığını anlamanın en dürüst yoludur. Önce havuzda durum uç noktasını açın:

    pm.status_path = /fpm-status
    ping.path = /fpm-ping
    
    ; Yavaş istekleri yığın izi ile kaydet
    slowlog = /var/log/php-fpm/magaza-slow.log
    request_slowlog_timeout = 5s
    

    Nginx tarafında bu yolu yalnızca localhost'a açın; dışarıya açık bırakmak sunucunuzun iç durumunu ifşa eder:

    location = /fpm-status {
        allow 127.0.0.1;
        deny all;
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/magaza.sock;
    }
    

    Ardından sunucudan sorgulayın:

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

    Çıktıdaki üç satır her şeyi söyler:

    active processes:      24
    max active processes:  40
    max children reached:  7
    listen queue:          12
    

    max children reached sıfırdan büyükse, PHP-FPM en az bir kez tavana çarpmış ve istekleri kuyruğa almış demektir. listen queue sıfırdan farklıysa şu anda bekleyen istek vardır. Bu iki sayının ikisi de sürekli sıfırda kalmalıdır; kalmıyorsa ya max_children düşüktür ya da PHP kodunuz gereğinden uzun sürüyordur. Ayrımı slowlog yapar: yavaş istek günlüğü, beş saniyeyi aşan her isteğin PHP yığın izini yazar, böylece hangi fonksiyonda takıldığını doğrudan görürsünüz. Genellikle karşınıza uzun süren bir veritabanı sorgusu çıkar; o zaman çözüm süreç sayısını artırmak değil sorguyu düzeltmektir. Bu ayrımı veritabanı sorguları sayfa hızını nasıl etkiler yazısında ayrıntılı işledim.

    502, 504 ve Kuyruk Hatalarının Teşhisi#

    Bu üç hata farklı sebeplerden gelir ve karıştırıldıklarında yanlış ayar değiştirilir. Ayrım şudur:

    HataAnlamıBakılacak ayar
    502 Bad GatewayWeb sunucusu PHP-FPM'e ulaşamadı ya da bağlantı koptuSoket yolu/izinleri, servis çalışıyor mu, max_children
    504 Gateway TimeoutPHP yanıtı zamanında dönmedifastcgi_read_timeout, max_execution_time, yavaş sorgu
    503 / kuyrukta beklemeTüm süreçler dolu, kuyruk taştıpm.max_children, listen.backlog

    502 aldığınızda ilk bakılacak yer PHP-FPM'in kendi hata günlüğüdür:

    # PHP-FPM servis günlüğü
    journalctl -u php8.3-fpm -n 50 --no-pager
    
    # Klasik uyarı satırı
    grep 'max_children' /var/log/php8.3-fpm.log
    # WARNING: [pool www] server reached pm.max_children setting (40),
    # consider raising it
    

    Bu uyarıyı görüyorsanız gerçekten max_children yetmiyordur — ama yukarıdaki bellek hesabını yapmadan artırmayın, yoksa 502 yerine takasa düşmüş kilitlenen bir sunucu elde edersiniz. Soket izinleri de sık bir 502 sebebidir: Nginx www-data olarak çalışırken havuzun soketi başka bir kullanıcıya ait ve listen.mode dar bırakılmışsa bağlantı kurulamaz; listen.owner, listen.group ve listen.mode üçlüsünü kontrol edin.

    Zaman aşımı tarafında iki ayar birbiriyle uyumlu olmalıdır: Nginx'in fastcgi_read_timeout değeri PHP'nin max_execution_time değerinden küçükse PHP hâlâ çalışırken Nginx bağlantıyı keser ve kullanıcı 504 görür, işlem ise arka planda yarım kalır. Uzun süren işleri (rapor üretimi, dışa aktarma) web isteğinde değil kuyrukta çalıştırmak doğru çözümdür; zaman aşımını büyütmek yalnızca sorunu erteler.

    Yapılandırmayı Güvenli Biçimde Uygulamak#

    Ayarları değiştirmeden önce mevcut dosyanın yedeğini alın, sonra söz dizimini doğrulayın ve servisi kesintisiz yeniden yükleyin:

    # 1) Yedek
    cp /etc/php/8.3/fpm/pool.d/www.conf /root/www.conf.$(date +%F)
    
    # 2) Söz dizimi testi (havuzları da doğrular)
    php-fpm8.3 -t
    # [25-Aug-2026 10:14:02] NOTICE: configuration file /etc/php/8.3/fpm/php-fpm.conf test is successful
    
    # 3) Kesintisiz yeniden yükleme
    systemctl reload php8.3-fpm
    
    # 4) Süreç sayısını doğrula
    ps -C php-fpm8.3 --no-headers | wc -l
    

    reload ile restart arasındaki fark gerçek bir kesinti farkıdır: reload çalışan süreçlerin işini bitirmesini bekleyip yeni yapılandırmayla değiştirir, restart ise hepsini birden öldürür ve o an işlenen istekler 502 alır. Canlıda her zaman reload kullanın.

    Değişikliğin işe yarayıp yaramadığını, ayarları değiştirmeden önce ve sonra aynı yük altında ölçerek anlarsınız. Elle yenileyerek bunu yapamazsınız; gerçek bir yük üreteciyle eşzamanlı istek göndermeniz gerekir. k6 ile yük testi yazısındaki senaryolarla, max_children değerini artırmadan önce ve sonra p95 yanıt süresini kıyaslayabilirsiniz.

    Sıkça Sorulan Sorular#

    pm.max_children değerini kaç yapmalıyım#

    Tek doğru sayı yoktur; hesaplanır. PHP'ye ayırabileceğiniz RAM'i, kendi sunucunuzda ölçtüğünüz ortalama PHP-FPM süreç boyutuna bölün ve sonuçtan güvenlik payı düşün. Örneğin 4 GB'ı PHP'ye ayırdıysanız ve ortalama süreç 68 MB kullanıyorsa yaklaşık 60 çıkar, 50 yazmak makul olur. Ayarı değiştirdikten sonra /fpm-status çıktısındaki max children reached sayacını izleyin; sıfırda kalıyorsa değeriniz yeterlidir.

    static, dynamic ve ondemand arasında hangisini seçmeliyim#

    Tek ve yoğun bir site barındırıyor, RAM'iniz bolsa static en düşük gecikmeyi verir çünkü süreç açma maliyeti hiç ödenmez. Aynı sunucuda çok sayıda düşük trafikli site varsa ondemand belleği en verimli kullanır. Bu ikisinin ortasındaki genel amaçlı kurulumlar için dynamic doğru tercihtir ve varsayılan olmasının sebebi budur.

    502 Bad Gateway hatasını nasıl çözerim#

    Önce sebebi ayırın. PHP-FPM servisinin çalıştığını (systemctl status), soket yolunun ve izinlerinin Nginx yapılandırmasıyla eşleştiğini doğrulayın. Servis günlüğünde server reached pm.max_children setting uyarısı varsa süreç sayısı yetmiyordur ve bellek hesabını yaparak artırmanız gerekir. Uyarı yoksa büyük ihtimalle soket izni ya da yanlış yol söz konusudur.

    PHP-FPM ayarı değiştirdim, ne zaman etkili olur#

    Havuz dosyalarındaki değişiklikler servis yeniden yüklenmeden etkili olmaz. php-fpm8.3 -t ile söz dizimini doğrulayın, sonra systemctl reload php8.3-fpm çalıştırın. reload çalışan istekleri kesmeden yapılandırmayı uygular; restart ise o an işlenen istekleri düşürür, bu yüzden canlı sunucuda tercih edilmez.

    Her site için ayrı havuz açmak şart mı#

    Şart değil ama aynı sunucuda birden fazla bağımsız site varsa şiddetle tavsiye edilir. Ayrı havuz, bir sitenin tüm süreçleri işgal edip diğerlerini durdurmasını engeller; her siteyi kendi sistem kullanıcısıyla ve open_basedir ile kendi dizinine kapatarak güvenlik izolasyonu sağlar. Ek olarak hata ve yavaş istek günlükleri site bazında ayrışır, teşhis kolaylaşır.

    pm.max_requests neden var, kaç olmalı#

    Uzun süre yaşayan bir PHP süreci, bir eklenti ya da uzantı kaynaklı yavaş bellek birikimi yaşayabilir. pm.max_requests, süreci belirli sayıda istekten sonra kapatıp yeniden doğurarak bu birikimi temizler. 500-1000 aralığı çoğu kurulum için uygundur. Çok düşük değerler (örneğin 50) gereksiz süreç yeniden doğumuna ve ölçülebilir bir ek yüke sebep olur.

    Süreç sayısını artırmak her zaman hızlandırır mı#

    Hayır. Sürecin beklediği yer PHP değil de veritabanıysa, daha fazla süreç yalnızca veritabanına daha fazla eşzamanlı sorgu gönderir ve tıkanmayı oraya taşır. Bu yüzden max_children artırmadan önce slowlog çıktısına bakın: istekler gerçekten CPU'da mı yoksa bir sorgu ya da harici API çağrısında mı bekliyor? Beklemenin kaynağı I/O ise çözüm önbellek ve sorgu optimizasyonudur.

    Kapanış#

    PHP-FPM ayarları, sunucu kaynaklarınızla gerçek eşzamanlılık kapasiteniz arasındaki köprüdür ve varsayılan değerlerle bırakıldığında bu köprü genellikle olması gerekenden çok dardır. Aklınızda kalması gereken dört alışkanlık şudur: max_children değerini ölçülmüş süreç boyutuna bölerek hesaplamak, max_children × memory_limit çarpımının fiziksel RAM'i aşmadığını doğrulamak, her siteye kendi havuzunu ve kendi kullanıcısını vermek, ve değişiklikten sonra /fpm-status ile slowlog çıktısını izleyerek gerçekten tıkanmanın kalktığını görmek. Bu dördü yapıldığında 502 hatalarının büyük bölümü kendiliğinden kaybolur.

    Bu ayarlarla tek tek uğraşmak istemiyorsanız Clou.TR tarafında hazır ayarlanmış seçenekler var. Yoğun trafikli projeler için havuz ve bellek limitleri optimize edilmiş kurumsal hosting ve e-ticaret hosting paketlerimizi inceleyebilir, kendi PHP-FPM yapılandırmanızı baştan kurmak isterseniz tam root erişimli VDS ya da bulut sunucu çözümlerimizi tercih edebilirsiniz. Yapılandırmayı ve izlemeyi bize bırakmak isterseniz sunucu yönetimi hizmetimiz bu işi uçtan uca üstlenir.

    PHP-FPMPerformansLinux

    Uygulamaya geçmeye hazır mısınız?

    NVMe SSD, ücretsiz SSL ve %99.9 uptime garantisiyle Clou.TR hosting ve sunucu çözümleriyle projenizi hayata geçirin.