Come posso velocizzare la funzione node_save () di drupal?


9

Sto riscontrando molti problemi con l'inefficienza di node_save (). Ma il nodo salva il mio problema? Questo è in definitiva quello che sto cercando di scoprire.

Ho creato un ciclo con 100.000 iterazioni. Ho creato il minimo indispensabile affinché l'oggetto nodo sia valido e salvato correttamente. Ecco il codice di salvataggio del nodo:

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

Ecco i risultati:

Sono stati salvati 100.000 nodi, ognuno usando node_save (). Per completare sono stati necessari 5196,22 secondi. Ciò significa che SOLO 19 risparmia un secondo.

Per non dire altro, ciò non è accettabile, soprattutto quando questa persona riceve circa 1200 query di inserimenti individuali al secondo e questa persona riceve 25.000 inserimenti al secondo .

Allora, cosa sta succedendo qui? Dov'è il collo di bottiglia? È con la funzione node_save () e come è progettata?

Potrebbe essere il mio hardware? Il mio hardware è un server di sviluppo, nessuno tranne me: Intel dual core, 3Ghz, Ubuntu 12.04 con 16 GB di RAM.

Mentre il ciclo esegue il mio utilizzo delle risorse è: MySQL 27% CPU, 6M RAM; PHP 22% CPU 2M RAM.

La mia configurazione mysql è stata fatta dal mago percona .

Mysql afferma che se il mio utilizzo della CPU è inferiore al 70%, il mio problema è legato al disco . Certo, ho solo una corsa del mulino WD Caviar 7200 RPM, ma dovrei ottenere più di 19 inserti al secondo con esso spero!

Non molto tempo fa ho scritto sul salvataggio di 30.000 nodi in un giorno . Tuttavia, per essere chiari, questo nodo non ha nulla a che fare con alcuna forza esterna. È puramente un punto di riferimento per sapere come aumentare la velocità delle chiamate a node_save ().

Realisticamente, ho bisogno di ottenere 30.000 elementi nel database ogni minuto usando node_save. Se il salvataggio del nodo non è un'opzione, mi chiedo se posso scrivere la mia funzione di API drupal "node_batch_save ()" o qualcosa che sfrutti la capacità di mysql di fare inserimenti di massa con la query INSERT . Pensi su come affrontare questo?


2
C'è una grande differenza tra le prestazioni degli inserti non elaborati e ciò che farà node_save. Per prima cosa, node_save esegue una serie di letture e scritture. Ma non ha senso discutere possibili colli di bottiglia e ottimizzazioni senza ulteriori dati.
Alfred Armstrong,

Devi considerare perché stai usando Drupal in questo modo per i tuoi scopi. Se vuoi semplicemente acquisire molti dati in una tabella piatta e visualizzarli utilizzando Drupal, potresti voler bypassare Drupal del tutto durante la scrittura e utilizzare un modulo personalizzato per integrare i dati utilizzando Views ecc.
Alfred Armstrong

Dubito che il collo della bottiglia sia sul lato del database. Il salvataggio dei nodi fa molte cose in background: invocherà un numero di hook (hook_node_presave, hook_entity_presave, hook_node_insert, hook_entity_insert, ecc.), Ognuno dei quali potrebbe chiamare un numero qualsiasi di moduli. Inoltre node_save ricostruirà le autorizzazioni per quel nodo e cancellerà la cache per quel nodo ...
Alice Heaton,

@AlfredArmstrong Sto creando nodi basati su dati presenti in un altro database. Stampo i dati sul tipo di contenuto drupal corretto e node_save. I miei clienti sono principalmente università che vogliono passare a Drupal. Non è raro che abbiano tra i 200.000 e i 1.000.000 di nodi (contenuti del sito dei depositi, registri degli studenti e delle facoltà, ecc.) Su cui vorrebbero migrare dopo un decennio di utilizzo della propria soluzione web. Ho letto questo, che è un approccio incoraggiante, ma ancora meno desiderabile. evolvingweb.ca/story/…
blue928

.. quindi, preferirei rimanere il più drupicamente possibile. L'uso del salvataggio del nodo con così tanti dati garantisce l'integrità. Se non riesco a farlo funzionare, sono disposto a diventare creativo.
blue928

Risposte:


10

Non otterrai mai 30.000 inserti al minuto usando node_save. Non c'è modo.

Un INSERT è veloce perché è tutto ciò che fa. Il salvataggio del nodo esegue più inserimenti (tabella principale, tabella di revisione, una tabella per ciascun campo), cancella tutte le cache delle entità e attiva gli hook. I ganci sono la parte difficile. Se hai molti moduli contrib (o anche uno che si comporta male) che possono davvero uccidere le prestazioni, specialmente se l'autore non ha tenuto conto del caso d'uso "Sto salvando una tonnellata di nodi contemporaneamente". Ad esempio, ho dovuto aggiungere questo alla mia 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'altra parte, se si scrive una funzione di salvataggio personalizzata che non richiama hook, si corre chiaramente il rischio di ottenere dati incoerenti, in uno stato inatteso dal sistema. Non consiglierei mai di farlo. Accendi xhprof e guarda cosa sta succedendo.


Alcuni dei moduli di migrazione là fuori, come fanno a finire i nodi di salvataggio in blocco? Voglio dire, alla fine, tutto si riduce a un'istruzione INSERT, giusto? In che modo la classe di migrazione alla fine si inserisce da "origine" a "destinazione" quando non si utilizza il salvataggio del nodo ma è ancora necessario mantenere l'integrità dei dati tra le tabelle?
blue928

Tutti i moduli di migrazione che ho incontrato usano un node_save.
Alfred Armstrong,

1
@ blue928 Sta dicendo che fa uso node_save(), ma aggiunge un po 'di codice per mitigare i problemi noti che possono essere causati, come Pathauto ricostruire la cache menu dopo ogni nodo Salva
Clive

ah, ok, capisco. Bojan è il tuo codice disponibile in un modulo o online dove ho potuto vedere come hai gestito i colli di bottiglia come il percorso automatico? Buona idea con l'xhprof. Ci penso io.
blue928

5

Prima di tutto, installa XCache / APC (per PHP <5.5) e configura memcached per Drupal.

Quindi è possibile ottimizzare la configurazione di MySQL per query pesanti utilizzando lo script mysqltuner disponibile su: http://mysqltuner.pl

Per esempio

# 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

Altri suggerimenti:

  • disabilitare i moduli non necessari (ad es. Devel , modulo di registrazione del database principale, ecc.),
  • aggiorna il tuo PHP alla filiale più recente o superiore,
  • ricompilare il PHP per un'architettura a 64 bit o superiore a seconda della CPU,
  • utilizzare il dispositivo di archiviazione più veloce per i tuoi file db o l'intero ambiente LAMP (ad esempio SSD o filesystem basato sulla memoria ),
  • utilizzare il debugger o il profiler PHP per scoprire eventuali colli di bottiglia delle prestazioni (ad esempio XDebug Profiler , DTrace o NuSphere PhpED PHP Profiler ),
  • eseguire alcuni comandi drush che richiedono tempo con lo strumento di profilazione gprof , in modo da poter trovare anche alcuni colli di bottiglia delle prestazioni

1
L'ottimizzazione di MySQL sembra fare la differenza. Sono passato da circa 80 node_saves al minuto a circa 700 solo seguendo i suggerimenti forniti da mysqltuner.pl.
John McCollum,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.