こんにちは、17新卒エンジニアのジャンハンです。

現在はDMM電子書籍サービスの開発部門で改修、保守の業務を担当しています。

サーバーサイド(PHP)がメインで、フロントの実装も度々あったりしまして、たまーーーにデプロイツールの実装や環境周りの業務も担当しています。

本日はDMM.com #2 Advent Calendar 2017の6日目を担当させていただき、新米エンジニアが電子書籍サービスの速度改善タスクを担当した時のアプローチについて文章にまとめました。

カレンダーのURLはコチラ
DMM.com #1 Advent Calendar 2017
DMM.com #2 Advent Calendar 2017

速度改善の指標

webサイトのアクセス速度に影響する要素は、css、jsの圧縮、画像の圧縮、初期レンダリング情報量、画像サーバーの返答速度等がありますが、今回の担当はメインサーバーの返答速度なので、サーバーサイドの処理時間を改善指標とします。サーバーサイドの処理時間はTTFB(Time To First Byte:以後TTFB)の値を指標にしました。

TTFBとは

サーバーがリクエストを受け取ってからデータを返し始めるまでの時間のことです。

TTFBの確認方法

chrome、safari等のブラウザの開発ツールを使用して確認できます。下図はchromeで確認した例です。「newwork」というタブを選択して、リスト一覧の最上部にある要素にカーソルをあわせるとTTFBを確認できます。
image.png

サーバーサイド応答速度改善

Googleが推奨するTTFB時間は200ms以下(きびしいー)でした。そこまでは道が遠いですが、ひとまずサーバーサイドの応答速度を影響する要因を考えてみました。主に以下3つが考えられます。

  • 速度の遅いアプリケーションロジック
    • ロジックが最適化されてない、重複処理が多い
    • array_pusharray_searchis_null等の処理速度の遅いメソッドが多い

処理速度の遅いPHPメソッドについてはこちらを参考してください

  • 速度の遅いクエリ

    • 必要のないデータを取得している(selcet*を多用)
    • indexが適用されていないクエリがある
    • データ件数分のクエリが実行されている(N+1問題)
  • キャッシュの利用が不十分

しかし、実際どれが原因なのかを考える時ボトルネックを探す必要があります。腕のいいエンジニアはソースコードをちらっと見みたらボトルネックが分かるかもしれませんが、自分はそんな超能力を持ってないのでボトルネックを調査するため、blackfireというプロファイリングツールを使用しました。

blackfireとは

blackfireはPHPフレームワークのSymfonyの開発元となるSensioLabsが開発した、PHPに特化したプロファイラーです。サーバーに必要なツールをインストールするだけで、リクエストを受けた際、どのメソッドを通り、各メソッドがどれくらい時間がかかり、どのぐらいメモリを消費している等を視覚化してくます。洗練されたユーザーインターフェイスが実装されていますので、スムーズにボトルネックを探せます。

有料プランが提供されていますが、ボトルネック調査だけなら無料プランでも十分使えます。
image.png

blackfireの初期設定

blackfireを使用するにあたて、まずはblackfire.ioにて登録する必要があります。
以下は公式ページからCentOSで利用する場合の初期設定を抜粋したものです。他のOSは公式ページを参考してください。

1. pygpgmeパッケージとblackfireリポジトリーのインストール

sudo yum install pygpgme
wget -O - "http://packages.blackfire.io/fedora/blackfire.repo" | sudo tee /etc/yum.repos.d/blackfire.repo

2. エージェントのインストール

sudo yum install blackfire-agent
sudo blackfire-agent -register

これらのコマンドを実行すると、ServerIDやServerToken等の情報が聞かれると思いますが、これらの情報はアカウント情報で確認できます。
その後、以下コマンドでエージェントを再起動します。

sudo /etc/init.d/blackfire-agent restart

3. blackfire CLI toolのインストールと起動

sudo yum install blackfire-agent
blackfire config

ここでまたClient IDとClient Tokenが聞かれます。これらの情報もアカウント情報で確認してください

4. PHP Probeをインストール

sudo yum install blackfire-php

ここで、サーバーサイドのインストール系が完了します。webサーバーを再起動してからblackfireが利用可能になります。

※ PHP ProbeはXHProf、IonCube、Pinba、Suhosinと競合するため、Probeを有効にするにはそれらのツールを無効化するか、アンインストールする必要があります。

5. Google Chromeの拡張機能をインストールする

以上でコマンドラインでプロファイリングができるようになりましたが、blackfireの素晴らしいインタフェースを使用するため、Chromeの拡張機能のをインストールする必要があります。インストールのリンクはこちらになります。

以上揃えるとblackfireを使用して、ボトルネック調査ができるようになります。

blackfireの使い方と見方

blackfireの使い方はとても簡単です。初期設定を完了したサイトにアクセスして、下図のようにChromeの右上の拡張一覧からblackfireのアイコンをクリックし、「Profile!」をクリックするだけです。

image.png

プロファイル完了したら、blackfire.ioコンソールページで該当計測結果をアクセスすると、以下のようなインタフェースが表示されます。
右側のグラフで、ボトルネックとなるメソッドが一目瞭然になります。左側のリストをクリックすることで、メソッドの処理時間の詳細、メモリ使用量等も確認できます。

また、最も左側のタブ「Recommendations」を選択すると、速度改善のレコメンドもあります。これでボトルネックとなるメソッドを探し、そのメソッドの中でさっきほど述べた「サーバーサイドの応答速度を影響する要因」を探し、一つずつ解決すればいいと思います。
image.png

まとめ

まとめとして、サーバーサイドが遅い原因は以下が考えられます。

  • 速度の遅いアプリケーションロジック

    • ロジックが最適化されてない、重複処理が多い
    • array_pusharray_searchis_null等の処理速度の遅いメッソドが多い
  • 速度の遅いクエリ

    • 必要のないデータを取得している(selcet*を多用)
    • indexが適用されていないクエリがある
    • データ件数分のクエリが実行されている(N+1問題)
  • キャッシュの利用が不十分

blackfireを使用してボトルネックとなるメソッドを探し、上記の「サーバーサイドの応答速度を影響する要因」を一つ一つ解決してみました。結果として、対象ページのサーバーサイドの応答速度を30%程度削減できました。

phpサーバーサイドの速度改善を考えている人には、個人的にこのアプローチがおすすめです。よかったら試してみてください。
ここまで見て頂きありがとうございました。明日のDMM.com Advent Calendarは@wshinoさんが担当します。

参考した記事

PHP 高速化に関するメモ書き
サイトを37倍に高速化した7つの手法
あなたのサイトは大丈夫?簡単手軽にサーバーのパフォーマンスを計測する方法
PHPプロファイラーのblackfireを使う
高速なWebサーバアプリケーションを構築するための6つの経験則