WordPress高速化手法を検証してみる

前回の記事

WordPressをサクっと500倍高速化する
Ubuntuで作る高速WordPress運用環境のまとめ

でWordpressの高速化を扱いましたが、まだ色々検証することがあるなと思ったので書いてみます。

その他のサーバ側最適化

前回はサーバ側処理の最適化に注目しました。前回の結論は、「Nginx + FastCGIキャッシュ + PHP7で十分」というものでしたが、ここをもう少し検証してみたいと思います。

色々ググってみると、キャッシュの導入と同時にMySQLやHHVMを導入を行うという手法をよく目にします。個人的にはそこまで意味が無いと思うのですが、一応検証してみたいと思います。

MySQLチューニング

私が使っているのは正確にはMariaDBですが、MySQLと方法は同じです。

MySQLではmysqltunerというその名の通りチューニングを半自動で行ってくれるツールがあるのでこれを使います。Ubuntuでは、

$ sudo apt install mysqltuner

でインストールできます。

$ mysqltuner -buffers

を実行すると、最後にRecommandationsのところにお勧めのMySQL設定が出てくるのでそれをmy.confに記述します。

今回はテーブルがフラグメントしているのでOPTIMIZE TABLEを実行しろと言われたのでそれも実施してます。

HHVM

HHVM(HipHop Virtual Machine)というのはFacebookで開発されたPHPのJITコンパイラだそうです。JSにおけるV8やNode.jsみたいなものですかね。PHPあんまり詳しくないので今回初めて知りました。

JITコンパイラなので、初回起動は普通にPHPコマンドから起動するよりも遅く、徐々に早くなっていきます。後述しますが、wordpressのトップページの表示処理が完全に最適化されるまで2000~4000回実行する必要がありました。

Ubuntuでデフォルトパッケージのhhvmだと設定が悪いのかうまく動かなかった(なぜかデータベース接続エラーと表示される)ので、リポジトリを追加してインストールしました。

Installation: Linux | HHVM

# installs add-apt-repository
sudo apt-get install software-properties-common

sudo apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0x5a16e7281be7a449
sudo add-apt-repository "deb http://dl.hhvm.com/ubuntu $(lsb_release -sc) main"
sudo apt-get update
sudo apt-get install hhvm

でOKです。

続いて、

$ sudo /usr/share/hhvm/install_fastcgi.sh

とすればFastCGIでhhvmを使う設定ができる…のですが、エラーにより途中で止まってしまいました。

