Wie kann ich die Funktion node_save () von drupal beschleunigen?

9

Ich habe große Probleme mit der Ineffizienz von node_save (). Aber ist Node Save mein Problem? Das versuche ich letztendlich herauszufinden.

Ich habe eine Schleife mit 100.000 Iterationen erstellt. Ich habe das absolute Minimum für das Knotenobjekt erstellt, damit es gültig ist und korrekt gespeichert wird. Hier ist der Knotenspeichercode:

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

Hier sind die Ergebnisse:

100.000 Knoten wurden jeweils mit node_save () gespeichert. Die Fertigstellung dauerte 5196,22 Sekunden. Das sind NUR 19 spart eine Sekunde.

Zumindest ist dies nicht akzeptabel, insbesondere wenn diese Person ungefähr 1200 einzelne Einfügeabfragen pro Sekunde erhält und diese Person 25.000 Einfügungen pro Sekunde erhält .

Also, was ist hier los? Wo ist der Engpass? Ist es die mit der Funktion node_save () und wie ist sie aufgebaut?

Könnte es meine Hardware sein? Meine Hardware ist ein Entwicklungsserver, niemand außer mir - Intel Dual Core, 3 GHz, Ubuntu 12.04 mit 16 GB RAM.

Während die Schleife ausgeführt wird, ist meine Ressourcennutzung: MySQL 27% CPU, 6 MB RAM; PHP 22% CPU 2M RAM.

Meine MySQL-Konfiguration wurde vom Percona-Assistenten durchgeführt .

MySQL sagt, dass mein Problem festplattengebunden ist , wenn meine CPU-Auslastung unter 70% liegt . Zugegeben, ich habe nur eine WD Caviar 7200 U / min, aber ich hoffe, ich sollte mehr als 19 Einsätze pro Sekunde damit bekommen!

Vor nicht allzu langer Zeit habe ich über das Speichern von 30.000 Knoten an einem Tag geschrieben . Um klar zu sein, hat dieser Knoten jedoch nichts mit externen Kräften zu tun. Es ist lediglich ein Benchmark, um zu erfahren, wie Sie die Geschwindigkeit von Aufrufen von node_save () erhöhen können.

Realistisch gesehen muss ich mit node_save jede Minute 30.000 Elemente in die Datenbank aufnehmen. Wenn das Speichern von Knoten keine Option ist, frage ich mich, ob ich meine eigene Drupal-API-Funktion "node_batch_save ()" schreiben kann oder etwas, das die Fähigkeit von mysql nutzt, Masseneinfügungen mit der INSERT-Abfrage durchzuführen . Gedanken darüber, wie man das angeht?

blue928
quelle
2
Es gibt einen großen Unterschied zwischen der Leistung der rohen Einfügung und der Leistung von node_save. Zum einen führt node_save eine Reihe von Lese- und Schreibvorgängen durch. Es macht jedoch keinen Sinn, mögliche Engpässe und Optimierungen ohne weitere Daten zu diskutieren.
Alfred Armstrong
Sie müssen überlegen, warum Sie Drupal auf diese Weise für Ihre Zwecke verwenden. Wenn Sie einfach viele Daten in einer flachen Tabelle erfassen und mit Drupal anzeigen möchten, können Sie Drupal beim Schreiben vollständig umgehen und ein benutzerdefiniertes Modul verwenden, um die Daten mithilfe von Ansichten usw. zu integrieren.
Alfred Armstrong
Ich bezweifle, dass der Flaschenhals auf der Datenbankseite liegt. Das Speichern von Knoten führt viele Dinge im Hintergrund aus: Es ruft eine Reihe von Hooks auf (hook_node_presave, hook_entity_presave, hook_node_insert, hook_entity_insert usw.), von denen jedes eine beliebige Anzahl von Modulen aufrufen kann. Zusätzlich wird node_save die Berechtigungen für diesen Knoten neu erstellen und den Cache für diesen Knoten leeren ...
Alice Heaton
@AlfredArmstrong Ich erstelle Knoten basierend auf Daten, die sich in einer anderen Datenbank befinden. Ich forme die Daten auf den richtigen Drupal-Inhaltstyp und speichere sie. Meine Kunden sind hauptsächlich Universitäten, die zu Drupal wechseln möchten. Es ist nicht ungewöhnlich, dass sie zwischen 200.000 und 1.000.000 Knoten (Site-Inhalte der Abteilungen, Aufzeichnungen von Studenten und Fakultäten usw.) haben, über die sie nach einem Jahrzehnt der Verwendung ihrer eigenen Weblösung migrieren möchten. Ich habe dies gelesen, was ermutigend, aber immer noch weniger als wünschenswert ist. evolvingweb.ca/story/...
blue928
.. also würde ich lieber so drupal wie möglich bleiben. Die Verwendung von Node Save mit so vielen Daten stellt die Integrität sicher. Wenn ich das nicht zum Laufen bringen kann, bin ich bereit, kreativ zu werden.
blue928

