Mysql
 sql >> Database >  >> RDS >> Mysql

Come fai un buon uso delle CPU multicore nelle tue applicazioni PHP/MySQL?

Introduzione

PHP ha il Multi-Threading completo supporto di cui puoi sfruttare appieno in tanti modi. Sono stato in grado di dimostrare questa capacità multi-threading in diversi esempi:

Una ricerca rapida darebbe risorse aggiuntive.

Categorie

1:query MySQL

MySQL è completamente multi-thread e utilizzerà più CPU, a condizione che il sistema operativo le supporti, massimizzerebbe anche le risorse di sistema se configurato correttamente per le prestazioni.

Un'impostazione tipica in my.ini che influiscono sulle prestazioni del thread è:

thread_cache_size = 8

thread_cache_size può essere aumentato per migliorare le prestazioni se hai molte nuove connessioni. Normalmente, questo non fornisce un notevole miglioramento delle prestazioni se si dispone di una buona implementazione del thread. Tuttavia, se il tuo server vede centinaia di connessioni al secondo, normalmente dovresti impostare thread_cache_size sufficientemente alto in modo che la maggior parte delle nuove connessioni utilizzi thread memorizzati nella cache

Se stai utilizzando Solaris allora puoi usare

thread_concurrency = 8 

thread_concurrency consente alle applicazioni di fornire al sistema di thread un suggerimento sul numero desiderato di thread da eseguire contemporaneamente.

Questa variabile è deprecata a partire da MySQL 5.6.1 e viene rimossa in MySQL 5.7. Dovresti rimuoverlo dai file di configurazione di MySQL ogni volta che lo vedi, a meno che non siano per Solaris 8 o precedenti.

InnoDB: :

Non hai tali limitazioni se stai usando Innod ha il motore di archiviazione perché supporta completamente la concorrenza dei thread

innodb_thread_concurrency //  Recommended 2 * CPUs + number of disks

Puoi anche guardare innodb_read_io_threads e innodb_write_io_threads dove l'impostazione predefinita è 4 e può essere aumentato fino a 64 a seconda dell'hardware

Altri:

Altre configurazioni da considerare includono key_buffer_size , table_open_cache , sort_buffer_size ecc. che si traducono in prestazioni migliori

PHP:

In PHP puro puoi creare MySQL Worker in cui ogni query viene eseguita in thread PHP separati

$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

Ecco un esempio di lavoro completo di SQLWorker

2:Analisi del contenuto HTML

Se conosci già il problema, è più facile risolverlo tramite loop di eventi, coda di lavoro o utilizzando i thread.

Lavorare su un documento uno alla volta può essere un molto, molto processo lento e doloroso. @ka una volta hackerato la via d'uscita usando ajax per chiamare richieste multiple, alcune menti creative avrebbero semplicemente biforcato il processo usando pcntl_fork ma se stai usando windows allora non puoi sfruttare pcntl

Con pThreads supportando entrambi i sistemi Windows e Unix, non hai tale limitazione. È facile come .. Se hai bisogno di analizzare 100 documenti? Genera 100 thread... Semplice

Scansione HTML

// 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);

Risultato

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

Classe usata

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');
        }
    }
}

Esperimento

Tentativo di analisi di 8,714 file che hanno 105,109 link senza thread e guarda quanto tempo ci vorrebbe.

Architettura migliore

Generare troppi thread che non è una cosa intelligente da fare In produzione. Un approccio migliore sarebbe usare Pooling . Avere un pool di define Lavoratori quindi stack con un Task

Miglioramento delle prestazioni

Bene, l'esempio sopra può ancora essere migliorato. Invece di attendere che il sistema esegua la scansione di tutti i file in un singolo thread, puoi utilizzare più thread per scansionare il mio sistema alla ricerca di file, quindi impilare i dati in Workers per l'elaborazione

3:aggiornamento dell'indice di ricerca

Questo è stato praticamente risposto dalla prima risposta, ma ci sono così tanti modi per migliorare le prestazioni. Hai mai considerato un approccio basato sugli eventi?

Introduzione all'evento

@rdlowrey Citazione 1:

@rdlowrey Citazione 2:

Perché non provi con event-driven , non-blocking I/O approccio al tuo problema. PHP ha libevent per potenziare la tua applicazione.

So che questa domanda è tutta Multi-Threading ma se hai un po' di tempo puoi guardare questo Reattore nucleare scritto in PHP di @igorw

Finalmente

Considerazione

Penso che dovresti considerare di usare Cache e Job Queue per alcuni dei tuoi compiti Puoi facilmente avere un messaggio che dice

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

Quindi fai tutto il tempo sprecando compiti in background. Si prega di guardare Ridurre un grande lavoro di elaborazione per un caso di studio simile.

Profilazione

Strumento di profilatura? Non esiste uno strumento di profilo unico per un'applicazione web da Xdebug a Yslow sono tutti molto utili. Per esempio. Xdebug non è utile quando si tratta di thread perché non è supportato

Non ho un preferito