Mysql
 sql >> Base de données >  >> RDS >> Mysql

Comment faire bon usage des CPU multicœurs dans vos applications PHP/MySQL ?

Présentation

PHP a un Multi-Threading complet un soutien dont vous pouvez profiter pleinement de bien des façons. Ont pu démontrer cette capacité de Multi-Threading dans différents exemples :

Une recherche rapide donnerait des ressources supplémentaires.

Catégories

1 :Requêtes MySQL

MySQL est entièrement multithread et utilisera plusieurs processeurs, à condition que le système d'exploitation les prenne en charge. Il maximiserait également les ressources système s'il était correctement configuré pour les performances.

Un paramètre typique dans le my.ini qui affectent les performances du thread est :

thread_cache_size = 8

thread_cache_size peut être augmenté pour améliorer les performances si vous avez beaucoup de nouvelles connexions. Normalement, cela ne fournit pas une amélioration notable des performances si vous avez une bonne implémentation de thread. Cependant, si votre serveur voit des centaines de connexions par seconde, vous devez normalement définir thread_cache_size suffisamment élevé pour que la plupart des nouvelles connexions utilisent des threads en cache

Si vous utilisez Solaris alors vous pouvez utiliser

thread_concurrency = 8 

thread_concurrency permet aux applications de donner au système de threads une indication sur le nombre souhaité de threads qui doivent être exécutés en même temps.

Cette variable est obsolète depuis MySQL 5.6.1 et est supprimée dans MySQL 5.7. Vous devez le supprimer des fichiers de configuration MySQL chaque fois que vous le voyez, sauf s'il s'agit de Solaris 8 ou d'une version antérieure.

InnoDB : :

Vous n'avez pas de telles limitations si vous utilisez Innodb a le moteur de stockage car il prend entièrement en charge la simultanéité des threads

innodb_thread_concurrency //  Recommended 2 * CPUs + number of disks

Vous pouvez également consulter innodb_read_io_threads et innodb_write_io_threads où la valeur par défaut est 4 et il peut être augmenté jusqu'à 64 selon le matériel

Autres :

D'autres configurations à examiner également incluent key_buffer_size , table_open_cache , sort_buffer_size etc. qui entraînent tous de meilleures performances

PHP :

En PHP pur, vous pouvez créer MySQL Worker où chaque requête est exécutée dans des threads PHP séparés

$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

Voici un exemple de travail complet de SQLWorker

2 :analyse du contenu HTML

Si vous connaissez déjà le problème, il est alors plus facile de le résoudre via des boucles d'événements, la file d'attente de tâches ou l'utilisation de Threads.

Travailler sur un document un par un peut être très, très processus lent et douloureux. @ka une fois piraté en utilisant ajax pour appeler plusieurs requêtes, certains esprits créatifs feraient simplement le processus en utilisant pcntl_fork mais si vous utilisez windows alors vous ne pouvez pas profiter de pcntl

Avec pThreads prenant en charge les systèmes Windows et Unix, vous n'avez pas une telle limitation. Est aussi simple que .. Si vous avez besoin d'analyser 100 documents ? Générer 100 fils ... Simple

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

Sortie

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 utilisée

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

Expérimenter

Essayer d'analyser 8,714 fichiers qui ont 105,109 des liens sans fils et voyez combien de temps cela prendrait.

Meilleure architecture

Générer trop de threads, ce qui n'est pas une chose intelligente à faire en production. Une meilleure approche serait d'utiliser Pooling . Avoir un pool de définition Travailleurs puis pile avec une Task

Amélioration des performances

Très bien, l'exemple ci-dessus peut encore être amélioré. Au lieu d'attendre que le système analyse tous les fichiers dans un seul thread, vous pouvez utiliser plusieurs threads pour analyser mon système à la recherche de fichiers, puis empiler les données sur Workers pour traitement

3 :Mise à jour de l'index de recherche

Cela a été à peu près répondu par la première réponse, mais il y a tellement de façons d'améliorer les performances. Avez-vous déjà envisagé une approche basée sur les événements ?

Présentation de l'événement

@rdlowrey Citation 1 :

@rdlowrey Citation 2 :

Pourquoi ne pas expérimenter avec event-driven , non-blocking I/O approche de votre problème. PHP a libevent pour dynamiser votre application.

Je sais que cette question est tout Multi-Threading mais si vous avez un peu de temps, vous pouvez regarder ce Réacteur nucléaire écrit en PHP par @igorw

Enfin

Considération

Je pense que vous devriez envisager d'utiliser Cache et Job Queue pour certaines de vos tâches. Vous pouvez facilement avoir un message disant

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

Ensuite, faites toutes les tâches qui vous font perdre du temps en arrière-plan. Veuillez consulter Rendre une grande tâche de traitement plus petite pour une étude de cas similaire.

Profilage

Outil de profilage ? Il n'y a pas d'outil de profil unique pour une application Web de Xdebug à Yslow sont tous très utiles. Par exemple. Xdebug n'est pas utile en ce qui concerne les threads car il n'est pas pris en charge

Je n'ai pas de favori