Ben daha hızlı yürütme biçimine benim PHP komut dosyası derlemek miyim?

8 Cevap php

Benim arka uç veritabanı için bir JSON API gibi davranan bir PHP komut dosyası var.

http://example.com/json/?a=1&b=2&c=3 ... benim veritabanından set sonucu ile bir json nesnesi dönecektir: Anlamı, bunu gibi bir HTTP isteği göndermek.

Kelimenin tam anlamıyla kod yaklaşık 10 satır çünkü PHP bunun için harika çalışıyor.

Ama aynı zamvea PHP yavaş olduğunu ve bu kez yaklaşık 40x saniyede denir ediliyor ve PHP yetişmek için mücadele bir API olduğunu biliyoruz.

Ben daha hızlı yürütme biçimine benim PHP komut dosyası derlemek için bir yolu var mı? Ben zaten bytekod PHP optimizasyonu gibi FastCGI PHP-APC kullanıyorum.

Yoksa, herkes Apache hala example.com / json / isteklerini işleyebilir böylece ben senaryoyu yeniden bir dil öneriyor?

Teşekkürler

UPDATE: Ben sadece bazı kriterler koştu:

  • PHP script takes 0.6 second to complete
  • Yukarıdaki PHP script oluşturulan SQL kullanımı ve aynı web sunucusu sorguyu çalıştırmak ancak doğrudan MySQL komutu anlam içinde, ağ gecikme hala oyunda ise - zorlama sonucu küme tamamlamak için sadece 0.09 saniye sürer.

Fark olarak, PHP sonuçları üreten yavaş anlamıyla büyüklük 1. emridir. Ben genellikle kök nedeni olduğunu kabul olsa da, ağ, bu durumda büyük bir darboğaz olarak görünmüyor.

8 Cevap

Veritabanı çok okuma-ağır ise (ben öyle tahmin ediyorum) daha sonra temel bir önbelleğe alma uygulaması yardımcı olur, ve memcached çok hızlı olur.

Bana bu örneğin URL yapısını değiştirmek edelim:

/widgets.json?a=1&b=2&c=3

Web servisine her çağrı için, GET argümanları ayrıştırmak ve önbellek kullanmak için bir anahtar oluşturmak için bu kullanmak mümkün olurdu. Diyelim ki widgets için sorguladığınız varsayalım. Örnek kod:

<?
// a function to provide a consistent cache key for your resource
function cache_key($type, $params = array()){
 if(empty($type)){
  return false;
 }
 // order your parameters alphabetically by key.
 ksort($params);
 return sha1($type . serialize($params));
}

// you get the same cache key no matter the order of parameters
var_dump(cache_key('widgets', array('a' => 3, 'b' => 7, 'c' => 5)));
var_dump(cache_key('widgets', array('b' => 7, 'a' => 3, 'c' => 5)));


// now let's use some GET parameters.
// you'd probably want to sanitize your $_GET array, however you want.
$_GET = sanitize($_GET);

// assuming URL of /widgets.json?a=1&b=2&c=3 results in the following func call:
$widgets_cache_key = cache_key('widgets', $_GET);

// connect to memcache (requires memcache pecl module)
$m = new Memcache;
$m->connect('127.0.0.1', 11211);

// try to get data from cache
$data = $m->get($widgets_cache_key);
if(empty($data)){
 // data is not in cache. grab it.
 $r = mysql_query("SELECT * FROM widgets WHERE ...;");
 while($row = mysql_fetch_assoc($r)){
  $data[] = $row;
 }
 // now store data for next time.
 $m->set($widgets_cache_key, $data);
}

var_dump(json_encode($data));
?>

Sen zaten iyi APC opcode önbelleğe alma kullanıyoruz. Eğer hala ihtiyacınız performans almıyorsanız bulursanız, burada deneyebilirsiniz diğer bazı şeyler şunlardır:

1) web sunucusunun önünde bir Squid caching proxy koyun. Talepleriniz derece önbelleklenebilecek iseniz, bu iyi mantıklı olabilir.

