web-dev-qa-db-fra.com

Comment puis-je accélérer la fonction node_save () de drupal?

J'ai beaucoup de mal avec l'inefficacité de node_save (). Mais le nœud sauve-t-il mon problème? C'est finalement ce que j'essaie de découvrir.

J'ai créé une boucle avec 100 000 itérations. J'ai créé le strict minimum pour que l'objet nœud soit valide et enregistre correctement. Voici le code de sauvegarde du nœud:

$node = new stdClass();
        $node->type = "test_page";

        node_object_prepare($node);

        $node->uid = 1;
        $node->title = $node_title;
        $node->status = 1;
        $node->language = LANGUAGE_NONE;
        if($node = node_submit($node)){
            node_save($node);
}

Voici les résultats:

100 000 nœuds ont été enregistrés, chacun utilisant node_save (). Il a fallu 5196,22 secondes pour terminer. C'est SEULEMENT 19 sauve une seconde.

Pour dire le moins, ce n'est pas acceptable, surtout lorsque cette personne reçoit environ 1200 requêtes d'insertion individuelles par seconde , et cette personne reçoit 25 000 insertions par seconde .

Alors, que se passe-t-il ici? Où est le goulot d'étranglement? Est-ce la fonction avec la fonction node_save () et comment est-elle conçue?

Serait-ce mon matériel? Mon matériel est un serveur de développement, personne d'autre que moi - Intel dual core, 3Ghz, Ubuntu 12.04 avec 16 Go de RAM.

Pendant que la boucle fonctionne, mon utilisation des ressources est: MySQL 27% CPU, 6M RAM; PHP 22% CPU 2M RAM.

Ma configuration mysql a été faite par assistant percona .

Mysql dit que si mon utilisation CPU est inférieure à 70% mon problème est lié au disque . Certes, je n'ai qu'une course du moulin WD Caviar 7200 RPM, mais je devrais obtenir plus de 19 insertions par seconde avec lui, j'espère!

Il n'y a pas si longtemps, j'ai écrit sur économiser 30 000 nœuds par jour . Cependant, pour être clair, ce nœud n'a rien à voir avec des forces externes. C'est purement une référence pour savoir comment augmenter la vitesse des appels à node_save ().

De manière réaliste, j'ai besoin d'obtenir 30 000 éléments dans la base de données chaque minute en utilisant node_save. Si la sauvegarde de nœud n'est pas une option, je me demande si je peux écrire ma propre fonction drupal api "node_batch_save ()" ou quelque chose qui tire parti de la capacité de mysql à faire des insertions en masse avec le - INSÉRER la requête . Réflexions sur la façon d'aborder cela?

9
blue928

Vous n'obtiendrez jamais 30 000 insertions par minute en utilisant node_save. En aucune façon.

Un INSERT est rapide car c'est tout ce qu'il fait. Node save effectue plusieurs insertions (table principale, table de révision, une table pour chaque champ), efface tous les caches d'entités et déclenche les hooks. Les hooks sont la partie délicate. Si vous avez plusieurs modules contrib (ou même celui qui se comporte mal) qui peut vraiment tuer les performances, surtout si l'auteur n'a pas tenu compte du cas d'utilisation "J'économise une tonne de nœuds à la fois". Par exemple, j'ai dû ajouter ceci à ma classe Migrate:

  public function processImport(array $options = array()) {
    parent::processImport($options = array());
    // Do not force menu rebuilding. Otherwise pathauto will try to rebuild
    // in each node_save() invocation.
    variable_set('menu_rebuild_needed', FALSE);
  }

D'un autre côté, si vous écrivez une fonction de sauvegarde personnalisée qui n'invoque aucun hook, vous courez un risque évident d'obtenir des données incohérentes, dans un état inattendu par le système. Je ne recommanderais jamais de faire ça. Lancez xhprof et voyez ce qui se passe.

10
Bojan Zivanovic

Tout d'abord, installez XCache/APC (pour PHP <5.5) et configurez memcached pour Drupal.

Ensuite, vous pouvez optimiser votre configuration MySQL pour les requêtes lourdes en utilisant le script mysqltuner disponible sur: http://mysqltuner.pl

Par exemple.

# performance tweaks (adjusted based on mysqltuner.pl)
query_cache_size = 32M
query_cache_limit = 256M
join_buffer_size = 32M
key_buffer = 8M
max_allowed_packet = 32M
table_cache = 512
sort_buffer_size = 1M
net_buffer_length = 8K
read_buffer_size = 256K
read_rnd_buffer_size = 1M
myisam_sort_buffer_size = 8M

# When making adjustments, make tmp_table_size/max_heap_table_size equal
tmp_table_size = 16M
max_heap_table_size = 16M

thread_cache_size = 4

Autres suggestions:

  • désactiver les modules dont vous n'avez pas besoin (par exemple Devel , module de base de données de journalisation, etc.),
  • mettez à niveau votre PHP vers la dernière ou plus récente branche,
  • recompilez votre PHP pour une architecture 64 bits ou supérieure selon votre CPU,
  • utiliser le périphérique de stockage plus rapide pour vos fichiers db ou tout l'environnement LAMP (par exemple SSD ou système de fichiers basé sur la mémoire ),
  • utilisez PHP débogueur ou profileur pour trouver tout goulot d'étranglement des performances (par exemple XDebug Profiler , DTrace ou NuSphere PhpED PHP Profiler ),
  • exécutez une commande drush qui prend du temps sous gprof outil de profilage, afin que vous puissiez également trouver un goulot d'étranglement des performances
5
kenorb

Utilisez le module Mongodb pour stocker les champs https://drupal.org/project/mongodb Résultats ici: selon http://cyrve.com/mongodb

1
giorgio79