本来は/etc/nginx/hhvm.confが出来るので、これを/etc/nginx/sites-available/defaultなどからインクルードするみたいですが、中身を参照しつつ手動でdefaultの中に記載しました。

        location ~ \.php$ {
                #include snippets/fastcgi-php.conf; # ←コメントアウト

                # With php7.0-cgi alone:
                #fastcgi_pass 127.0.0.1:9000;
                # With php7.0-fpm:
                #fastcgi_pass unix:/run/php/php7.0-fpm.sock;

                # ↓ここから追記
                fastcgi_keep_conn on;
                fastcgi_pass   127.0.0.1:9000;
                fastcgi_index  index.php;
                fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
                include        fastcgi_params;

ちなみに、運用時はhhvmが標準でブート時に起動するようになってないので、以下のコマンドで標準起動させるようにします。

$ sudo update-rc.d hhvm defaults

設定が完了したらnginxとhhvmを再起動しときます。

検証条件

すでに運用しているブログをローカルのPC上で動かして計測しています。プラグインも記事数も結構入ってます。
環境はNginx + PHP7で、Intel(R) Core(TM) i5-4590 CPU @ 3.30GHz / MEM 4Gというスペックです。
ローカルからアクセスして計測するので、ネットワークによる遅延はほぼありません。
それぞれ開始前に4000回程度リクエストをかけてから計測してます。

検証結果

以下のようになりました。

項目 time/req time/req(concurrent) reqs/sec
初期状態 111.3 5.6 179.76
初期状態 + キャッシュ 2.1 0.1 9674.03
MySQLチューニング 106.9 5.3 187.1
MySQLチューニング + HHVM 87.0 4.4 229.86
全部 1.3 0.064 15627.20

初期状態の179.76 reqs/secというパフォーマンスもすでに十分だと思います。

MySQLのチューニング結果は大した伸びてないですね。というか、そもそもmysqltunerがほとんど提案を返してくれなかったんですね。初期パラメータで十分なパフォーマンスが出ているということなのでしょう。ここからマニアックなチューニングを進めればさらに伸びると思いますが、苦労の割にメリットは少なそうです。MySQLがボトルネックになるような環境であれば、素直にSSD化しろ、メモリ積めって感じになるんじゃないでしょうか。

HHVMはかなり伸びてますが、このスコアになるまで4000回くらい実行させてます。初回1000回の結果は128reqs/secと初期状態よりもだいぶ遅かったので、プログラム変更するたびにちゃんと慣らし運転をしといた方が良いレベルですね。そんな手間かけるくらいならわざわざ導入する必要もないかなぁという感じです。

全部入りでダントツの性能を発揮していますが、ちょっとこれは解せません。キャッシュが効いているならば、MySQLチューニングとHHVM導入の効果は初回のアクセスにしか効かないからです。だから、「初期状態+キャッシュ」と「全部」はほぼ同じになるはずと思っていたのですが、なにか他の影響があるのかもしれません。

サーバ側速度改善のまとめ

やはり当初の結論通り、サーバ側速度改善はキャッシュ導入のみで良いのではないかと思います。HHVMやMySQLのチューニングはキャッシュが有効に働かない環境、つまりアクセスするたびにサーバ側で動的に生成しなければならないコンテンツが大量にある場合などに限ります。普通のブログなどであればやる意味は無いかなと思いました。

というか、サーバ側で常時動的に生成するコンテンツがある場合はPHPなんか選ぶなよって私は思うのですが、まあ例えばPHPで作られたソシャゲーの類っていっぱいあるみたいなんで、うーん、人それぞれですね。

その他改善

さて、サーバ側のレスポンス速度の改善は以上ですが、これでサイトの表示が爆速になったかというとそういう訳でもないです。例えば私のブログはNginx + FastCGI キャッシュでかなり高速化しましたが、実際ブラウザでブログを表示してみると遅いです(現時点では)。実測値で500倍高速化したはずですが、実感としては1/3くらいにしかなってない気がします。それでも十分早くなったとは言えますが。

面倒くさいのを我慢して色々調査してみると、まあうすうす感づいていた通り、WebサイトのレンダリングやAjaxリクエスト、キャッシュが有効に効いていないなどの理由が分かってきました。このあたりはabコマンドなどで負荷テストをしても分からない領域です。クライアント側の処理までセットで対処しないと効果は薄いので、今回はそれらも改善します。

調査方法

GoogleのPageSpeed Insightsが便利です。これを使うことで、実際のサイトを読み込み「ここを改善すれば早くなるよ!」というのを教えてくれます。

あとは、Chromeの開発者ツール(F12キーで表示)のNetworkやProfileも役に立ちます。いや、ブログごときだったらプロファイラは使わないかもしれないけど…。まあ一応。

使い方は見て覚えてください。見て理解できなければHTTP通信やHTML/JSの基礎が理解できてないということなのでそこから勉強してください。ガンバ。

以降では実施してなかった設定などを書きます。

Gzip圧縮の有効化

サーバ~クライアント間でGzip圧縮を利用して通信量と転送時間を削減します。基礎中の基礎ですが、これが有効になっていませんでした。デフォルトで有効になってるもんだと思ってましたが、なってないんですね…。デフォルトだとtext/htmlしか圧縮しないそうです。テキストファイルなんかデフォルトで全部圧縮しろよとおもうんですがなんか理由有るんですかね。

ともかく、/etc/nginx/nginx.confの下記コメント行をコメントアウトします。

        ##
        # Gzip Settings
        ##

        gzip on;
        gzip_disable "msie6";

        gzip_vary on;
        gzip_proxied any;
        gzip_comp_level 6;
        gzip_buffers 16 8k;
        gzip_http_version 1.1;
        gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

ブラウザキャッシュの有効化

静的コンテンツはExpireヘッダ/Cache-Control: max-ageヘッダ、あとはLast-Modifed ヘッダー/ETag ヘッダーを付けろとのことです。Expireは1年先を出来れば指定して、Cache-Control: max-ageよりはExpireで対応したほうが良いとの事。
(参考:ブラウザのキャッシュを活用する | PageSpeed Insights

Nginxのデフォルト設定でETagはついてましたが、Expireヘッダはついてなかったので静的コンテンツにはこれを付けます。

server {
       location ~ .*\.(jpg|gif|png|css|js|ico|woff|mp4|webm)$ { access_log off; expires 365d; }

という設定を/etc/nginxs/ites-available/defaultに書きます。

ただ、これだと静的ファイルを変更した時にキャッシュが消せずにしんどくなります。ファイル名末尾にハッシュ値とかバージョン番号とかを含めておいて、更新するたびファイル名を変更すると良い(URLフィンガープリント)とありますが、正直面倒ですね。なんかうまい方法は無いでしょうか。

CSSとJavaScriptのMinify

無駄な改行やスペースを削除したり、変数名を短くしたりしてテキストファイルのサイズを圧縮するアレですね。Node.jsとかPlay Frameworkとかで開発していればアセットを作るときに自動でやってくれたりするんですが、PHPはどうすりゃいいんでしょう…。謎です。

Ubuntuではaptでインストールすればコマンドラインからyui-compressorを使えるのでとりあえずそれで圧縮するのが適切でしょうか。面倒ですけど。

スクロールせずに見えるコンテンツのレンダリングをブロックしている JavaScript/CSS を排除する

Page Insightではこうやって…簡単に…言いますけどねぇ。依存しているJavaScriptがあると途端にこれは面倒になります。

Google Analyticsなど外部のサービスを使っている場合で、かつ、それが非同期実行に対応しているならばそれを利用するという程度がすぐ出来る対応としては限界ですかねぇ。

あとは、軽量なCSS/JSならばインライン化してしまう、とかですかね。

このあたりも、Node.jsみたいなアセットをあれこれうまいこと変換してくれるものがあれば楽なんでしょうけど、PHPでは良くわからん。アセットコンパイラを使うためだけにNode.jsを導入するとか…?

まとめ

WordPressサイトの高速化はキャッシュ導入してはい、終わり。では無くて、その他にも一般的な表示高速化テクニックを導入する必要があります。サーバサイドの知識からフロントエンドまで知識がある人でないとこの作業って難しいでしょうから、高速化も中々奥が深いですねぇ。