2) memcached pahalı veritabanı aramalarını önbelleğe için kullanın.

Eğer veritabanı güncellemeleri taşıma yapıyorsanız, MySQL performans IMO, dikkat edilmesi gereken, ne olduğunu düşünün. Ben şöyle bir test koşum genişletmek olacaktır:

  • dbserver üzerinde mytop çalıştırın
  • masaüstü gibi, bir istemci ab (apache tezgah) çalıştırın
  • web sunucusu üzerinde üst veya vmstat çalıştırmak

Ve bunlar için izle

  • zorlayarak masaya güncellemeleri (MyISAM motoru) beklemek okur
  • web sunucusu üzerinde yüksek yük (webserver düşük bellek durumlara işaret edebilir)
  • web sunucusu üzerinde yüksek disk etkinliği, belki günlük veya diğer web istekleri uncached dosyaların rastgele arayan neden
  • apache işlemlerin bellek büyüme. Lütfen sonuç kümeleri büyük ilişkisel diziler, veya serisi / tefrika almak dönüşür alıyorsanız, bu pahalı bellek ayırma işlemleri olabilir. Sizin kod Mysql_Fetch_Assoc gibi aramaları önlemek () ve bir seferde bir satır getiriliyor başlamak gerekebilir.

Ben sık sık alışılmadık sorgu kez oturum, gibi pek geçiş yapabilirsiniz küçük bir profiler adaptörü ile benim db sorguları sarın:

function query( $sql, $dbcon, $thresh ) {
    $delta['begin'] = microtime( true );
    $result = $dbcon->query( $sql );
    $delta['finish'] = microtime( true );
    $delta['t'] = $delta['finish'] - $delta['begin'];
    if( $delta['t'] > $thresh )
        error_log( "query took {$delta['t']} seconds; query: $sql" );
    return $result;
}

Ben onunla birlikte teşhis sayfayı beğendim çünkü Şahsen ben, APC XCache kullanmayı tercih.

Zamanla performansını Grafik. Eşzamanlı bağlantı sayısını takip ve performans sorunları ile korelasyon olmadığını görmek. Bir cronjob netstat http bağlantılarının sayısını grep ve daha sonra analiz için o giriş yapabilirsiniz.

Senin de mysql sorgu önbelleği etkinleştirmeyi düşünebilirsiniz.

Bakınız this question. Birkaç seçeneğiniz var. Evet, PHP yerli ELF için derlenmiş olabilir (ve hatta muhtemelen FatELF) biçimi. Sorun Zend yaratık konfor hepsi bu.

Php kodu gerçekten sorun gibi kriter itibaren görünüyor. Eğer kod gönderebilir miyim?

Eğer MySQL kodunu kaldırmak ve sadece db geri alırsınız ne temsil kodlanmış bir dize koymak ne olur?

Bu php den 0,60 saniye ve bir MySQL CLI sadece 0,09 saniye sürer beri bağlantı oluşturma çok fazla zaman alıyor tahmin olacaktır. PHP varsayılan istek başına yeni bir bağlantı oluşturur ve bazen yavaş olabilir.

Sizin env ve sizden kodunuzu bağlı, Bir düşünün:

  1. Bir IP MySQL sunucusunun bilgisayar adını çözümlemek
  2. Sunucuya bir bağlantı açın
  3. Sunucusuna kimlik doğrulaması
  4. Son olarak sorguyu çalıştırın

Have you considered using persistent MySQL connections or connection pooling? It effectively allows you to jump right to query step from above.

Önbellekleme de performans için harika. Ben diğerleri zaten oldukça iyi bu örtülü düşünüyorum.

Eğer bir sorun varsa bir şey, ilk figürü optimize gitmeden önce. Ben çok bir sorun yok sanıyorum (size göre) kod sadece 10 satır düşünüyor. Komut yürütmek için ne kadar sürer zamanı. Bu ağ gecikme olacak tipik cüce önemsiz komut dosyası yürütme kez unutmayın.

