先日からapcuと戯れていましたが、とは言えもうちょっと速くならないかなぁと調整してみました。多分、いい感じになったと思います。
200msの壁
「200ms」とは、Google PageSpeed Insightsが「サーバーが高速に応答している」と判断する閾値で、一般にWebサーバーの応答は200ms以下というのが、一つの目標のデファクトになっている、と、私は勝手に思っています。
たかが200ms、されど200ms。Wordpressでいろいろやっても200msってのはなかなか出ないです。あ、でも、簡単に出す方法もあります。ページキャッシュ。これをやってしまえばおしまい。なんですが、ページキャッシュ系のプラグインは更新が反映されない等のトラブルが良くあるのもご承知の通り。CDNもトラブルと厄介なので(経験者は語る)使いたくないと。そんなわけで、Wordpress単体で、なんとか高速化できないか、というのが昨今の課題です。
ちなみに、ページキャッシュは嫌ってるけど、オブジェクトキャッシュは使ってるんですが。
トップページの応答時間はnginxのログで見るとだいたい200ms前後。これをもう一回り高速化したい、というのが目標です。
straceで分析
現在、このブログサーバーはphp7で動いており、以前使っていたNewRelicのAgentが使えなくなっています。NewRelicのAPCでは、PHPスクリプトの処理内容の時間分布が見えて便利だったんですが、今は見えません。でも、PHP5で動かしていた当時、見ていた感触として、DB時間はほぼ応答に関係無く、PHP本体の処理時間が殆どであることが分かっています。
じゃぁそのPHPの処理の中で、何が遅いのかを分析するのですが、今回は(個人的には「最後の手段」だと思っている)straceを使いました。straceとは、プロセス・スレッド単位でシステムコールの発行内容を出力してくれるツールです。例えばファイルIOが多いとか、どこかと通信しているとかは、これを使えば一発で分かります。
php-fpmのworkerプロセスを一つ捕まえて、curlでトップページへのリクエストを繰り返して、処理内容をダンプさせてみました。
# strace -r -p 21006
こんな感じ。
分析結果:山のようなファイルアクセス
結論から言うと、すごい数のファイルを読み込もうとしていることが分かりました。読み込んでいるわけではなく、statをかけまくっている。
0.000064 gettimeofday({1456757344, 636908}, NULL) = 0 0.000024 lstat("/var/www/html/wordpress/wp-blog-header.php", {st_mode=S_IFREG|0644, st_size=271, ...}) = 0 0.000033 stat("/var/www/html/wordpress/wp-blog-header.php", {st_mode=S_IFREG|0644, st_size=271, ...}) = 0 0.000038 stat("/var/www/html/wordpress/wp-load.php", {st_mode=S_IFREG|0644, st_size=3316, ...}) = 0 0.000069 access("/var/www/html/wordpress/wp-config.php", F_OK) = 0 0.000038 stat("/var/www/html/wordpress/wp-config.php", {st_mode=S_IFREG|0644, st_size=4805, ...}) = 0
こんな感じで、大量のphpスクリプトにaccess/statをかけまくっています。なるほど、WordpressはSSD等速いストレージで動かすと速いと言われるる理由が分かりました。大量のスクリプトファイルにアクセスするからなんですね。また、プラグインも大量にファイルアクセスを引き起こしていることが分かりました。
これを改善すれば、高速化できそうです。
・・・あ、元も子もないことを言いますと、これを避ける最も簡単な手段は、キャッシュ系プラグインです・・・って、そこの裏も取れた(苦笑)。
対策案を考える。
じゃぁ、どうやって高速化するか。
その1。高速なファイル・システムにする。accessではなく、statを掛けたがっているので、metaデータアクセスの速いファイルシステムやRAMDISKに、wp-includes等、読み込まれるphpファイルを配置する、ということを考えた訳ですが、どう考えても既に殆どがファイル・システムのキャッシュに載っていると想定されるため、これは見込み薄かなぁ、と思いました。
その2。ファイルをキャッシュするプラグインを使う。apcuのオブジェクトキャッシュを見ていると、実際載っているのはDBオブジェクトばかりで、ファイルは載っていません。ファイルを読み込んでおくプラグインとか無いんだけっけ、と調べたのですが、見当たらない。うーん。
その3。プラグインを外す。端的に言って、全体の半分以上がjetpackプラグインファイルへのアクセスでしたので、これを切ってみたらどうか、と思った。jetpackは便利なんですが、いかんせん、プラグイン自体が巨大過ぎる、という。
と、ここで、はたと気づく。
これだけstatしてるって、なんだろう、と考えてみたら、そう、opcacheがスクリプトファイルの更新確認をしてるんです(いや、すぐ気づくだろ、普通)。じゃぁ、opcacheに「チェックすんな」って言えば良いじゃん、ってこと。
その4。opcacheのファイルチェック間隔の調整。
という訳で、プラグイン外しとopcacheのパラメータ調整で、性能改善にトライしてみました。
Jetpackプラグインを停止してみた
まずは、変更前。staceで一回のリクエストで発生したログをファイルに落として、stat(lstat含む)の数を数えてみると、結果「695回」という値になっていました。一回一回のstatなんて1msにも満たない時間なんですが、数が多ければ馬鹿になりません。このうち、Jetpackに関連するファイル・フォルダへのstatが「354回」です。
という訳で、Jetpackプラグインを「停止」して、再度アクセスしてみました。
結果、stat件数は「34回」まで激減しました(苦笑)。
要するに、Jetpackプラグインから呼ばれている関連するスクリプトファイルへのアクセスも多数あったということのようです。この段階で、応答時間は100ms程度まで改善しました。やはりstat回数を減らすのが効果は高いです。
opcacheパラメータ調整してみた
端的に言って、こっからが本命です。opcacheの、スクリプトファイルチェックの周期を見てみると、なんとデフォルトは「2秒」になっています。つまり、2秒おきに、ファイル更新チェックする。まぁ戦略として悪い数字ではないような気もしますが(2秒で数百件とかアクセスされるサイトでは、こういう数字でも全く意味がありますから)、ウチのブログではもっと長くて良いです。
という訳で、7200秒にしてみた。こうなってしまうと、もうモジュールアップデート時とか、php-fpm再起動は必須なんですが、そこは気にしない。
;opcache.revalidate_freq=2 opcache.revalidate_freq=7200
php-fpmを再起動して、再度アクセス試験してみると、stat件数は「16回」まで減少しました。Jetpackを戻しても「21回」です。opcacheの動作からすれば、当たり前といえば当たり前なんですが、素晴らしい。当然、応答時間も100ms程度に落ち着いています。
という訳で、結論から言うと、Wordpressはopcacheを正しく設定すると、アクセス性能がとても上がります、ということです。
さらに微調整。
じゃぁ、何がファイルアクセスとして残ったかというと、moファイル(翻訳ファイル)です。これが曲者で、「001 Prime Strategy Translate Accelerator」は試したことがあるんですが、ウチの環境ではうまくキャッシュで翻訳できないんですよね。PHP7が悪いのか、プラグインが最新のWordpressに対応していないのかは分かりません。
また、ついでの改善として、不要なテーマファイルをすべて捨てました。straceの結果の中で、テーマフォルダを舐める処理も見受けられて、ちょっと気になったので、片付けてみたと。これはきっと性能には寄与するほどではないですがね。
結論
WordPressはページを表示するのに、大量のスクリプトファイルにアクセスします。なのでキャッシュ系プラグインが有効なんですが、それは「処理をさせない」という意味での高速化です。
処理をさせる前提での高速化手法としては、opcacheのバイトコンパイルを有効に活用すれば良いのですが、デフォルト設定ではスクリプトファイルの更新チェックが頻繁過ぎて、性能が落ちてしまいます。なので、スクリプトファイルの更新チェック間隔を伸ばす設定が非常に有効です。これはphpのopcacheのパラメータ設定で対策が可能です。もちろん、スクリプト修正時は、キャッシュのパージやphp-fpmの再起動が必要になります。
念のため、ここで「性能が落ちる」と言っているのは、あくまで200ms未満を目指すようなケースの話です。こんなことをしなくても、一般的なサイトとして「遅い」と感じるようなレベルにはなりません。
一方で、1秒未満で数十msの応答速度でオーガニックサーチの流量勝負をしている人や、性能測定サイトのスコアにチャレンジしている人には結構これは重要だったりするかなぁ、と思います。
あと、こういう性能解析って、最後はやっぱり、プリミティブなところに行くんだなぁって、改めて感じました。
コメント