İçeriğe geç
Muhammet Şafak
en
Servis & yük

Yedi PHP framework'ü aynı yükte ölçtüm: fark, istek gerçek iş yaptıkça küçülüyor

Aynı donanımda, aynı PHP sürümünde ve aynı yedi rotayla, Laravel, Symfony, CodeIgniter, Yii2, Phalcon, Laminas ve Slim saniyede kaç isteği ne gecikmeyle karşılıyor?

Bulgu

Boş bir rotada en hızlı ile en yavaş arasında 4,4 kat var (Slim 25.975, Laravel 5.966 istek/sn). Ama istek gerçek iş yapmaya başlayınca fark kapanıyor: veritabanından tek satır çeken bir istekte 3,7 kata, yirmi satır çekende 3,5 kata iniyor. Phalcon boş rotada üçüncüyken veritabanı isteğinde beşinciye düşüyor — C eklentisi olmak, sorgu beklerken bir işe yaramıyor. Asıl pahalı olan şey framework seçimi değil: Laravel'in kendi varsayılan web middleware grubu, aynı yanıtı 5.858'den 2.176 istek/sn'ye düşürüyor — yani tek bir varsayılan, framework'ler arasındaki farkın çoğundan daha pahalı.

Boş rota, en hızlı
25.975 istek/sn
Boş rota, en yavaş
5.966 istek/sn
Fark: boş rota → veritabanı
4,4× → 3,7×
Laravel web grubu
−%63

Yöntem

Yedi aday tek bir PHP 8.4.24 derlemesinde, birebir aynı opcache/php.ini/php-fpm havuzunda (pm=static, 8 worker) ve tek bir nginx server bloğunda koştu. Her aday kendi resmî iskeletinde, kendi dokümante ettiği production kurulumuyla (route/config/view cache, APP_ENV=prod, YII_DEBUG=false, Volt önderlenmiş) ve aynı composer bayraklarıyla kuruldu. Yedisi de tam elli rota kaydediyor; parametreli rota her zaman 47. sırada. Ölçüm sırasında yalnız tek bir aday koşuyor; php-fpm 0-3, nginx 4-5, MySQL 6-7 ve yük üreteci 8-11 çekirdeklerinde, ayrık. Her senaryo 64 bağlantıyla 15 saniye, 9 tekrar; adayların sırası her turda karıştırılıyor. Her ölçümün önünde ve arkasında, PHP'ye hiç uğramayan sabit bir nginx referansı örneklenerek o anda makinenin verdiği kapasite kaydediliyor. Raporlanan değer tekrarların en iyisidir: makine sakinleştirilemediği için girişim throughput'u yalnız aşağı çekebilir, donanım tavanının üstüne çıkaramaz. Toplam 546 yük ölçümü, 150 host örneklemesi, sıfır non-200 yanıt.

Orta güven Tekrarlı ölçüm, sınırlı ortam denetimi. Aynı düzendeki farklar anlamlıdır.
Ölçüm tarihi

2 gün önce ölçüldü

Yayın

Ortam

PHP
8.4.24 NTS · opcache açık · JIT kapalı
Sunucu
nginx 1.29.1 + php-fpm · pm=static · 8 worker
Veritabanı
MySQL 8.4.11 · 10.000 satır · kalıcı bağlantı
Yük üreteci
oha 1.15.0 · 64 bağlantı · 15 sn
Donanım
Apple M4 Pro · 12 çekirdek · 24 GB · macOS 26.6.1
Sanallaştırma
Docker Desktop 29.7.2 · 12 vCPU / 7,75 GB · aarch64
Çekirdek ayrımı
fpm 0-3 · nginx 4-5 · MySQL 6-7 · yük 8-11
Tekrar
9 (+6 takviye) · en iyi koşu raporlanır

Teknolojiler

Laravel Symfony CodeIgniter Yii2 Phalcon Laminas Slim PHP Docker nginx MySQL

Tekrarlamak için

./bench/build.sh && STAMP=$(date -u +%F) ./bench/run.sh --all