Başka bir deyişle: have Bir sorun sizin kadar sorunu çözmek değil.

Zaten bir opcode önbellek (APC) kullanıyorsunuz. Bu çok daha hızlı almaz. Daha fazla noktaya, nadiren needs daha hızlı daha alır.

Eğer bir şey size veritabanı ile sorunları gerekir. (Saniyede 20x olası) bağlamak için çok yavaş ya da büyük bir çok bağlantıları: sorgu çok yavaş. Eğer 9 kez 10 etkili indeksleme dışında bu durumda kendinizi bulmak ve veritabanı ayarlama yeterli ise.

Memcached, beanstalkd ve gibi: bazı önbelleğe tür için nereye değil durumda.

Ama dürüst olmak gerekirse saniyede 20x bu çözümleri neredeyse kesinlikle bir sorun değil bir şey için overengineering demektir.

Ben çok hızlı sonuçlar için birlikte PHP, memcached ve nginx adlı memcache modülü kullanarak şans çok yaşadım. Kolay yolu sadece önbellek anahtarının olarak tam URL'yi kullanmak için

Bu URL kabul edeceğiz:

/widgets.json?a=1&b=2&c=3

Örnek PHP kodu:

<?
$widgets_cache_key = $_SERVER['REQUEST_URI'];

// connect to memcache (requires memcache pecl module)
$m = new Memcache;
$m->connect('127.0.0.1', 11211);

// try to get data from cache
$data = $m->get($widgets_cache_key);
if(empty($data)){
    // data is not in cache. grab it.
    $r = mysql_query("SELECT * FROM widgets WHERE ...;");
    while($row = mysql_fetch_assoc($r)){
    	$data[] = $row;
    }
    // now store data for next time.
    $m->set($widgets_cache_key, $data);
}

var_dump(json_encode($data));
?>

Bu başlı başına çok büyük bir performans artışı sağlar. Eğer Apache için bir ön uç (80 üzerine 8080 ve nginx üzerinde Apache koymak) olarak nginx kullanmak olsaydı, sizin nginx config yapabilirsiniz:

worker_processes  2;

events {
    worker_connections  1024;
}

http {
    include  mime.types;
    default_type  application/octet-stream;

    access_log  off;
    sendfile  on;
    keepalive_timeout  5;
    tcp_nodelay  on;
    gzip  on;

    upstream apache {
        server  127.0.0.1:8080;
    }

    server {
        listen  80;
        server_name  _;

        location / {
            if ($request_method = POST) {
                proxy_pass  http://apache;
                break;
            }
            set  $memcached_key $uri;
            memcached_pass  127.0.0.1:11211;
            default_type  text/html;
            proxy_intercept_errors  on;
            error_page  404 502 = /fallback;
        }

        location /fallback {
            internal;
            proxy_pass  http://apache;
            break;
        }
    }
}

set $memcached_key $uri; çizgisine dikkat edin. Bu memcached önbellek anahtar REQUEST_URI sadece PHP komut gibi kullanmak için ayarlar. Nginx bu anahtara sahip bir önbellek girdisi keşfeder Yani bellekten doğrudan hizmet edecek, ve PHP veya Apache dokunmak zorunda kalmazsınız. Çok hızlı.

Resmi olmayan bir Apache memcache module yanı yoktur. Bunu denemedim ama nginx ile karmaşa istemiyorsanız, bu da size yardımcı olabilir.

Optimizasyonu ilk kuralı aslında bir performans sorunu var emin olmaktır. İkinci kural performans sorunu measuring kodunuz tarafından nerede olduğunu anlamaya etmektir. Sanırım yok. Sabit ölçümler alın.

PHP, engel olacak değildir. Ben hemen hemen garanti edemez. Ağ bant genişliği ve gecikme derlenmiş bir C programı vs PHP kullanarak küçük yükü cüce olacak. Ve hızını ağ değilse, o zaman disk I / O veya veritabanı erişimi, ya da gerçekten kötü bir algoritma veya dilin kendisi dışında daha olası suçluları bir ev sahibi olacaktır.