Bagaimana saya bisa mempercepat fungsi node_save () drupal?

9

Saya mengalami banyak masalah dengan inefisiensi node_save (). Tetapi apakah simpul menyelamatkan masalah saya? Pada akhirnya itulah yang saya coba cari tahu.

Saya membuat satu lingkaran dengan 100.000 iterasi. Saya membuat minimum untuk objek node agar valid dan menyimpan dengan benar. Inilah node save code:

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

Inilah hasilnya:

100.000 node disimpan, masing-masing menggunakan node_save (). Butuh 5196,22 detik untuk selesai. HANYA 19 menghemat satu detik.

Untuk sedikitnya, itu tidak dapat diterima, terutama ketika orang ini mendapatkan sekitar 1.200 permintaan memasukkan per detik , dan orang ini mendapatkan 25.000 sisipan per detik .

Jadi, apa yang terjadi di sini? Dimana kemacetannya? Apakah ini dengan fungsi node_save () dan bagaimana ia dirancang?

Mungkinkah itu perangkat keras saya? Perangkat keras saya adalah server pengembangan, tidak ada seorang pun di atasnya kecuali saya - Intel dual core, 3Ghz, Ubuntu 12,04 dengan 16 gigs of ram.

Sedangkan loop menjalankan penggunaan sumber daya saya adalah: MySQL 27% CPU, 6M RAM; PHP 22% CPU 2M RAM.

Konfigurasi mysql saya dilakukan oleh wizard percona .

Mysql mengatakan bahwa jika penggunaan CPU saya di bawah 70% masalah saya adalah disk terikat . Memang, saya hanya memiliki menjalankan pabrik WD Caviar 7200 RPM, tapi saya harus mendapatkan lebih dari 19 sisipan sebentar dengan itu saya harap!

Belum lama ini saya menulis tentang menghemat 30.000 node dalam sehari . Namun, untuk menjadi jelas, simpul ini tidak ada hubungannya dengan kekuatan eksternal apa pun. Ini murni patokan untuk mempelajari tentang cara meningkatkan kecepatan panggilan ke node_save ().

Secara realistis, saya perlu memasukkan 30.000 item ke dalam basis data setiap menit menggunakan node_save. Jika simpanan simpul bukan opsi, saya ingin tahu apakah saya dapat menulis fungsi api drupal saya sendiri "node_batch_save ()" atau sesuatu yang memanfaatkan kemampuan mysql untuk melakukan penyisipan massal dengan permintaan INSERT . Pikiran tentang bagaimana mendekati ini?

blue928
sumber
2
Ada perbedaan besar antara kinerja penyisipan mentah dan apa yang akan dilakukan node_save. Untuk satu hal node_save melakukan serangkaian proses baca dan tulis. Tapi tidak ada gunanya membahas kemungkinan kemacetan dan optimisasi tanpa lebih banyak data.
Alfred Armstrong
Anda perlu mempertimbangkan mengapa Anda menggunakan Drupal dengan cara ini untuk tujuan Anda. Jika Anda hanya ingin menangkap banyak data dalam tabel datar dan menampilkannya menggunakan Drupal, Anda mungkin ingin mem-bypass Drupal sama sekali saat menulis dan menggunakan modul khusus untuk mengintegrasikan data menggunakan Tampilan dll.
Alfred Armstrong
Saya ragu leher botol ada di sisi basis data. Node save melakukan banyak hal di latar belakang: ia akan memanggil sejumlah kait (hook_node_presave, hook_entity_presave, hook_node_insert, hook_entity_insert, dll.), Yang masing-masing dapat memanggil sejumlah modul. Selain itu node_save akan membangun kembali izin untuk simpul itu dan itu akan menghapus cache untuk simpul itu ...
Alice Heaton
@AlfredArmstrong Saya membuat node berdasarkan data yang ada di database lain. Saya mencetak data ke tipe konten drupal yang benar dan node_save. Klien saya terutama universitas yang ingin beralih ke drupal. Ini tidak biasa bagi mereka untuk memiliki antara 200.000 dan 1.000.000 node (isi situs depts, catatan mahasiswa dan fakultas, dll) mereka ingin bermigrasi setelah satu dekade menggunakan mereka sendiri dalam solusi web. Saya membaca ini, yang menggembirakan, tetapi masih kurang dari pendekatan yang diinginkan. evolvingweb.ca/story/…
blue928
.. jadi, saya lebih suka untuk tetap setinggi mungkin. Menggunakan node save dengan data sebanyak ini memastikan integritas. Jika saya tidak bisa melakukannya, saya bersedia untuk menjadi kreatif.
blue928

