Bir PHP App hızlandırmak

7 Cevap php

Ben işlenmesi gereken verilerin bir listesi var. Şu anda çalışıyor yolu şudur:

  • Bir kullanıcı sürecinin düğmesine tıklar.
  • PHP kodu böylece, işlenmiş gereken ilk öğeyi alır işlemek için 15-25 saniye sürer, sonraki öğeye geçer, ve.

Bu yol çok uzun sürüyor. Ne istiyorum yerine olmasıdır:

  • Kullanıcı sürecinin düğmesine tıklar.
  • Bir PHP betiği ilk öğeyi alır ve işleme başlar.
  • Aynı anda komut başka bir örneği sonraki öğeyi alır ve onu işler.
  • Ve böylece, bu yüzden etrafında 5-6 öğelerin eşzamanlı işlem ediliyor ve biz bunun yerine sadece bir 15-25 saniye içinde işlenen 6. ürün almak.

Mümkün böyle bir şey mi?

Ben her saniye script bir örneğini başlatmak için kullanmak CRON düşünüyordum. Işlenmesi gereken tüm öğeleri MySQL veritabanı gibi bayraklı olacak, bu yüzden bir örneği CRON üzerinden başlatılan olduğunda, sadece bir sonraki öğeyi işlenecek bayraklı almak ve bayrağı kaldırmak olacaktır.

Düşünceler?

Edit: bir şey açıklığa kavuşturmak için, her bir 'madde' ayrı satır olarak bir MySQL veritabanı tablosunda saklanır. Bir öğenin üzerine başlar işleme zaman, bu nedenle her yeni örneği sadece işleniyor değil sonraki satır kapmak ve onu işleyecek, db işleniyor olarak işaretlenir. Dolayısıyla ben komut satırı argümanları olarak ürün tedarik etmek zorunda değilsiniz.

7 Cevap

Burada bir çözüm, değil büyük, ama Linux üzerinde ince çalışacak:

Ayrı bir CLI komut içine işleme PHP bölmek:

  • The command line inputs include `$id` and `$item`
  • The script writes its PID to a file in `/tmp/$id.$item.pid`
  • The script echos results as XML or something that can be read into PHP to stdout
  • When finished the script deletes the `/tmp/$id.$item.pid` file

Sizin ana komut (muhtemelen sizin sunucunuza) yapardı:

  • `exec("nohup php myprocessing.php $id $item > /tmp/$id.$item.xml");` for each item
  • Poll the `/tmp/$id.$item.pid` files until all are deleted (sleep/check poll is enough)
  • If they are never deleted kill all the processing scripts and report failure
  • If successful read the from `/tmp/$id.$item.xml` for format/output to user
  • Delete the XML files if you don't want to cache for later use

Bir arka planlı nohup başladı uygulaması başlattı komut bağımsız çalışacaktır.

Bu bir POC yazmaya karar verdim yeterince ilgimi.

dnm.php

<?php
$dir =  realpath(dirname(__FILE__));
$start = time();

// Time in seconds after which we give up and kill everything
$timeout = 25;

// The unique identifier for the request
$id = uniqid();

// Our "items" which would be supplied by the user
$items = array("foo", "bar", "0xdeadbeef");

// We exec a nohup command that is backgrounded which returns immediately
foreach ($items as $item) {
    exec("nohup php proc.php $id $item > $dir/proc.$id.$item.out &");
}

echo "<pre>";
// Run until timeout or all processing has finished
while(time() - $start < $timeout) 
{
  echo (time() - $start), " seconds\n";
  clearstatcache();    // Required since PHP will cache for file_exists
  $running = array();
  foreach($items as $item)
  {
      // If the pid file still exists the process is still running    
      if (file_exists("$dir/proc.$id.$item.pid")) {
          $running[] = $item;
      }
  }
  if (empty($running)) break;
  echo implode($running, ','), " running\n";
  flush();
  sleep(1);  
}

// Clean up if we timeout out
if (!empty($running)) {
    clearstatcache();
    foreach ($items as $item) {
        // Kill process of anything still running (i.e. that has a pid file)
        if(file_exists("$dir/proc.$id.$item.pid") 
            && $pid = file_get_contents("$dir/proc.$id.$item.pid")) {
            posix_kill($pid, 9);                
            unlink("$dir/proc.$id.$item.pid");
            // Would want to log this in the real world
            echo "Failed to process: ", $item, " pid ", $pid, "\n";
    }
    // delete the useless data
    unlink("$dir/proc.$id.$item.out");
    }
} else {
    echo "Successfully processed all items in ", time() - $start, " seconds.\n";
    foreach ($items as $item) {
    // Grab the processed data and delete the file
        echo(file_get_contents("$dir/proc.$id.$item.out"));
        unlink("$dir/proc.$id.$item.out");
    }
}
echo "</pre>";
?>

