LoginSignup
11
6

More than 5 years have passed since last update.

yii2で高性能なWebAPIを実現する

Last updated at Posted at 2016-12-03

yii2で高性能なWebAPIを実現する

この記事はmediba advent calendar 2016 4日目です。

はじめに

とあるプロジェクトでyiiのバージョン2系で実装したWebAPIを開発、運用しています。
本エントリーでは、yiiのバージョン2系(以下yii2)でWebAPIを開発する際のtipsをまとめました。
ご査収ください。

想定読者

相変わらず、ターゲットが狭いです。

  • PHPer
  • yii2で実装されたWEBアプリケーションを開発、運用している
  • 高性能なWebAPIを要求されている

yii2とは

PHPのWeb Application Frameworkです。多機能パフォーマンスも悪くないとバランスの取れたフレームワークと言えるでしょう。
また、弊社の開発現場では実績の多いフレームワークです。

高性能とは

このエントリーでは、以下の通りとします。

  • 複数の機能を提供しており、その拡張性を担保出来ている
  • 費用対効果の高い性能を担保出来ている

WebAPIとは

JSON over HTTPなWebアプリケーションとします。

3行で

プロジェクトを経て気づいたことを3行でまとめます。

  • RESTfulに設計する
  • ガイドを熟読する
  • 計測する

出来たことも出来なかったこともあったプロジェクトでしたが、気づきの多い良いプロジェクトだっと振り返って思います。
気づきを得たいエンジニアは、奮ってご応募下さい。

RESTfulに設計する

フレームワークが課題の解決に寄与できる割合というのは、想像よりも多くありません。可能な限りRESTfulに設計しましょう。多くのフレームワークは、RESTfulな設計を歓迎しています。yii2も例に漏れず、RESTfulな設計に応えてくれます。

...

とはいえ、現実のプロジェクトでRESTfulな設計を実現することは難しいものです。現実と向き合い、真摯な姿勢で課題の解決を図るべきでしょう。
今回のプロジェクトでは、インターフェイスの変更も実施しましたが、それはRESTfulとは呼べないものでした。RESTfulに設計が出来れば、生産性は高くなるなと気づいた程度です。
yii2のRESTfulについては、ガイドに詳しくまとまっています。ActiveRecordとの密な連携を提供していますので、RESTfulに設計したかったと悔しく思います。

ガイドを熟読する

開発チームには、迷ったらStack Overflowや他チームの実装ではなく、まずはガイドを読もうと口を酸っぱくして言い続けました。

日本語訳もあります。
今回のプロジェクトで、参考になった章を掘り下げてみます。

Quick Start

まずは、この章を読んでyiiが提供しているWebAPIな機能の概要を把握しましょう。通読すれば、実装のスリム化を図れる場合がほとんどでしょう。

Controllers

コントローラの実装について、ガイドしてくれます。RESTfulに設計出来なかった場合でも、yii\rest\Controllerを継承しておくと幸せになれます。WebAPIで重要視されるフィルターの機能が提供されているからです。

/**
 * behaviors
 * エンドポイントの振る舞いを定義
 *
 * @return array behaviors
 */
public function behaviors()
{
    $behaviors = parent::behaviors();
    $behaviors['contentNegotiator'] = [
        'class' => ContentNegotiator::className(),
        'formats' => [
            'application/json' => Response::FORMAT_JSON,
        ],
    ];
    $behaviors['verbs'] = [
        'class' => VerbFilter::className(),
        'actions' => [
            'index'  => ['get'],
        ]
    ];
    return $behaviors;
}

上記の様に、コントローラクラス内でyii\base\Behavior[]型のbehaviors関数をオーバーライドし、エンドポイントの振る舞いを定義します。エンドポイントの振る舞いを明示的に指定し、見通しを確保することが出来ます。
上記のコードでは、以下を指定しています。

  • レスポンスボディのフォーマットをJSONとする
  • indexアクション(indexAction関数)へのリクエストは、GETメソッドのみとする

また、ユーザ認証やレートリミット等のアクセス制限も明示的に指定することも出来ます。Webサーバとの担当範囲の問題もありますが、アプリケーションの開発者としてはアクセス制限をコードで管理出来ることのメリットはあると思います。

Error Handling

エラーハンドリングは、ハマりどころでした...前述のBehaviorと同じくらいカジュアルに指定出来るといいのですが、アプリケーションコンポーネントをグローバルに変更するしかありませんでした。

return [
    // 中略
    ],
    'components' => [
        // アプリケーション全体のレスポンスを設定
        'response' => [
            // レスポンスボディのフォーマットはJSONとする
            'format' => yii\web\Response::FORMAT_JSON,
            'charset' => 'UTF-8',
            // 異常系のレスポンスは、レスポンスボディを空配列とする
            'on beforeSend' => function($event) {
                $response = $event->sender;
                if ($response->statusCode != 200) {
                    $response->data = [];
                }
            },
        ],
    // 以下略

yii2のコアなアプリケーションコンポーネントとして、errorHandlerがあります。

'errorHandler' => [
    'errorAction' => 'site/error',
],

このコンポーネントのerrorActionプロパティにアクション(コントローラで実装した関数)をしてすれば、エラー時のレスポンスを定義出来ると見込んでいたのですが、結果は上述の通り、responseコンポーネントのbeforeSendイベントをオーバーライドする必要がありました。

今回のプロジェクトでは、この実装で事足りましたが、エンドポイント(リソース)毎にエラーレスポンスが異なる場合は、そうもいきません。引き続き、調査をしたいと思います。

計測する

これまでは、機能とその拡張の担保の観点で見てきましたが、今回のプロジェクトでは性能管理(向上あるいは維持)もスコープにしておりました。
性能管理は、とにもかくにも計測することには始まりません。Rob Pike先生のお言葉ですね。我々のプロジェクトでは、以下について計測しました。

  • プロファイリング

    • Xhprofを用いてアプリケーションをプロファイリングします。ボトルネックとなりうるコンポーネントや関数を把握しておきます。
  • 性能試験

    • gatlingを用いてWebAPIに対し一定の負荷を掛け、秒間リクエスト数を把握します。この際の条件は後の性能試験でも利用するので、wiki等にまとめておきます。

今回のプロジェクトで性能(秒間リクエスト数)を1.7倍程度上げることが出来ました。パフォーマンス・チューニングの勘所もお伝えできるとよいのですが、眠くなってきたので、またの機会に。結構地道なアプローチでしたが、結果を出すことが出来て、良かったです。

計測の理想は、改修の度に(コミットが発生したら)実施することなのでしょうが、今回はそこまで至りませんでした。今後の課題としたいです。
また、gatlingを用いた性能試験については、次回に譲ります。TravisCIを利用している開発チームは少し幸せになれるかもしれません。

おわりに

大仰なタイトルの割に、お伝えできることが小振りなのはいつものことですが、プロジェクトを通して、yii2というフレームワークときちんと向き合うことが出来ましたので、その一部をお伝えしてきました。WebAPIを高いクオリティで開発するには、まだまだ課題が多いのは事実ですが、フレームワークを武器に継続的に課題に取り組んでいきたいと思います。
また、yii2を用いた開発プロジェクトの生産性に少しでも寄与できていたら、とても光栄です。

明日は、制作部平尾さんの「JavaScript初級者がVue.jsで幸せになれたお話」です。

11
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
6