WordPressをサクっと500倍高速化する

そういうことをやってみたので書いてみます。

背景

当ブログはさくらのレンタルサーバ、スタンダードプランで運営していました。これは共有サーバというやつで、単一のサーバを複数のユーザーが利用します。各ユーザーの公開ディレクトリはユーザーディレクトリの下にあります。昔からよくあった形態のひとつですね。

で、共用サーバっていろんな人が使ってるんで正直リソースの取り合いみたいなところがあるんですよ。もちろん、取り合いにならないよう何らかのユーザーごとの負荷制限はかけてるんでしょうけど、同じ環境を使っている以上公平にはならない。仮想マシンならばもうちょっとリソース管理も公平にできるんでしょうけど。

そんなわけで果たして私のブログはどのくらいのリソースを使っているのか。調べてみました。

な、なんじゃこりゃ…。

まず、503エラーに着目してみます。503というのはサービスが一時的に利用できないという状態を表すエラーコードですが、つまりは負荷がかかったときにレンタルサーバ側が積極的にプロセスを殺しているんですね。これを見ると12/1あたりにかけて約90万回のエラーが発生しています。おそらくこれは攻撃を受けてるんでしょう。しかも、管理系のスクリプトには国外アドレスからの接続をブロックしているので、国内からの攻撃と言う事です。不正アクセスに当たる行為と思われますので、IPアドレスから開示請求を依頼して訴訟を起こしてみようかな(やってみたいから)と思ったのですが、なんとっ!ログが取られていませんでした…。おっかしいなあ?ログを取る設定になってなかったんです。なぜ…。

ちなみに、グラフを見ると12/1以外は発生回数がゼロに見えますが、これはY軸が伸びきってるのが原因でして、日常的に2000~4000回の503エラーが発生しています。一日2000~4000回も表示回数を損失してるって、これえらいことですよ!私の独自の計算だと、これで一日にジュースX本分くらいの収入機会を損失してますからね。

続いてCPU時間ですが、大体7時間から8時間前後を行き来しています。な、なんと…。先に「共用サーバっていろんな人が使ってるんで正直リソースの取り合いみたいなところがあるんですよ」などと言いましたが、リソースぶんどってるのは私だったのですね。みんなすまん。

ちなみに、右端がストンと落ちてるのは、後述するようにサーバ移行が完了したからです。

サーバスペックを見てみるとCPUは2コア、私のサーバには実に130人程度の人が同居していました。2コアなんで実質的な一日のCPU時間は48時間。そのうちの9時間、実に20%弱を私が使ってる。均等に割ると一人1%以下のリソースになるんだけど。うーん。すまん。すまんがとは言ったが、あんまり申し訳ない気持ちは無い。なぜならば高負荷によるアクセス制限が行われたというログは例の12/1のバースト時にしか残ってなかったから。

しかしながら、503エラーが日常的に数千回も発生しているような慢性的なリソース不足の状態で制限が掛かってないというのも良くわからないんですが。

対応策

そもそもWordpressみたいにLLで作られたCMSはCPUリソース的にしんどいものがあります。根本的にはフロントエンドサーバを用意してキャッシュするしかないでしょう。Wordpressだとプラグインでキャッシュ機構を実現するようなものもありますが、Apacheの.htaccessやWordpress本体のソースを書き換えたりと危険な処理をするものが多いようなので、あまりそれらの方法は取りたくありません1

レンタルサーバではフロントエンドをどうこうするのは出来ないです。.htaccessで設定できるところまでが限界。Apache HTTPを実はあんまりよく知らない(私はNginx原理主義者)ので.htaccessを頑張って設定すればphpの実行結果もキャッシュできるのかもしれませんが、頑張るモチベーションが生まれるほどにApacheが好きじゃない。

それに、月間何十万PVもあってちゃんと収益化までできているブログを月500円かそこらのレンタルサーバに押し込んで皆に迷惑かけているという状況がそもそもアカンと思うので、VPSをどこかで借りてサーバ移行することとした。今年の2月にドメイン取っておいてよかった(運営開始から3年経ってようやく取った)。

現状測定

まずは現状を測定しましょう。サイト表示にかかる時間のベンチマークを取ります。

色々方法がありますが、ab(Apache Benchmark)コマンドが楽です(先ほどApacheをdisっておきながら)。Ubuntuならば、

$ sudo apt install apache2-utils

で入ります。Windowsとかは適当にどこかからバイナリを持ってきてください。