proc.php

<?php
$dir =  realpath(dirname(__FILE__));
$id = $argv[1];
$item = $argv[2];

// Write out our pid file
file_put_contents("$dir/proc.$id.$item.pid", posix_getpid());

for($i=0;$i<80;++$i)
{
    echo $item,':', $i, "\n";
    usleep(250000);
}

// Remove our pid file to say we're done processing
unlink("proc.$id.$item.pid");

?>

Put dnm.php and proc.php in the same folder of your server, load dnm.php and enjoy.

Elbette bu işe almak için nohup (unix) ve PHP cli gerekir.

Çok eğlenceli, daha sonra bunun için bir kullanım bulabilirsiniz.

Beanstalkd PHP komut çok işlerin bir sürü yazar gibi harici workqueue kullanın. Sen gibi çok sayıda işçi işlemleri beanstalkd işlerini çekerek ve mümkün olduğunca hızlı onları işleme sahiptir. Eğer bellek / işlemci var gibi birçok işçi kadar spin olabilir. İşiniz vücut, mümkün olduğunca sizinle DB vurmak belki sadece biraz kimlikleri az bilgi içermelidir. beanstalkd istemci API'leri bir takım var ve kendisi çok temel bir API vardır, memcached düşünüyorum.

Biz arka plan tüm işleri işlemek için beanstalkd kullanın, ben onu seviyorum. Onun çok hızlı, kullanımı kolay.

PHP hiçbir çoklu ancak çatal kullanabilirsiniz vardır.

php.net:pcntl-fork

Yoksa bir sistem () komutu yürütmek ve okuyuculu başka bir işlem başlatmak olabilir.

Eğer istemci tarafında javascript parçacığı uygulama olabilir? Bunu uygulayan (belki? google dan) bir javascript kitaplık gördüm gibi geliyor bana. google ve ben bir şey bulacaksınız eminim. Ben bunu hiç yapmadım, ama mümkün biliyorum. Neyse, istemci tarafı javascript ayrı ipler her madde için bir kez (ajax) bir php script aktive olabilir. bu sunucu tarafında tüm yapmak için çalışırken daha kolay olabilir.

-Don

Eğer yüksek trafik PHP sunucu çalıştırıyorsanız vardır INSANE Eğer Alternatif PHP Cache kullanmak istemiyorsanız: http://php.net/manual/en/book.apc.php. Kod modifikasyonlar APC çalıştırmak için yapmak zorunda değilsiniz.

APC sayfaları yeniden zorunda kalmamak çıktıyı önbelleğe sağlar Smarty şablon sistemi kullanıyor ile birlikte çalışabilir bir başka yararlı bir tekniktir.

Bu sorunu çözmek için, ben iki farklı ürünler kullandım; Gearman ve RabbitMQ.

Gearman veya Tavşan gibi yazılım kuyruk çeşit içine işler koyarak yararı hepsi kuyruğa (ler) kapalı işleme öğeleri katılabilir birden fazla makine, olması.

Gearman kurulumu kolaydır, bu yüzden ilk onunla biraz etrafında alay öneririm. Eğer bulursanız sıra sağlamlığı ile bir şey daha ağır gerekir; RabbitMQ içine bak

IPC geri çocuk süreç (Eğer fork'd bir) bitmiş ana süreç iletişim kurmak gibi bir şey gerekiyor - ancak bir süreç çatallanamadı pcntl_fork () ve aile kullanabilirsiniz.

Bunları memcache veya DB aracılığıyla gibi, paylaşımlı bellek yazmak olabilir.

Ayrıca çocuk süreç ana süreç kontrol sürdürür, bir dosyaya tamamlanan veri yazmak olabilir - her çocuk süreç dosyası güncelleştirildi / yazılır / oluşturulur ve ana süreç bir anda yakala tamamlar gibi, ve Onları callee / istemci onları geri atmak.

Ebeveynin iş (vb ... iyi ki kaçak süreci öldürmek ve baştan başlamak) Emin aynı veri çocukları kontrol aklı iki defa ve aynı zamanda işlenmiş olmadığından emin olmak için, kuyruğunu kontrol etmek

Başka bir şey akılda tutmak için - Ben size bunun için destek PHP derlenmiş sürece pcntl_ erişimi dont bile düşünüyorum - pencereler platformlarda ciddi sınırlı olacak.

Ayrıca, onun işlendiğinde kez verileri önbelleğe, ya da her zaman benzersiz bir veri olabilir? bu kesinlikle kadar şeyleri hızlandırmak istiyorsunuz ..?