PHP framework karşılaştırması, Türkçe internette çoğunlukla yöntemsiz yapılıyor: bir sayı veriliyor, hangi sürümde, hangi donanımda, kaç tekrarla ölçüldüğü yazılmıyor. Bu kaydın katkısı sıralama değil — sıralamanın yeniden türetilebilir olması. Aşağıdaki her rakam bench/run.sh çıktısından geliyor ve ham koşuların hepsi depoda duruyor.

Ne ölçtüm

Yedi aday da son kararlı sürümünde, kendi resmî iskeletinde ve kendi dokümante ettiği production kurulumunda koştu. Değişken tek bir şey: framework.

Aday Sürüm Veri katmanı Şablon
Slim 4.15.2 yok — ham PDO yok — slim/php-view
Yii2 2.0.55 ActiveRecord Yii View
Phalcon 5.19.0 Phalcon Model Volt
Symfony 8.1.4 Doctrine ORM Twig
Laminas 3.8.0 laminas-db TableGateway laminas-view
CodeIgniter 4.7.4 CI Model CI View
Laravel 13.26.1 Eloquent Blade
Slim'in kendi veri katmanı ve şablon motoru yok; o iki senaryoda diğerlerinden daha az iş yapıyor. Sonucu okurken bu satır akılda tutulmalı.

Yedisi de tam elli rota kaydediyor ve parametreli rota her zaman 47. sırada duruyor; böylece rota çözümü tek kayıtlı bir tabloda değil, gerçekçi bir tabloda ölçülüyor. Senaryolar: düz metin, JSON, parametreli rota, beş katmanlı middleware zinciri, yüz satırlık şablon (veritabanı yok), birincil anahtarla tek satır ve yirmi satırlık liste.

Sayı ne söylüyor

Saniyede karşılanan istek, üç senaryoda

Boş rotadan veritabanına inildikçe sütunlar birbirine yaklaşıyor: framework'ün kendi maliyeti, istek gerçek iş yaptığında baskın gider olmaktan çıkıyor.

  • Boş rota
  • Şablon (100 satır)
  • Veritabanı (tek satır)

Kaynak: 9 tekrarın en iyisi, 64 bağlantı, 15 sn — bench/run.sh çıktısı

Veri tablosu
9 tekrarın en iyisi, 64 bağlantı, 15 sn — bench/run.sh çıktısı
Seri SlimYii2PhalconSymfonyLaminasCodeIgniterLaravel
Boş rota 25.97519.83415.02113.0678.3496.4315.966
Şablon (100 satır) 22.78016.99510.5639.3557.4195.5575.290
Veritabanı (tek satır) 14.4439.3665.2226.9725.4214.5273.887

Grafik tarayıcıda çizilir; aşağıdaki tablo aynı veriyi taşır.

En çarpıcı hareket Phalcon’da. Boş rotada üçüncü (15.021), şablonda yine üçüncü, ama veritabanı isteğinde beşinciye düşüyor (5.222) ve Symfony’nin altında kalıyor. Yirmi satırlık listede daha da geriye, altıncılığa iniyor (2.040) — Laminas ve CodeIgniter’ın gerisinde. Framework’ün C ile yazılmış olması, süreç MySQL’den yanıt beklerken hiçbir şey kazandırmıyor; kazandırdığı yer, PHP’nin kendi kodu çalıştırdığı yer.

Aday Boş rota JSON Rota (47/50) Middleware Şablon DB tek satır DB 20 satır
Slim 25.975 25.609 24.774 24.020 22.780 14.443 4.551
Yii2 19.834 18.731 18.775 18.877 16.995 9.366 3.245
Phalcon 15.021 15.161 15.061 14.906 10.563 5.222 2.040
Symfony 13.067 12.714 12.187 12.964 9.355 6.972 3.060
Laminas 8.349 8.114 8.127 8.036 7.419 5.421 2.874
CodeIgniter 6.431 6.233 5.960 6.037 5.557 4.527 2.494
Laravel 5.966 5.848 5.603 5.704 5.290 3.887 1.293
İstek/saniye, 9 tekrarın en iyisi. Sıralama boş rotadaki hıza göre.