Antworten:

10

Mit node_save erhalten Sie niemals 30.000 Einfügungen pro Minute. Auf keinen Fall.

Ein INSERT ist schnell, weil das alles ist, was es tut. Das Speichern von Knoten führt mehrere Einfügungen durch (Haupttabelle, Revisionstabelle, eine Tabelle für jedes Feld), löscht alle Entitätscaches und löst Hooks aus. Die Haken sind der schwierige Teil. Wenn Sie viele Contrib-Module haben (oder sogar eines, das sich schlecht verhält), die die Leistung wirklich beeinträchtigen können, insbesondere wenn der Autor den Anwendungsfall "Ich speichere eine Menge Knoten auf einmal" nicht berücksichtigt hat. Zum Beispiel musste ich dies meiner Migrate-Klasse hinzufügen:

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

Wenn Sie dagegen eine benutzerdefinierte Speicherfunktion schreiben, die keine Hooks aufruft, besteht eindeutig die Gefahr, dass inkonsistente Daten in einem vom System unerwarteten Zustand abgerufen werden. Ich würde das niemals empfehlen. Starten Sie xhprof und sehen Sie, was passiert.

Bojan Zivanovic
quelle
Einige der Migrationsmodule da draußen, wie kommen sie zu Bulk-Save-Knoten? Ich meine, am Ende läuft alles auf eine INSERT-Anweisung hinaus, oder? Wie fügt Ihre Migrationsklasse letztendlich von 'Quelle' zu 'Ziel' ein, wenn Sie nicht Node Save verwenden, aber dennoch die Datenintegrität über Tabellen hinweg aufrechterhalten müssen?
blue928
Alle Migrationsmodule, auf die ich gestoßen bin, verwenden einen node_save.
Alfred Armstrong
1
@ blue928 Er sagt , er tut Gebrauch node_save(), aber einige Code fügt bekannte Probleme zu mildern, die wie Pathauto Wiederaufbau des Menü - Cache nach jedem Knoten speichern verursacht werden können
Clive
Ah, ok, ich verstehe. Bojan ist Ihr Code in einem Modul oder online verfügbar, wo ich sehen konnte, wie Sie mit Engpässen wie path auto umgegangen sind? Gute Idee mit dem xhprof. Ich werde das überprüfen.
blue928
5

Installieren Sie zunächst XCache / APC (für PHP <5.5) und konfigurieren Sie memcached für Drupal.

Anschließend können Sie Ihre MySQL-Konfiguration für umfangreiche Abfragen optimieren, indem Sie das Skript mysqltuner verwenden, das unter folgender Adresse verfügbar ist: http://mysqltuner.pl

Z.B

# 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

Weitere Vorschläge:

  • Deaktivieren Sie Module, die Sie nicht benötigen (z. B. Devel , Core Database Logging-Modul usw.).
  • Aktualisieren Sie Ihr PHP auf den neuesten oder höheren Zweig.
  • Kompilieren Sie Ihr PHP für eine 64-Bit- oder höhere Architektur neu, abhängig von Ihrer CPU.
  • Verwenden Sie das schnellere Speichergerät für Ihre Datenbankdateien oder die gesamte LAMP-Umgebung (z. B. SSD oder speicherbasiertes Dateisystem ).
  • Verwenden Sie den PHP-Debugger oder -Profiler, um einen Leistungsengpass herauszufinden (z. B. XDebug Profiler , DTrace oder NuSphere PhpED PHP Profiler ).
  • Führen Sie einen zeitaufwändigen Drush-Befehl unter dem gprof- Profiling-Tool aus, damit Sie auch einen Leistungsengpass feststellen können
Kenorb
quelle
1
Das Optimieren von MySQL scheint einen großen Unterschied zu machen. Ich ging von ungefähr 80 node_saves pro Minute auf ungefähr 700, indem ich den Tipps von mysqltuner.pl folgte.
John McCollum