drupalのnode_save()関数を高速化するにはどうすればよいですか?


9

node_save()の非効率性に多くの問題を抱えています。しかし、ノードは私の問題を保存していますか?それが最終的に私が調べようとしていることです。

100,000回の繰り返しでループを作成しました。ノードオブジェクトが有効で正しく保存されるための最低限の条件を作成しました。ノードの保存コードは次のとおりです。

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

結果は次のとおりです。

それぞれnode_save()を使用して、100,000のノードが保存されました。完了するまで5196.22秒かかりました。それは19秒だけを節約します。

控えめに言っても、これは受け入れられません。特に、この人物が毎秒約1200の個別の挿入クエリを取得しており、この人物が毎秒25,000の挿入を取得している場合はなおさらです。

それで、ここで何が起こっているのですか?ボトルネックはどこですか?それはnode_save()関数であり、どのように設計されていますか?

それは私のハードウェアでしょうか?私のハードウェアは開発サーバーで、私以外は誰もいません-Intelデュアルコア、3 GHz、16 GBのRAMを搭載したUbuntu 12.04。

ループの実行中の私のリソース使用量は次のとおりです。MySQL27%CPU、6M RAM。PHP 22%CPU 2M RAM。

私のmysql設定はperconaウィザードによって行われました。

Mysqlによると、CPU使用率が70%未満の場合、問題はディスクにバインドされているということです。確かに、私は工場のWD Caviar 7200 RPMしか実行していませんが、1秒あたり19以上の挿入が得られるはずです。

少し前に、1日に30,000ノードを節約することについて書きました。ただし、明確にするために、このノードは外力とは何の関係もありません。これは、node_save()への呼び出しの速度を上げる方法を学ぶための純粋なベンチマークです。

現実的には、node_saveを使用して毎分30,000項目をデータベースに取得する必要があります。ノードの保存がオプションでない場合、独自のdrupal api関数「node_batch_save()」またはINSERTクエリで一括挿入を実行するmysqlの機能を利用する何かを記述できるかどうか疑問に思います。これにアプローチする方法についての考え?


2
生の挿入のパフォーマンスとnode_saveの動作には大きな違いがあります。1つには、node_saveは一連の読み取りと書き込みを実行します。しかし、データがなければ、ボトルネックと最適化の可能性について議論する意味がありません。
アルフレッドアームストロング

目的のためにこの方法でDrupalを使用する理由を考慮する必要があります。あなたは、単に平らなテーブルに大量のデータをキャプチャし、Drupalのを使用して、それを表示したい場合、あなたはそれを書くときに完全にバイパスのDrupalにしたいとビューなどを使用してデータを統合するカスタムモジュールを使用することができます
アルフレッド・アームストロング

ボトルネックがデータベース側にあるとは思えません。ノードの保存はバックグラウンドで多くのことを実行します。それはいくつかのフック(hook_node_presave、hook_entity_presave、hook_node_insert、hook_entity_insertなど)を呼び出し、それぞれが任意の数のモジュールを呼び出す可能性があります。さらに、node_saveはそのノードの権限を再構築し、そのノードのキャッシュをクリアします...
Alice Heaton

@AlfredArmstrong別のデータベースにあるデータに基づいてノードを作成しています。データを正しいdrupalコンテンツタイプに成形し、node_saveします。私のクライアントは主にドルーパルに切り替えたい大学です。20万から1,000,000のノード(学部のサイトコンテンツ、学生や教職員のレコードなど)を所有することは、Webソリューションで独自のノードを10年間使用した後に移行することも珍しくありません。私はこれを読みました。これは励みになりますが、それでも望ましいアプローチとは言えません。evolvingweb.ca/story/...
blue928

..だから、私はできる限り無茶苦茶にとどまることを望みます。これだけのデータでノード保存を使用すると、整合性が保証されます。それがうまくいかない場合は、私はクリエイティブになりたいと思っています。
blue928 2013

回答:


10

node_saveを使用すると、1分間に30 000挿入されることはありません。ありえない。

INSERTはそれだけなので高速です。ノードの保存は複数の挿入(メインテーブル、リビジョンテーブル、各フィールドのテーブル)を実行し、エンティティキャッシュをクリアして、フックを起動します。フックはトリッキーな部分です。多くのcontribモジュール(または正しく動作しないもの)があり、特に作成者が「大量のノードを一度に保存する」ユースケースを考慮していなかった場合、パフォーマンスが大幅に低下する可能性があります。たとえば、これを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);
  }

一方、フックを呼び出さないカスタム保存関数を作成すると、システムが予期しない状態で、一貫性のないデータを取得する危険が明らかにあります。私はそれをすることを決して勧めません。xhprofを起動して、何が起こっているかを確認します。


そこにある移行モジュールのいくつかは、ノードをどのように一括保存するのですか?つまり、結局のところ、すべてをまとめるとINSERTステートメントになりますよね?ノードの保存を使用せずに、テーブル間でデータの整合性を維持する必要がある場合、移行クラスは最終的に「ソース」から「ターゲット」にどのように挿入しますか?
blue928 2013

私が遭遇したすべての移行モジュールは、node_saveを使用します。
アルフレッドアームストロング

1
@ blue928彼はを使用していると言ってますがnode_save()、Pathautoが各ノードの保存後にメニューキャッシュを再構築するなど、発生する可能性がある既知の問題を軽減するためのコードを追加します
Clive

ああ、わかりました。Bojanは、コードがモジュールまたはオンラインで利用できるので、パス自動などのボトルネックにどのように対処したかを確認できます。xhprofの良いアイデア。確認します。
blue928 2013

5

まず、XCache / APC(PHP <5.5の場合)をインストールし、Drupal用にmemcachedを構成します。

次に、http://mysqltuner.plにあるmysqltunerスクリプトを使用して、重いクエリ用にMySQL設定を最適化できます

例えば

# 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

その他の提案:

  • 不要なモジュールを無効にします(例:Devel、コアデータベースロギングモジュールなど)。
  • PHPを最新またはそれ以上のブランチにアップグレードし、
  • CPUに応じて、64ビット以上のアーキテクチャ用にPHPを再コンパイルします。
  • dbファイルまたはLAMP環境全体(SSDまたはメモリベースのファイルシステムなど)には、より高速なストレージデバイスを使用します。
  • PHPデバッガーまたはプロファイラーを使用して、パフォーマンスのボトルネック(XDebugプロファイラーDTraceNuSphere PhpED PHPプロファイラーなど)を見つけます
  • gprofプロファイリングツールで時間のかかるdrushコマンドを実行して、パフォーマンスのボトルネックも見つけることができます

1
MySQLのチューニングは大きな違いをもたらすようです。mysqltuner.plによって提供されたヒントに従うだけで、1分あたり約80のnode_savesから約700になりました。
ジョン

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.