$ ab -n リクエスト送信数 -c リクエスト同時送信数 対象URL

という感じでテストできます。基本、ローカルで実施するためのツールと思いますが、リモートサイトを測定するときは-Bオプションで自分のIPアドレスを指定してあげないとダメみたいです。ちなみに、私のブログを対象にやらないでね。やったら容赦なく開示請求かける。

これを使って、まずは共用サーバで動いている私のブログを測定してみました。といっても、あまり負荷掛けられないのでリクエスト送信数は数十回と少なめに。

すると…。
'''
Requests per second: 0.48 [#/sec] (mean)
Time per request: 2067.031 [ms] (mean)
Time per request: 2067.031 [ms] (mean, across all concurrent requests)
Transfer rate: 31.88 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 12 13 0.5 13 15
Processing: 1710 2054 331.3 1966 3114
Waiting: 1378 1679 272.3 1623 2673
Total: 1723 2067 331.2 1979 3127

Percentage of the requests served within a certain time (ms)
50% 1979
66% 2051
75% 2187
80% 2276
90% 2549
95% 2979
98% 3127
99% 3127
100% 3127 (longest request)
'''

レスポンスタイム2067msec, 0.48RPS…。秒間1アクセスに満たない…。なんとなく想像してたけどこれは厳しい。Webサイトのレスポンスとしてはゴミの領域です。これアカンだろ…。なぜもっと早く気付けなかった…。

ちなみに、ローカルマシンに構築したインストール直後のWordpressで33msec/30RPSといった感じでした。

これはもちろん要求したURLに対する応答だけなので、実際のブラウザアクセスでは多数のAjaxリクエストが発生することを考えると体感速度はもっとひどいでしょう。

VPS選定

こんな遅いサーバではやってられません(遅くなった原因の一翼は自分にあるのですが)。VPSにさっさと引っ越します。

候補としては、長らくお世話になっているさくらインターネットさんのVPSか、AWS(Amazon EC2)かなぁといったところ。

AWSの見積もりツールで色々やってみたが、EC2はリージョンが日本だとt2.microで$14くらいと結構安いのだけど、データ転送量が高い。1日10GBとして1か月300GBとすると、データ転送量だけで$41もかかるようだ。ぼええ?マジかあ?これみんな払ってんの?と思ってググってみると、これが原因で他サーバに乗り換えたという報告もちらほら。

自分みたいな規模のサイトで運営するにはAWSでは全然スケールメリットがでないようだ。AWS便利ぃー!おっしゃれー!セクシー!みたいに絶叫しているエンジニアもずいぶん前から見かけたが、それなりの規模のソシャゲーとか運営しないとセクシーじゃないんだね。

という訳で庶民の味方(?)さくらVPS。すでに1台VPSは契約しているので、もう一台契約する。すでに契約する一台は「くるまくん」を運用しており、このサイトは全然アクセスがないのでこちらで共存させても良いのだけど、いやいや、くるまくんはこれから流行らせるから!という気概も込めてVPS追加。

高速化方針

本記事で最も重要なとこ。高速化方法を色々検討したり、ググったりして調べた。結果、以下が有効と判断。

  • NginxによるFastCGIキャッシュを使用
  • php7.0の使用

特に参考にしたのが、下記の@ITの記事。

「NginxのFastCGIキャッシュ」を導入して「1127倍」まで高速化する──「WordPress“1000倍”高速化」チューニング総仕上げ

この記事では色々な方法を実施しているが、やるべきなのはNginx + FastCGIだけかな、と私は判断。

ブログはほとんどが静的なコンテンツである。しかしながらWordpressではアクセスのたびにデータベースアクセスを経て同じHTMLをphpで生成している。アクセスのたびにIOの発生にphpの実行。明らかに無駄である。ここの処理をバイパスできるのは非常に大きい。

今回はそれに加えてphp7.0にしたが、これは単にphp5.xシリーズのサポートが終わっており、Ubuntu16.04でphpパッケージをインストールすると標準が7.0系になっていることによる。5.xから7.xでパフォーマンスの改善もかなりあるらしいが、キャッシュを導入すればあまり恩恵は無い(最悪値は改善される)。

ちなみに、上記記事では1100%の高速化、22830%の高速化などと勇ましいことが列挙されているが、データやプラグインがふんだんに入り、かつインターネット越しにアクセスするような実環境ではここまでの効果は望めないと思われる。

ためしにローカルのデスクトップPCでNginx + FastCGI、 PHP7の組み合わせでテストしたところ、平均アクセス時間0.075ms, 13300RPSというすさまじい値になった。これだけやれば実サイトでは十分だろう。

また、その他にもWordpress向けに特別チューニングした仮想マシンイメージとかクラウドサービスなどがあるようだが、私にとっては知識があってかつ汎用的な環境(Ubuntu)で運用することに意味があるので、こういうものは最初から選ばなかった。特殊化を進めるとトラブルがあったときに困るので。

WordPress環境構築

【超簡単!】Ubuntuで作る手間いらずのほっこりnginx+wordpress環境!というふざけた名前の記事で解説していたのだが、この内容はすでに古いので以下に書きなおした。参照されたし。

Ubuntuで作る高速WordPress運用環境のまとめ

サイト移行

WordPressの移行作業はそんなに苦労しない。やり方は色々あるのだけど、ようはDBを復元したうえでwordpressのディレクトリ一式をコピーすれば良いです。クリーンインストールしたい場合は、wp-content以下を復元すれば良いはずです。

移行時にちょっと面倒なのがDNSの設定です。

サーバ移行時にはドメインに紐づくサーバのIPアドレスを変更します。移行先のwordpressサイトが完全に復元できてからドメインに紐づくIPアドレスを変更したい…と思いますよね?しかし、Wordpressの設定を復元した段階でこれは不可能になります。なぜならば、Wordpressは内部に設定されたドメイン名をしつこく使用してこようとします。そのため、DNSのIPアドレスを更新する前に管理画面に入ろうとしても、現状のサイトに飛ばされてしまいます(伝わるかな?)。

だから、一時的に移行先のサーバのIPアドレスを直接指定しておきましょう。wp-config.phpに

define('WP_HOME','http://123.456.789.012/');
define('WP_SITEURL','http://123.456.789.012/');

という設定をしておけば、移行先のサイトの管理画面にIPアドレス指定でログインすることができます。移行作業が終わったらこの設定を削除すれば元に戻ります。

私はバックアップにUpdraftPlusプラグインを使っているので、このプラグインをつかって復元します。上記の仮設定をしたうえで、wp-content/updraft/以下のバックアップファイルをコピーします。その後、UpdraftPlusの管理画面から復元ボタンを押せば復元できます。簡単。

DNSレコード更新

DNSのAレコードとAAAAレコード(IPv6)を新サーバに移行します。浸透するまで数分~数十分かかるのでちょっと待ちましょう。OSでDNSキャッシュしている場合はクリアしてください。

もうこのブログは新しいサーバで動いていますが、Windowsは(そして最近のUbuntuディストロも)ローカルにDNSキャッシュを持つので、しばらくたたないと新サイトにはつながりません。強制的にDNSキャッシュクリアするにはなんかコマンドがあったはずですが忘れました。適当にぐぐってみてください(Windows嫌いなので適当)。

パフォーマンス測定

'''
Requests per second: 221.00 [#/sec] (mean)
Time per request: 90.496 [ms] (mean)
Time per request: 4.525 [ms] (mean, across all concurrent requests)
Transfer rate: 14077.58 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 6 18 77.3 11 1012
Processing: 32 72 62.1 58 698
Waiting: 6 13 18.3 11 252
Total: 41 90 98.2 71 1072

Percentage of the requests served within a certain time (ms)
50% 71
66% 74
75% 77
80% 79
90% 100
95% 274
98% 323
99% 505
100% 1072 (longest request)
'''

秒間221アクセスです。ちなみにこれは、Wifi接続されたノートパソコンからリモートサーバーに対してアクセスして測定した結果です。まあこんな感じでだいたい500倍くらいになりました。

うーん、正直もうちょっと早くなっても良いかな?と思いましたが、ローカルで(VPS内部で)テストしたら秒間1万アクセスくらいは平気で出るので、もう回線のボトルネックでしょう。よほど大きなサイトでもない限り、秒間250アクセスという値は十分に高性能と言えるんじゃないでしょうか。

まとめ

今回はサイトの負荷増を確認してからサイト移行まで実質作業時間3時間程度というなかなかすばやい動きだったように思います。子供が寝てる横でVPSの設定とかしてたぜ。これが30代子持ちエンジニアだっ!分かったか!分かったらさっさと寝ろ!


  1. ちなみに、Wordpressの話題を扱うブログでよく「良くわからずにキャッシュを使うのは危険」などという話が書いてありますが、正確にはキャッシュが危険なのではなくてWordpressのキャッシュプラグインが危険なのだと思います。