Farkın nasıl kapandığı tek bir satırda görünüyor: en hızlı adayın en yavaşa oranı boş rotada 4,4×, tek satırlık veritabanı isteğinde 3,7×, yirmi satırlıkta 3,5×. Phalcon’un Laravel’e oranı ise 2,5בten 1,3בe düşüyor.

Gecikme

JSON isteğinde gecikme yüzdelikleri

Yedisi de p99'da milisaltı: bu yükte hiçbiri kullanıcıya yavaş gelmiyor. Fark, aynı donanımdan kaç kullanıcı geçirebildiklerinde.

  • p50
  • p95
  • p99

ms düşük olan iyi Kaynak: En iyi throughput'u veren tekrarın kendisinden, 64 bağlantı

Veri tablosu
En iyi throughput'u veren tekrarın kendisinden, 64 bağlantı
Seri SlimYii2PhalconSymfonyLaminasCodeIgniterLaravel
p50 0,25 ms0,35 ms0,46 ms0,58 ms0,88 ms1,16 ms0,75 ms
p95 0,43 ms0,59 ms0,73 ms0,89 ms1,52 ms1,84 ms1,97 ms
p99 0,53 ms0,73 ms0,94 ms0,96 ms2,23 ms1,98 ms2,59 ms

Grafik tarayıcıda çizilir; aşağıdaki tablo aynı veriyi taşır.

Laravel’in p50’si (0,75 ms) Laminas ve CodeIgniter’dan daha iyi, ama p99’u (2,59 ms) en kötüsü. Yani Laravel tipik isteği hızlı bitiriyor, kuyruğun ucunu ise iyi yönetemiyor.

Tartışılan şeyler ucuz, varsayılanlar pahalı

Elli rotalık tabloda parametreli rota çözmek, boş rotaya göre adaylara %0-7 arasında bir bedele mal oluyor. Beş katmanlı middleware zinciri %1-8. Yani geliştiricilerin karşılaştırırken en çok konuştuğu iki şey, ölçüldüğünde tek haneli yüzdeler.

Sonra Laravel’in kutudan çıkan varsayılanına bakıyorsunuz:

Laravel rotası İstek/sn p50 p99
Middleware grubu yok 5.858 1,32 ms 2,88 ms
Varsayılan web grubu session + cookie şifreleme + CSRF 2.176 1,73 ms 71,89 ms
Aynı JSON yanıtı, aynı konteyner, aynı koşu. Tek fark rotanın web grubunun arkasında olması. p99 yirmi beş katına çıkıyor.

Bu ölçüm file session sürücüsüyle alındı. Laravel’in kutudan çıkan varsayılanı database — yani her istekte bir okuma ve bir yazma daha. Rakam oradan daha da kötüye gider.

Doygunluk: tavan sekiz worker

Eşzamanlı bağlantı sayısını 8’den 256’ya çıkardım. Yedisinde de throughput ve p99 düz kaldı.

Bağlantı Slim Yii2 Phalcon Symfony Laminas CodeIgniter Laravel
8 25.812 19.242 14.894 12.817 8.149 6.193 5.909
32 25.785 19.018 15.053 12.811 7.828 6.259 4.774
64 26.234 18.964 14.802 9.324 8.114 6.276 5.890
128 25.842 19.251 14.783 11.795 8.044 6.067 6.016
256 25.802 19.808 15.109 12.129 8.075 6.140 5.901
Sekiz php-fpm worker, dört çekirdek. Tavan sekiz bağlantıda zaten dolmuş; sonrası nginx'te kuyruğa giriyor. Bu tablo tavanı sınırlıyor, doyma eğrisi çizmiyor.

Nasıl ölçtüğüm — ve iki kez baştan başladığım

Bu ölçüm üç kez koşuldu. İlk ikisi iptal edildi ve ikisi de gerçek bir kusur buldu; ikisi de depoda gerekçesiyle duruyor.

