VPS üzerinde iki, üç, beş PHP uygulaması çalıştırmak — küçük SaaS dünyasında çok normal.
Default kurulumda hepsi tek bir www.conf pool’unu paylaşıyor. Bu çoğu zaman çalışıyor —
çalışmayana kadar.
Tek pool’un sorunu
Tek pool şu anlama geliyor:
- Bir uygulama
pm.max_children = 50’yi tüketirse diğerleri response veremez. - Bir uygulamadaki memory leak diğerlerinin worker’larını da OOM’a sürükler.
- Bir uygulamayı yeniden başlatmak (örn. opcache reset) hepsinin worker’larını restart eder.
Pool ayrımı bu üç sorunu birden çözüyor.
Pool başına config
/etc/php/8.3/fpm/pool.d/billing.conf:
[billing]
user = billing
group = billing
listen = /run/php/billing.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = dynamic
pm.max_children = 20
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 8
pm.max_requests = 500
request_terminate_timeout = 30s
catch_workers_output = yes
decorate_workers_output = no
clear_env = no
php_admin_value[memory_limit] = 256M
php_admin_value[error_log] = /var/log/php-fpm/billing-error.log
/etc/php/8.3/fpm/pool.d/notify.conf:
[notify]
user = notify
group = notify
listen = /run/php/notify.sock
; ...
pm.max_children = 8 ; daha hafif uygulama
php_admin_value[memory_limit] = 128M
İki şey kazandık:
- Filesystem izolasyonu —
user = billingile billing uygulaması notify’ın dosyalarına yazamaz. - Resource izolasyonu — billing’in maxchildren’i tükenirse notify hâlâ çalışır.
Nginx tarafında
Her vhost kendi socket’ine bağlanıyor:
server {
server_name billing.example.com;
root /var/www/billing/public;
location ~ \.php$ {
fastcgi_pass unix:/run/php/billing.sock;
# standart fastcgi params
}
}
server {
server_name notify.example.com;
root /var/www/notify/public;
location ~ \.php$ {
fastcgi_pass unix:/run/php/notify.sock;
}
}
opcache shared mı, ayrı mı?
PHP-FPM master process’i opcache’i paylaşıyor — bu yüzden pool’lar arasında
opcache otomatik izole değildir. Ancak opcache.validate_root = 1 ve farklı root
path’leri kullanılırsa çakışma olmaz. Pratikte: aynı master, ayrı pool’lar yeterli.
İzleme
/status endpoint’ini pool’a açın:
pm.status_path = /status
Sonra Nginx tarafında bunu sadece localhost’a açın:
location ~ ^/status$ {
access_log off;
allow 127.0.0.1;
deny all;
fastcgi_pass unix:/run/php/billing.sock;
# ...
}
curl localhost/status ile aktif worker, kuyruk uzunluğu, slow request sayısı
gibi metrikleri alıp Prometheus exporter veya basit bir cron’la izleyebilirsiniz.
Ne zaman tek pool yeterli?
Aynı kod tabanının iki kopyasını çalıştırıyorsanız (örn. app.example.com ve
staging.example.com) ayrı pool gereksiz. Farklı domain’ler ama aynı süreç sınıfı.
Ayrım, uygulamaları operasyonel olarak bağımsız kılmak istediğinizde değerli.