このエントリはMagento Advent Calendarの1日目です。

ある程度サイトが流行ってくると、セールやメディア露出によって突発的なアクセス増が起きてきます。
例えば以下のようにCPU使用率が100%近い状態になり、応答しなくなるというようなケースです。
(グラフは横軸が6時間なので、かなり長時間にわたって断続的に負荷が高いことがわかります)

CPU使用率

これはどんなシステムであっても同様に発生する現象で、立ち上げ期を脱したサイトが次のステージに移行するための試練のようなものです。 

さて、一般的にMagentoといえば、

  • 処理が重くてレスポンスに時間がかかる
  • SQLの発行数が多く、データベースに負荷がかかる
  • データベースがMySQLなので書き込みの負荷分散が難しい

という声をよく耳にします。
はっきり言って、間違っていません。全て正しい意見です。

では、アクセス集中を乗り切るためにどうすれば良いのでしょうか?

サーバー性能を含めたインフラ構成を見直す

MagentoはWebアプリケーションです。
それもLinux,PHP,MySQLをベースにしています。他のWebアプリケーションと同様のインフラ構築・チューニング手法がそのまま使えます。
スケールアップ・スケールアウトというのはこれまで様々な人が話題にしてきました。
定石的な対応をしていけば、Magento特有の対策というものは特に必要はありません。

ただ、強いていうならば、CPU処理性能を重視したサーバー構成にしておくと良いでしょう。

ミドルウエアの構成を見直す

インフラ構成と平行して見直しが必要なのは、ミドルウエアの構成です。
データベースはMySQL(あるいはその派生プロダクト)から変更できないので、主にWebサーバー側の調整作業です。

Nginx + php-fpmに乗り換える

Apache + mod_phpというのは非常によく使われる構成です。実績もあり、安定しているだけでなく、多くのアプリケーションで標準的にサポートされています。ですが、高負荷状態ではPHPがApacheのmpm_preforkでしか動作しないこともあり、どうしても弱い面があります。

通常Apacheをmpm_preforkで動かすと、子プロセスを作ってアクセスを処理します。この処理がどうしても負荷がかかりやすい上、静的なファイルの配信であってもApacheの1プロセスが占領されるため、サーバーのメモリを浪費しがちになります。
(keepaliveを使ってもpreforkはpreforkです)

そこで、Apache + mod_phpの構成をやめて、Nginx + php-fpmに乗り換えます。静的ファイルの配信においては、Nginxに軍配が上がるほか、php-fpmがHTMLドキュメントの配信だけに専念できるため、静的ファイルの多いサイトではかなり威力を発揮します。

Apache + mod_phpよりは玄人向けな構成にはなりますが、Apacheよりも省メモリで運用ができるのがNginx + php-fpmの魅力です。

PHPのバージョンやエクステンション構成を見直す

MagentoがベースにしているPHPは、新しいバージョンほどパフォーマンスがでます。もうすぐリリースされる予定のPHP7は、PHP5.6と比べても圧倒的なパフォーマンスを実現しています。より速く処理をしてブラウザに結果を返すことで、同じサーバー性能であってもより多くのアクセスをさばくことができます。

PHP5系の場合は、Zend OpCacheなどのバイトコードキャッシュを活用することで、未導入の状態よりも性能を高めることができます。
その他、realpath_cacheなどのパラメータを調整することで、多少でもパフォーマンスが向上するとされています。
環境に合わせてこれらは最適な値を探していくことになるでしょう。

Magento自体を見直す

行きつくところは結局アプリケーション自身です。Magento自体をチューニングすることで、より多くのアクセスをさばけるようにしましょう。

ログの記録を止める

Magentoは1回のアクセス毎にどの商品やカテゴリを見たかをデータベースに記録しています。データベースへの更新処理は比較的重い処理なので、アクセス数の多いサイトでは無視できない負荷になります。

Magento1.9.2.xでは、管理画面の設定でログ記録を止めることができます。
最近見た商品やあまりアテにならない統計機能を使わないのであれば、止めてしまいましょう。

予算が許すのであればレコメンデーションエンジンに委ねてしまったほうが遥かに売上に貢献してくれると思います。

TOPページの表示内容を見直す

どうしてもTOPページにはあれこれ表示したくなります。新着商品や売れ筋商品といった情報を出したくなるのは道理です。
とはいえ、あれこれたくさん表示させてしまうとデータベースへの問い合わせが増えてしまい、ページが遅くなります。表示させたい気持ちをぐっと堪え、最小限の表示に止める勇気も時には必要です。

静的ブロックの数を減らす、あるいはキャッシュ化する

静的ブロックは便利です。
あらかじめあちこちに埋め込んでおけば、管理画面から更新ができるようになり、利便性が向上します。
ところが、静的ブロック1個につき、データベースへの問い合わせが3〜4回発生します。

アクセス数の多いサイトでは、1回でもデータベースへの問い合わせを減らすチューニングが必要になるため、静的ブロック削減だけでなく、出力内容をキャッシュ化するようなチューニングも必要です。

フラットテーブルを使う

それなりに商品点数があるサイトの場合は、フラットテーブルを使うほうがパフォーマンスがでます。
と言っても数%程度ですが、アクセス数の多いサイトでは無視できない数字です。

フラットテーブルを有効にすると、インデックス処理が必要になりますが、その代わり多少でもパフォーマンスが向上します。 

フルページキャッシュを使う

フルページキャッシュはエンタープライズ向けのCMSパッケージでもよく採用される手法です。
Magentoの場合はEnterprise Editionは標準で付属しますが、Community Editionの場合はサードパーティ製のものを利用します。

様々な実装の方法があるようですが、概してPunch holeという方式が採用されることが多いようです。
名前の通り、ページのコンテンツに対してパンチで穴を開けたかのようなHTMLデータを作成してキャッシュとして保管しておきます。
このデータを利用するページをブラウザに送信する前に、穴が空いたところを埋めるように動的なコンテンツを生成し、はめ込んでから送信します。

商品リストやTOPページのコンテンツといった、一番重い処理の部分を再利用し、負荷の軽減と処理効率の向上を図ります。
この威力は絶大で、同じ性能のサーバーでも10倍以上のレスポンス性能を叩き出すことがあります。

反面、キャッシュの更新タイミングがわかりにくいため、商品やカテゴリの情報を更新してもすぐには反映されないという問題が起きます。
しかし、他のどの対策よりも効果が期待でき、なおかつ正しくカスタマイズがされていさえすれば導入が簡単です。
ところがこの「正しくカスタマイズ」というのが殊の外難しいのです。

次回の予告

次回はフルページキャッシュを導入するための正しいカスタマイズについて解説します。
どのようなカスタマイズがバッドケースで、どのようなカスタマイズがベストプラクティスなのか。
知っているのと知らないのとではカスタマイズ作業に大きな差がでます。
(ちなみにMagento1でもMagento2でも同じ概念が使えます)

 

と、明日はkzkick2ndさんなので一旦バトンタッチします。