Jawaban:

10

Anda tidak akan pernah mendapatkan 30.000 sisipan satu menit menggunakan node_save. Tidak mungkin.

INSERT cepat karena hanya itu yang dilakukannya. Node save tidak memasukkan banyak (tabel utama, tabel revisi, tabel untuk setiap bidang), membersihkan semua cache entitas, dan menembakkan kait. Kait adalah bagian yang sulit. Jika Anda memiliki banyak modul contrib (atau bahkan modul yang bertingkah buruk) yang benar-benar dapat mematikan kinerja, terutama jika pembuatnya tidak menjelaskan kasus penggunaan "Saya menghemat satu ton node sekaligus". Misalnya, saya harus menambahkan ini ke kelas Migrasi saya:

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

Di sisi lain, jika Anda menulis fungsi simpan kustom yang tidak meminta kait, Anda jelas berisiko mendapatkan data yang tidak konsisten, dalam keadaan yang tidak terduga oleh sistem. Saya tidak akan merekomendasikan melakukan itu. Jalankan xhprof dan lihat apa yang terjadi.

Bojan Zivanovic
sumber
Beberapa modul migrasi di luar sana, bagaimana mereka berakhir pada node penghematan massal? Maksud saya, pada akhirnya, semuanya bermuara pada pernyataan INSERT, kan? Bagaimana kelas migrasi Anda akhirnya memasukkan dari 'sumber' ke 'target' saat tidak menggunakan simpanan simpul tetapi masih perlu mempertahankan integritas data di seluruh tabel?
blue928
Semua modul migrasi yang saya temui menggunakan node_save.
Alfred Armstrong
1
@ blue928 Dia mengatakan dia memang menggunakan node_save(), tetapi menambahkan beberapa kode untuk mengurangi masalah yang diketahui yang dapat disebabkan, seperti Pathauto membangun kembali cache menu setelah setiap node menyimpan
Clive
ah, baiklah. Bojan adalah kode Anda tersedia dalam modul atau online di mana saya bisa melihat bagaimana Anda telah berurusan dengan kemacetan seperti jalur otomatis? Ide bagus dengan xhprof. Saya akan memeriksanya.
blue928
5

Pertama-tama, instal XCache / APC (untuk PHP <5.5) dan konfigurasikan memcached untuk Drupal.

Kemudian Anda dapat mengoptimalkan konfigurasi MySQL Anda untuk pertanyaan berat dengan menggunakan skrip mysqltuner yang tersedia di: http://mysqltuner.pl

Misalnya

# 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

Saran lain:

  • nonaktifkan modul yang tidak Anda perlukan (mis. Devel , modul Logging Database inti, dll.),
  • tingkatkan PHP Anda ke cabang terbaru atau lebih tinggi,
  • mengkompilasi ulang PHP Anda untuk arsitektur 64-bit atau lebih tinggi tergantung pada CPU Anda,
  • gunakan perangkat penyimpanan yang lebih cepat untuk file db Anda atau seluruh lingkungan LAMP (mis. SSD atau sistem file berbasis memori ),
  • gunakan debugger atau profiler PHP untuk mengetahui hambatan kinerja (misalnya XDebug Profiler , DTrace atau NuSphere PhpED PHP Profiler ),
  • menjalankan beberapa perintah drush yang menghabiskan waktu di bawah alat profiling gprof , sehingga Anda dapat menemukan beberapa hambatan kinerja juga
kenorb
sumber
1
Tuning MySQL tampaknya membuat perbedaan besar. Saya beralih dari sekitar 80 node_save satu menit menjadi sekitar 700 hanya dengan mengikuti tips yang diberikan oleh mysqltuner.pl.
John McCollum