PHP performansı
Hızlı PHP satın alınmaz, ayarlanır.
Ekibimiz yirmi beş yıldır PHP ile çalışıyor ve bir isteğin zamanını nerede kaybettiğini biliyor. O zamanı sunucunuzda buluyor ve katman katman geri kazanıyoruz.
Bir isteğin anatomisi
Bir sayfa, beklemelerden oluşan bir zincirdir: sunucuyu bulmak, bağlantıyı açmak, PHP için sıraya girmek, derlemek, çalıştırmak, veritabanına sormak, göndermek. Hangi halkaları kısalttığımızı görmek için durumlar arasında geçiş yapın.
-
DNS sorgusu Ziyaretçinin çözümleyicisi tarafından yanıtlanır. Her durumda aynı: bu kısım ziyaretçinin ağıdır. Her durumda aynı: bu kısım ziyaretçinin ağıdır.
-
Bağlantı ve TLS Eski bir TLS kurulumu, her dosya için yeni bir bağlantı. TLS 1.3 ve her dosya için yeniden kullanılan tek bir HTTP/2 bağlantısı. TLS 1.3 ve her dosya için yeniden kullanılan tek bir HTTP/2 bağlantısı.
-
Bir PHP worker'ı beklemek Tüm worker'lar meşgul, bu yüzden istek kuyrukta bekler. Belleğe göre boyutlandırılmış bir havuz: boş bir worker hazırdır. Hiçbir PHP worker'ı gerekmez.
-
Betikleri derlemek PHP her istekte her dosyayı okur ve derler. OPcache derlenmiş betikleri bellekten sunar. Derlenecek bir şey yok.
-
Dosyaları ve sınıfları bulmak Autoloader her sınıf için dizinleri arar. Classmap tabanlı bir autoloader ve dolu bir realpath önbelleği. Yüklenecek bir şey yok.
-
Kodunuzu çalıştırmak Uygulamanın kendi işi. Hemen hemen aynı: JIT tipik bir sitede bunu nadiren değiştirir. Bu ziyaret için kodunuz çalışmaz.
-
Veritabanı sorguları Eksik indeksler ve her sayfada aynı sorgu. İndeksler eklendi, tekrarlanan yanıtlar Redis'te tutuluyor. Hiçbir sorgu gönderilmez.
-
Sayfayı göndermek Sıkıştırılmadan gönderilir. Sunucudan çıkmadan önce sıkıştırılır. Hazır sayfa, doğrudan sayfa önbelleğinden.
Yukarıdaki çubuklar bir çizimdir. Bu rakam ise bir ölçümdür.
Geri kalan süre, Almanya'daki sunucularımızla aranızdaki mesafedir. Bu kısım nerede olduğunuza bağlıdır; kendi bağlantınızdan ölçün.
Bağlantınızdan ölçünBeklemenin çoğunu ortadan kaldıran ayarlar
Derleme, dosyaları bulma ve sınıfları yükleme, kodunuz tek bir satır çalıştırmadan önce gerçekleşir. Bu ayarlar bunların her istekte değil, bir kez yapılmasını sağlar.
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0
opcache.preload=/srv/app/preload.php
opcache.preload_user=www-data
opcache.jit=tracing
opcache.jit_buffer_size=64M
realpath_cache_size=4096K
realpath_cache_ttl=600
$ composer install --no-dev --classmap-authoritative
-
OPcache
PHP her dosyayı çalıştırmadan önce derler. OPcache derlenmiş sonucu paylaşılan bellekte tutar, böylece bir sonraki istek bu işi atlar. Belleğini ve dosya sayısını siteye göre boyutlandırır, hiçbir şeyin dışarı atılmadığını isabet oranından doğrularız.
Canlı ortamda PHP her dosyayı değişiklik için denetlemeyi bırakır; her dağıtım önbelleği kendisi temizler.
-
Ön yükleme
Bir framework için ön yükleme, çekirdek dosyalarını PHP başlarken bir kez yükler ve her istek için hazır tutar. Bu dosyalardaki bir değişiklik yeniden başlatma gerektirir; bu yüzden yeniden başlatma dağıtımın bir parçasıdır.
-
JIT
JIT sık çalışan PHP kodunu makine koduna çevirir. İşlemciyi meşgul eden işlere yardım eder - görüntü işleme, hesaplamalar, uzun döngüler. Tipik bir site zamanını veritabanını ve ağı bekleyerek geçirir; orada JIT pek bir şey değiştirmez. Onu her yerde değil, bir ölçümün fark gösterdiği yerde açarız.
-
Realpath önbelleği
Her include, bir dosyanın gerçekte nerede olduğunu diske sorar. Daha büyük bir realpath önbelleği bu yanıtları bellekte tutar; bu, istek başına yüzlerce dosya yükleyen framework'ler için önemlidir.
-
Composer autoloader
Yetkili bir classmap, dizinleri aramak yerine her sınıfı tek bir aramada bulur ve geliştirme paketleri sunucuya girmez.
Ayar düğmesi: PHP-FPM
PHP-FPM bir PHP worker havuzu tutar. Az olursa istekler sıraya girer; çok olursa sunucunun belleği tükenir ve herkes için yavaşlar. Havuz, sunucunun gerçekte sahip olduğuna göre ayarlanır.
pm = static
pm.max_children = 64
Sabit sayıda worker, her zaman çalışır
Tek bir yoğun siteye ayrılmış sunucu için. Süreç başlatmaya zaman harcanmaz ve kullandığı bellek önceden bilinir.
pm = dynamic
pm.max_children = 64
pm.start_servers = 8
pm.min_spare_servers = 4
pm.max_spare_servers = 12
Birkaç worker hazır, yük altında daha fazlası
Birkaç boşta worker'ı beklemede tutar ve trafik arttıkça sınıra kadar yenilerini ekler. Günlük yoğunlukları olan bir site için olağan tercih.
pm = ondemand
pm.max_children = 64
pm.process_idle_timeout = 10s
Worker yalnızca bir istek geldiğinde
Tek sunucudaki birçok küçük site için: bellek ziyaret edilen sitelere gider ve sakin bir dönemden sonraki ilk istek kısa bir başlatma bedeli öder.
pm.max_children değerini nasıl belirliyoruz
pm.max_children = PHP için bellek ÷ worker başına bellek
$ ps --no-headers -o rss -C php-fpm8.3 | awk '{s+=$1} END {print s/NR/1024 " MB"}'
Bir hesap örneği, öneri değil: gerçek rakamlar sunucunuzdan gelir ve yoğun an için pay bırakırız.
- pm.max_requests
- Bir worker'ı belirli sayıda istekten sonra yeniler; böylece yavaş bir bellek sızıntısı asla kesintiye dönüşmez.
- request_slowlog_timeout
- Daha uzun süren bir istek, yığın izini yavaş günlüğe yazar; bu günlük incelenecek fonksiyonu gösterir.
- request_terminate_timeout
- Kontrolden çıkan bir isteği, bir worker'ı kalıcı olarak tutmadan durdurur.
- pm.status_path
- Kuyruğu ve havuzun sınırına ne sıklıkla ulaştığını gösterir - bir site yoğun saatte yavaşladığında ilk baktığımız yer.
Web sunucusundan PHP'ye iki yol
İkisini de işletiyor ve sitenin ihtiyacına göre seçiyoruz. Her iki durumda da en hızlı istek, PHP'nin hiç yanıtlamak zorunda kalmadığı istektir.
LiteSpeed + LSAPI
- Ziyaretçi
- LiteSpeed
- LSCachesayfa önbelleği
- LSAPI
- lsphp
LiteSpeed, PHP ile kendi LSAPI protokolü üzerinden konuşur ve tam sayfaları LSCache'te tutar; WordPress ve diğer uygulamalar içerik değiştiği anda bu önbelleği temizleyebilir.
Nginx + PHP-FPM
- Ziyaretçi
- Nginx
- fastcgi_cachesayfa önbelleği
- FastCGI
- PHP-FPM
Nginx statik dosyaları kendisi sunar, PHP'yi yerel bir soket üzerinden bir PHP-FPM havuzuna iletir ve oturum açmamış ziyaretçiler için hazır sayfaları FastCGI önbelleğinde tutabilir.
-
Nesneler ve oturumlar için Redis
Bir sayfanın veritabanından tekrar tekrar istediği yanıtlar bellekte tutulur ve oturumlar diske dokunmaz olur.
-
Tam sayfa önbelleği
Oturum açmamış bir ziyaretçi, PHP'ye veya veritabanına hiç sorulmadan hazır bir sayfa alır. Sepetler, hesaplar ve ödeme sayfaları bunun dışında tutulur.
-
HTTP/2 ve sıkıştırma
Tek bir şifreli bağlantı sayfanın tüm dosyalarını taşır, metin gönderilmeden önce sıkıştırılır ve statik dosyalar sürümlü adlarla uzun önbellek sürelerine sahip olur.
-
Veritabanı süresi
Yavaş sorgu günlüğü ve EXPLAIN hangi sorgunun neden beklediğini gösterir; çoğu zaman bunun büyük kısmı tek bir indeks ya da tekrarlanan tek bir sorgudur.
Veritabanlarını nasıl ayarlıyoruz
Önce ölçer, sonra tek bir şeyi değiştiririz
Her değişiklik, öncesinde alınmış bir ölçüme karşı yapılır; böylece ne sağladığını size gösterebiliriz. Ölçümler şunlardır.
opcache_get_status()İsabet oranı, boş bellek ve betiklerin dışarı atılıp atılmadığı.pm.status_pathBekleme kuyruğu ve havuzun sınırına ne sıklıkla ulaştığı.slowlogFazla uzun süren her isteğin yığın izi.slow_query_log + EXPLAINHangi sorguların beklediği, kaç satır okudukları ve hangi indeksin eksik olduğu.redis-cli INFO statsÖnbellek isabetlerine karşı ıskalar ve anahtarların dışarı atılıp atılmadığı.curl -w %{time_starttransfer}İlk bayta kadar geçen süre, öncesinde ve sonrasında aynı yöntemle ölçülür.
Rakamın diğer yarısını, yani sunucularımızla aranızdaki mesafeyi mi görmek istiyorsunuz? Hız testini çalıştırın

Hangi sayfanın yavaş olduğunu bize söyleyin
Adresi ve bugün nerede çalıştığını bize gönderin. Önce sunucuyu inceliyor, sonra neyi değiştireceğimizi ve bunun ne sağlaması gerektiğini söylüyoruz - ve bu görüşmeden sonra iş için teklif veriyoruz.