search
LoginSignup
6

More than 5 years have passed since last update.

posted at

updated at

Organization

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

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で幸せになれたお話」です。

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
What you can do with signing up
6