Nasıl PHP çok çekirdekli işlemcilerin iyi şekilde yapabilirim / MySQL uygulamaları?

4 Cevap php

Ben bir özel inşa CMS benzeri bir uygulama korumak.

Bir belge teslim olduğu zaman, bazı görevler kabaca aşağıdaki kategorilerde toplanabilir ki yapılır:

  1. MySQL sorgular.
  2. HTML içeriği ayrıştırma.
  3. Arama kütüğü güncelleştirme.

Kategori 1, bir belgenin içeriğine ilişkin çeşitli MySQL tabloları güncelleştirmeleri içerir.

Kategori 2, bazı otomatik çapa etiketi dönüşümleri gerçekleştirmek için MySQL LONGTEXT alanlarında saklanan HTML içeriği ayrıştırma içerir. Ben hesaplama zaman büyük bir bu görevde harcanan olduğunu sanıyorum.

Kategori 3 belgeye karşılık gelen alanların sadece bir avuç kullanarak basit MySQL tabanlı arama dizinine güncelleştirmeleri içerir.

Bütün bu görevleri tam olarak kabul edilecek belge sunulması için tamamlamanız gerekir.

Bu uygulamayı barındıran makine çift dört çekirdekli Xeon işlemciler (8 çekirdek toplam) sahiptir. Bir belge gönderdiğinde zaman Ancak, yürütür, tüm PHP kodu çekirdek birinde çalışan tek bir süreç sınırlıdır.

Benim soru:

Ne şemaları, varsa, birden fazla CPU çekirdek arasında sizin PHP / MySQL web uygulama işleme yük bölmek için kullanılır mı? Benim ideal çözümü temelde, birkaç süreçleri yumurtlamaya onları birkaç çekirdek paralel olarak yürütmek, izin ve süreçlerin tüm yapılır kadar sonra bloke olur.

İlgili soru:

En sevdiğiniz PHP performans profilleme aracı nedir?

4 Cevap

PHP oldukça multi-threading yönelik değildir: Zaten fark olarak, her sayfası bir PHP süreci ile servis edilir - SQL sorgusu veritabanı sunucusu üzerinde idam edilirken, sadece "bekleme" de dahil olmak üzere, bir seferde bir şey yapar.

Ne yazık ki, bu konuda yapabileceği fazla bir şey yok: PHP çalışır yoludur.


Still, here's a couple of thoughs :

  • First of all, you'll probably have more that 1 user at a time on your server, which means you'll serve several pages at the time time, which, in turn, means you'll have several PHP processes and SQL queries running at the same time... which means several cores of your server will be used.
    • Her PHP işlemi, bir kullanıcı isteğine karşılık olarak, tek bir iç kısım üzerinde çalışacaktır, ancak Apache paralel çalışan birçok alt işlemler (one for each request, up to a couple of dozens or hundreds, depending on your configuration) orada
    • Her isteği daha o bir çekirdek hizmet olamaz bile - MySQL sunucusu birkaç eşzamanlı isteklerini yanıtlamak için birkaç farklı çekirdek kullanabilirsiniz anlamına gelir, multi-threaded.

Yani, aslında, sunucunun 8 çekirdekli kullanılıyor sona erecek ;-)


And, if you think your pages are taking too long to generate, a possible solution is to separate your calculations in two groups :

  • Bir bir yandan, sayfa oluşturmak için yapılması gereken şey: olanlar için, çok fazla yapabileceğiniz yok
  • On the other hand, the things that have to be run sometimes, but not necessarily immediatly
    • Onları oldukça güncel olmak istiyorum, ama onlar geride birkaç dakika gecikme varsa, bu genellikle oldukça Tamam: Örneğin, bazı istatistik hesaplamaları düşünüyorum duyuyorum.
    • Neyse, kullanıcıların / alma kendi posta okumak önce birkaç dakika geçecek, böylece derhal onları göndermek gerek yoktur: e-posta göndermek için aynı.

For the kind of situations in my second point, as you don't need those things done immediatly... Well, just don't do them immediatly ;-)
A solution that I often use is some queuing mecanism :

  • Bir "todo-listesi" web uygulama mağazası şeyler
  • Ve "todo listesi" cronjob üzerinden sıklıkla işletilen bazı partiler tarafından de-kuyruğa olduğunu

Burada da, bir cronjob mükemmel bir araçtır, ve - ve diğer bazı manipülasyonlar için, sadece onları her X dakikada çalıştırmak istiyorum.

Introduction

PHP pek çok yönden tam yararlanabilirsiniz tam Multi-Threading desteği vardır. Farklı örneklerde bu Multi-Threading yeteneğini göstermek mümkün olmuştur:

A quick Search ek kaynak verecekti.

Categories

1: MySQL queries

Düzgün performans için yapılandırılmış ise MySQL is fully multi-threaded ve birden fazla CPU kullanımı yapacak, işletim sistemi bunları destekleyen koşuluyla, aynı zamanda sistem kaynaklarını en üst düzeye çıkarmak olacaktır.