Birinci iptal — makine sakin değildi. Slim /json bir turda 15.260, ertesi turda 2.107 istek/sn verdi; p50 ikisinde de 0,23 ms. İstek başına maliyet aynı, istek sayısı yedide bir: uygulama yavaşlamamış, koşu CPU alamamıştı. Host bir dizüstü ve üstünde pencere sunucusu, terminal ve editör çalışıyor; cpuset konteyneri VM’in içinde izole eder, VM’i macOS’ten izole etmez.

Bunun düzeltmesi ortalamayı almak değil. Girişim throughput’u yalnız aşağı çekebilir — bir koşu gürültülü komşu yüzünden yavaşlayabilir, ama donanımın izin verdiğinden hızlı olamaz. O yüzden raporlanan değer tekrarların en iyisi, yanında medyanı ve yayılımıyla. Ayrıca PHP’ye hiç uğramayan sabit bir nginx referansı her bloğun önünde ve arkasında örnekleniyor: 150 örneklemede en kötüsü en iyinin %84’ü.

İkinci iptal — port tükenmesi. Veritabanı senaryolarında isteklerin yarısı 500 dönüyordu: SQLSTATE[HY000] [2002] Cannot assign requested address. php-fpm her istekte MySQL’e yeni bir TCP bağlantısı açıyor ve konteyner saniyede birkaç bin istekte ephemeral port’ları tüketiyor. Tek istekle yapılan ön kontrol bunu yakalayamaz. Yedisinde de kalıcı bağlantıya geçildi (PDO::ATTR_PERSISTENT, CodeIgniter’da pConnect) — php-fpm için dokümante edilmiş production ayarı. Etkisi büyük: Slim’in /db sonucu 3.594’ten 14.074’e çıktı. Yani önceki ölçüm veri katmanını değil port çalkantısını ölçüyormuş.

Atlanmayan bulgular

Ölçüm boyunca çıkan ve tabloya sığmayan her şey:

  1. Yedi framework’ün buluştuğu tek PHP sürümü var: 8.4. Symfony 8.1 en az 8.4.1 istiyor, laminas/laminas-mvc 3.8 tavanı ~8.4.0. Pencere tam bir minor sürüm geniş.
  2. Phalcon ile Symfony aynı PHP sürecinde çalışmıyor. Phalcon ext-psr istiyor; o eklenti yüklüyken Symfony fatal veriyor: Declaration of Symfony\Component\Cache\CacheItem::expiresAt(?DateTimeInterface $expiration): static must be compatible with PsrExt\Cache\CacheItemInterface::expiresAt($expiration). C eklentisi PSR arayüzlerini, userland paketlerinin kullandığı parametre tipleri olmadan tanımlıyor. “Tek imaj, tek eklenti seti” planı bu yüzden tam bir yerde çatallandı: Phalcon kendi runtime imajında koşuyor, geri kalan altısı ortak imajda.
  3. CodeIgniter 4’ün PDO sürücüsü yok — MySQL desteği yalnız MySQLi. Eklenti seti aynı kalsın diye ext-mysqli yedisine birden kuruldu; diğer altısı kullanmıyor.
  4. Laminas’ın resmî iskeleti PHP 8.4 için yayınlanmamış. laminas/laminas-mvc-skeleton 2.4.0 hâlâ ~8.1.0 || ~8.2.0 || ~8.3.0 diyor; kurulum --ignore-platform-req=php olmadan reddediliyor. Açtığı bileşen (laminas/laminas-mvc 3.8.0) ~8.4.0’ı kabul ediyor.
  5. Yii2 hâlâ 2.0.x. Yii3’ün kararlı sürümü yok, yani “son kararlı Yii”, mimarisi diğerlerinin güncel sürümlerinden eski olan bir hat.
  6. Middleware yedisinde aynı kavram değil. CodeIgniter filtreleri ve Yii2 action filter’ları rotaya bağlı, diğer senaryolara hiçbir şeye mal olmuyor. Symfony, Laminas ve Phalcon’da rota bazlı bir pipeline yok; dokümante edilmiş karşılık global bir event listener, yani beş katman o uygulamalarda her istekte yoklanıp erken dönüyor. Bu onların mimarisi, buraya uydurulmuş bir handikap değil.
  7. Slim iki senaryoda daha az iş yapıyor. Kendi veri katmanı yok (/db ham PDO üstünde), kendi şablon motoru yok (slim/php-view). Birincilik bu iki satırda bu bağlamla okunmalı.
  8. Bir hücre kendi kendisiyle çelişti ve takviye edildi. Slim’in /route sonucu 9 tekrarda 6.778 istek/sn çıkmıştı — sahanın en düşük p50’si (0,23 ms) ile, kendi boş rotasının %26’sı. Dokuz tekrarın hiçbiri kırpılmamış pencereye denk gelmemişti. Önceden sabitlenmiş iki kural (temiz tekrar sayısı ≤2, veya throughput’un 8/p50’nin yarısının altında kalması) altı hücreyi işaretledi; hepsi Slim ve Yii2, yani sahanın en hızlı ikilisi — yanlılığın öngörülen yönü. Altısına altışar tekrar eklendi, Slim /route 24.774’e oturdu ve hiçbir hücre işaretli kalmadı.
  9. Sıfır non-200. 546 yük ölçümünün tamamı, kalıcı bağlantı düzeltmesinden sonra, %100 HTTP 200 döndü.
  10. JIT kapalı. Yedisinden hiçbiri opcache JIT’i production adımı olarak dokümante etmiyor ve açmak ikinci bir değişken eklerdi. Açık JIT ile sonuç farklı olabilir; bu ayrı bir ölçüm.
  11. Worker mode ölçülmedi. FrankenPHP/Octane gibi kalıcı süreç modelleri yedisinde de resmî olarak desteklenmiyor; klasik php-fpm hepsinin eşit zeminidir. Worker mode ayrı bir kayıt konusudur.

İlgili yazılar

Paylaş:

Diğer Kayıtlar

Tüm kayıtlar
Araç karşılaştırması Ölçüm

Bir PHP framework'ünü kurmanın sabit maliyeti: disk boyutu hiçbir şey söylemiyor

Yedi PHP framework'ü kurulduğunda diskte kaç megabayt, istek başına kaç dosya ve ilk istekte kaç milisaniye tutuyor — ve bu sayılardan hangisi gerçekten yük altındaki hızı öngörüyor?

Bulgu

Disk boyutu hiçbir şey öngörmüyor: Yii2 en büyük vendor'a sahip (34,1 MB) ama istek başına yalnız 62 dosya yüklüyor — sahanın en azlarından. İstek başına dosya sayısı da öngörmüyor: CodeIgniter 96 dosya yükleyip 6.431 istek/sn veriyor, Symfony 224 dosya yükleyip 13.067 veriyor. Gerçekten ayrışan tek şey opcache soğukken ödenen ilk istek: Phalcon 2,2 ms, Laravel 72,2 ms — otuz üç kat. Bu, her deploy'dan sonra ilk ziyaretçinin ödediği derleme faturasıdır ve framework başına birkaç kilobayt değil, onlarca milisaniye tutuyor.

Yüksek güven
Arayüz performansı Ölçüm

Chart.js'i nasıl import ettiğin, ziyaretçiye kaç kilobayt gönderdiğini belirliyor

`chart.js/auto` ile seçmeli `Chart.register()` arasındaki fark, gerçek bir üretim derlemesinde kaç kilobayt?

Bulgu

Seçmeli register, `chart.js/auto` yerine 9,7 kB gzip tasarruf ettiriyor (67,8 → 58,1 kB, %14,3). Asıl büyük düşüş kütüphanenin kendisinde değil, hiç kullanılmayan controller'ları dışarıda bırakmakta: yalnız çubuk grafiği kaydeden bir sayfa 46,0 kB'a iniyor — auto'nun üçte ikisi.

Yüksek güven

Sitede Ara

Yazı, proje ve sayfalarda arama yapmak için yazmaya başlayın.

Esc ile kapat Pagefind ile güçlendirildi