WordPress 4.3でcronタスクが凄まじい量に肥大化、メモリを使いすぎる件の対応

WordPress4.3のバグ

こんにちは。はじめての寄稿になります。タロスカイで開発を行っている高橋です。

WordPress 4.3へのアップグレードに関する注意点です。弊社運営サイトのTENNIS.jp(マルチサイト)で、Internal Server Errorが頻発し、ほとんど機能しなくなるという問題が発生しました。

ソースコードはいじっていないので、当初はサーバを疑ったのですが、ログを見たり色々としているうちに、アプリケーション側の問題とわかりました。さくらインターネットさんには何度も問い合わせをしてしまい、申し訳なかったです。

バグの症状

さて、肝心の症状ですが、基本的には「サイトが重い」ということです。ロードアベレージも18ぐらいになって、まともにアクセスすらできません。memory_limitのエラーが出るときもあれば、そのままInternal Server Errorになることもあります。

Google Analyticsのリアルタイム解析を確認すると、見ている人は何人かいたので、サイト全体が完全に落ちている状態ではありませんでした。

解決までの道筋

ローカルの環境では再現しなかったため、データベース周りだろうと当たりをつけて色々調査しました。そもそも管理画面にアクセスできないのでWP CLIコマンドでプラグインをオン・オフしてみようかと wp help plugin と打ってみたところ、シリアライズされた配列がドワーっと表示されました。

なんじゃこりゃ! と驚いて、wp_optionsの cron テーブルを確認してみると、cronタスクが4MBぐらい登録されていました……

wp_optionsのcronはautoload=yes、つまり、毎回読み込まれるデータなので、すべてのアクセスにおいて4MBのデータを引き回していたことになります。このため、メモリの使用量が増大したわけですね。

そのcronデータが8/25から増えているので、社内を確認したところ、4.3へのアップデートをそれぐらいの日に行ったとのこと。タバコを吸いに行って戻ってくると、五十嵐くんが「WordPress 4.3 cron バグ」でのグーグリングを完了していました。

WordPress 4.3でメモリ消費量増大・CPU高負荷になる重大なバグあり。直し方を一応解説。 – enjoypclife.net

これで解決! いやー、焦りました。

バグの詳細

一応、バグの詳細です。WordPress 4.3へのアップグレードにおいて、以下のパッチが適用されました。おそらく、WordPressのタクソノミーの取り扱いが変更したことによるバッチ処理の登録ですね。

wp-includes/taxonomy.php


/**
 * In order to avoid the wp_batch_split_terms() job being accidentally removed,
 * check that it's still scheduled while we haven't finished splitting terms.
 *
 * @ignore
 * @since 4.3.0
 */
function _wp_check_for_scheduled_split_terms() {
    if ( ! get_option( 'finished_splitting_shared_terms' ) && ! wp_next_scheduled( 'wp_batch_split_terms' ) ) {
        wp_schedule_single_event( 'wp_batch_split_terms', time() + MINUTE_IN_SECONDS );
    }
}

上記はwp_schedule_single_eventの呼び出しにバグがあります。引数の順番が違うので、wp_next_scheduledの確認がtrueにならず、延々とタスクが登録されていきます。

このフックは管理画面へのアクセスで毎回生成されるので、Ajax(WordPressのAjaxエンドポイントは管理画面扱い)でなにかしていたりすると、すごいことになります。


add_action( 'admin_init', '_wp_check_for_scheduled_split_terms' );

この結果、アクセス数に応じてすごい数のCronが登録されていました。で、上記で紹介したブログ記事の修正方法は

  1. 引数の順番を正しく戻す
  2. すでに登録してしまったゴミデータを消去するためのパッチをmu-pluginsに登録する

というものです。mu-pluginsのファイルは必要なくなったら消去してしまってもいいでしょう。このバグに対する修正はすでに行われているようですが、リリースは4.3.1まで待たないといけませんね。高トラフィックサイト、投稿者が多いサイト、更新が頻繁なサイトは4.3.1までアップデートを見送った方がよいと思われます。

このバグへの感想

なぜこのバグが混入したかというと、色々理由はあると思いますが以下の2つですかね。

  • PHPは7以上じゃないと引数の型付けでintやstringなどを指定できない(もし指定できていれば、今回のミスは防げたはず)
  • cronの登録それ自体は成功してしまうので、量がかなり多くならないと問題が顕在化しない

WordPressのコアはユニットテストを適用しているのですが、「データが極度に多い」というケースに対応するのはユニットテストだと難しいですね。データベースがからむと結合テストが難しいとはよく言いますが、まさにこの問題が該当するケースなのではないでしょうか。

ちなみに、私の個人ブログは4.3にしても特に問題なかった(ゴミデータは存在していましたが)ので、レアケースともいえるでしょう。

 

というわけで、WordPressご利用の皆さん、お互い気を付けましょう。