Iplik performansı etkileyen my.ini tipik bir ayardır:

thread_cache_size = 8

thread_cache_size yeni bağlantıları bir sürü varsa performansını artırmak için artırılabilir. Eğer iyi bir işlem uygulamasına sahipseniz, normal olarak, bu dikkate değer bir performans artışı sağlamaz. Sunucu saniyede bağlantı yüzlerce görürse en yeni bağlantı önbelleğe kullanımı konuları böylece Ancak, normalde yeterince thread_cache_size yüksek ayarlamanız gerekir

Eğer kullanıyorsanız Solaris daha sonra da kullanabilirsiniz

thread_concurrency = 8 

thread_concurrency konuları sistem aynı anda çalıştırılması gereken parçacığı istenen sayısı hakkında bir ipucu vermek için uygulamaları sağlar.

Bu değişken MySQL 5.6.1 itibariyle önerilmemektedir ve MySQL 5.7 çıkarılır. Onlar Solaris 8 veya daha önceki sürece bunu görmek ne zaman MySQL yapılandırma dosyalarından bu kaldırmanız gerekir.

InnoDB::

Eğer Innodb depolama motoru kullanıyorsanız eğer böyle bir sınırlama yok çünkü tam destekleri parçacığı eşzamanlılık

innodb_thread_concurrency //  Recommended 2 * CPUs + number of disks

Default 64 bağlıdır 4 ve o kadar yüksek artış olabilir yeri de innodb_read_io_threads bakmak ve innodb_write_io_threads olabilir donanım

Others:

Ayrıca bakmak için diğer konfigürasyonları key_buffer_size, table_open_cache, sort_buffer_size, vb daha iyi bir performans sonucunu cal tüm gruplar arasında

PHP:

In pure PHP her sorgu ayrı PHP parçacığı yürütülür MySQL Worker oluşturabilirsiniz

$sql = new SQLWorker($host, $user, $pass, $db);
$sql->start();

$sql->stack($q1 = new SQLQuery("One long Query")); 
$sql->stack($q2 = new SQLQuery("Another long Query"));

$q1->wait(); 
$q2->wait(); 

// Do Something Useful

Here is a Full Working Example of SQLWorker

2: HTML content parsing

I suspect that a great deal of computation time is spent in this task.

Zaten sorunu biliyoruz, o zaman daha kolay bir olay döngüler, İş Kuyruğu veya konu kullanarak yoluyla çözmek için yapar.

Bir defada tek bir belge birinde çalışan bir very very slow painful process olabilir. @ka anda birden fazla isteği çağıran için ajax kullanarak onun yolunu kesmek, bazı Yaratıcı beyinler sadece pcntl_fork kullanarak işlemini çatal ederim ama windows kullanıyorsanız, o zaman olabilir pcntl yararlanmak değil

pThreads hem de Windows ve UNIX sistemleri destekleyen, Sen böyle bir sınırlama yoktur ile. Kadar kolay mı .. ayrıştırmak için gerekiyorsa 100 document? Spawn 100 Threads ... Basit

HTML Scanning

// Scan my System
$dir = new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS);
$dir = new RecursiveIteratorIterator($dir);

// Allowed Extension
$ext = array(
        "html",
        "htm"
);

// Threads Array
$ts = array();

// Simple Storage
$s = new Sink();

// Start Timer
$time = microtime(true);

$count = 0;
// Parse All HTML
foreach($dir as $html) {
    if ($html->isFile() && in_array($html->getExtension(), $ext)) {
        $count ++;
        $ts[] = new LinkParser("$html", $s);
    }
}

// Wait for all Threads to finish
foreach($ts as $t) {
    $t->join();
}

// Put The Output
printf("Total Files:\t\t%s \n", number_format($count, 0));
printf("Total Links:\t\t%s \n", number_format($t = count($s), 0));
printf("Finished:\t\t%0.4f sec \n", $tm = microtime(true) - $time);
printf("AvgSpeed:\t\t%0.4f sec per file\n", $tm / $t);
printf("File P/S:\t\t%d file per sec\n", $count / $tm);
printf("Link P/S:\t\t%d links per sec\n", $t / $tm);

Output

Total Files:            8,714
Total Links:            105,109
Finished:               108.3460 sec
AvgSpeed:               0.0010 sec per file
File P/S:               80 file per sec
Link P/S:               907 links per sec

Class Used

Sink

class Sink extends Stackable {
    public function run() {
    }
}

LinkParser

class LinkParser extends Thread {

    public function __construct($file, $sink) {
        $this->file = $file;
        $this->sink = $sink;
        $this->start();
    }

    public function run() {
        $dom = new DOMDocument();
        @$dom->loadHTML(file_get_contents($this->file));
        foreach($dom->getElementsByTagName('a') as $links) {
            $this->sink[] = $links->getAttribute('href');
        }
    }
}

Experiment

8,714 dosya ayrıştırma çalışılıyor bu konuları olmadan 105,109 bağlantıları var ve ne kadar süreceğini görüyoruz.

Better Architecture

Üretimi yapmak için akıllı bir şey değil pek çok konuları yumurtlama. Daha iyi bir yaklaşım açısından kullanmak olacaktır Pooling. Bir havuzu var Task ile Workers ardından stack tanımlamak

Performance Improvement

Yine de yukarıdaki örneğin ince improved. Tarama sistemi bekliyor Insted all files in a single thread siz de use multiple threads scan my system dosyalar daha sonra işlenmek üzere İşçi veri yığını olabilir

3: Search index updating

Bu hemen hemen ilk cevap tarafından cevap olmuştur, ancak performans iyileştirilmesi için pek çok yol vardır. Hiç Olay tabanlı yaklaşım düşündünüz mü?

Introducing Event

@rdlowrey Alıntı 1:

Peki bu gibi düşünüyorum. Eğer web uygulamasında 10.000 anda bağlı müşterilerine hizmet etmek gerekir düşünün. Lütfen ipler hala ne kadar hafif olursa olsun bir anda açık onlardan 10.000 tutamaz çünkü Geleneksel thread-per-request veya process-per-request sunucuları bir seçenek değildir.

@rdlowrey Alıntı 2:

Öte yandan, tek bir süreç içinde tüm yuva tutmak ve bu prizler okunabilir olmak ya da sizi yazılabilir için dinlemek eğer tek bir olay döngü içinde tüm sunucu koymak ve okuma / yazma için bir şey var sadece her soketi üzerinde çalışır.

Neden soruna event-driven, non-blocking I/O yaklaşımı ile deneme yok. PHP vardır libevent uygulama güçlendirmek için.

Ben biliyorum, bu soru, tüm Multi-Threading ama bazı zamanınız varsa Nuclear Reactor written in PHP @igorw bu bakabilirsiniz

Finally

Consideration

Ben senin görevin bazı Cache ve Job Queue kullanarak kondansatöre gerektiğini düşünüyorum. Kolayca belirten bir mesaj olabilir

Document uploaded for processing ..... 5% - Done   

Sonra her zaman arka planda görev israf yok. Benzer bir vaka çalışması için Making a large processing job smaller bakınız.

Profilling

Aracı profilleme? Için Xdebug bir web uygulaması için tek bir profil araç yoktur Yslow hepsi çok yararlıdır. Örn. Onun desteklenmiyor çünkü parçacığı geldiğinde xdebug kullanışlılığı değil

I don't have a favorite

Bu aradığınız soruya bir cevap olmayabilir, ama çözüm parçacığı ile fırsatlar arıyorlar. Threading çok çekirdekli programlama için gerekli olan, ve diş not PHP uygulanmaktadır.

Ama, bir anlamda, işletim sisteminin çoklu görev yetenekleri dayanarak PHP yaparsın sahte parçacığı. Ben ne gerek ulaşmak için bir strateji geliştirmek için Multi-threading strategies in PHP hızlı bir bakış verilir öneririz.

Web Sunucuları ölçekleme bu çok çekirdekli işlemcilerin erişmek söz konusu olduğunda MySQL bir inç ödün yapmak için gitmiyor. Neden? Öncelikle MySQL iki ana Depolama Motorları düşünün

MyISAM

Bu depolama motoru çoklu çekirdek erişmez. Bu asla ve asla. Her INSERT, UPDATE için tam bir tablo kilitleme yapar ve DELETE. Bir MyISAM ile bir şey yapmak için birden çok Web Sunucuları sorguları gönderme sadece bottlenecked alır.

InnoDB

Önce MySQL 5.1.38 için, bu depolama motor sadece bir CPU erişti. Sen run MySQL multiple times on one machine to coerce the cores to handle different instances of MySQL gibi garip şeyler yapmak zorunda. Ardından, Web Sunucular 'DB bağlantıları birden çok örneği arasında dengeli yük var. Yani (MySQL 5.1.38 önce MySQL sürümlerini kullanıyorsanız, özellikle) eski okul.

MySQL 5.1.38 ile başlayarak, yeni InnoDB eklentisi yükleyin. Bu, birden fazla işlemci erişimi InnoDB almak için ayarlamak zorunda özelliklere sahiptir. Ben DBA StackExchange bu konuda yazdım

Bu yeni özellikleri de MySQL 5.5/5.6 ve Percona Server tamamen mevcuttur.

CAVEAT

Özel CMS FULLTEXT indeksleme / arama kullanıyorsa InnoDB şimdi FULLTEXT indeksleme / arama destekler, çünkü MySQL 5.6 için yükseltmeniz gerekir.

MySQL 5.6 için yükleme otomatik işlemciler olacak almak için gitmiyor. SOL yapılandırılmamış, daha yeni sürümleri depar ve outgun MySQL eski sürümleri için mümkündür, çünkü onu ayarlamak zorunda kalacak: