APIのレスポンスを最適化するには

APIを使ったシステム開発で常に問題になるのがレスポンスです。一つ一つのレスポンスは高速であったとしても、リクエスト数が増えればトータルのレスポンスが遅くなっていきます。

今回はAPIのレスポンスを最適化するためにできる改善案について紹介します。

処理の並列化

10回のリクエストを順番に行なっている場合、前の処理が終わるまで次の処理ができません。一つでもレスポンスが遅い処理があると、それがボトルネックになって全体が遅くなります。それを防ぐのが並列化です。

JavaScriptなどはネットワーク処理が並列で行えます。プログラミング上の注意点はありますが、複数のネットワークリクエストを並列で行えば一番重たい処理が終わった段階で全ての処理が終わってるでしょう。他のプログラミング言語でもスレッド処理を使うことで並列処理が行えるようになります。

問題点としては1つの処理結果を受けて別な処理を行う場合に向かないことです。なるべく分岐処理が入らない形で一気にデータの投入や更新を行うようにすべきでしょう。もう一つの問題は多数のリクエストが同時に走ることでサーバの負荷が上がってしまうことです。サーバによっては同じリクエスト元からの大量のアクセスがあるとDoS攻撃と見なしてリクエストを破棄してしまうことがあります。

キャッシュ

クライアント側で処理をキャッシュするのも一つの手です。メモリ上に乗せるのはもちろんのこと、クライアント上のストレージ上に保存しておくようにすれば再実行した際にもデータを取得せずに済むようになります。簡易的にはKVSのようなキーと値だけの保存形式から、SQLiteなどを使ったデータベースまで考えられます。

問題点はデータの状態が最新であるかどうかの確認する手段を用意しなければならないということです。特にサーバ側で削除されたデータがあるかどうかの確認が問題になりがちです。

データをまとめて返す(画面最適化)

スマートフォンアプリでよくある方法ですが、必要なデータをまとめて返してしまうことでネットワークリクエスト数を削減できます。専用のAPIを用意することで、ほぼその画面を作るためだけのAPIとして最適化されます。多くのスマートフォンアプリでは専用の非公開APIを用いて開発されているため、このような方法が使えます。なお、画面の変更に伴ってAPIの形式も変化しますが、後方互換性を維持する必要があるためAPIのレスポンスが徐々に肥大化する傾向があります。

データをまとめて返す(バッチ処理)

また、ゲームアプリなどで使われている方法で、複数のAPIアクセスをバッチ処理として一つのリクエストに集約するというものがあります。これは主に取得系APIに対して用いられます。一つ一つはRESTfulなAPIですが、まとめてアクセスすることで一度に複数のデータが取得できます。

これは実装も楽で、プロキシサーバを立てるだけで済みます。プロキシサーバが複数のAPIアクセスを個別に行い、レスポンスをまとめて返却します。この方法は簡易的な一方、重たいAPIアクセスがあるとボトルネックになって結果が返るのが遅くなる傾向があります。

GraphQLを使う

GraphQLがベストかは分かりませんが、原理的にはクライアント側から自分が必要なデータを指定するという方法になります。つまり必要なデータしか取得しないことでデータベース側の負荷を下げたり、転送量を小さくできます。また、画面最適化のようにクライアント側のバージョンアップに伴う後方互換性を気にする必要がありません。

問題点としてはGraphQL自体がまだまだ新しい技術であるため、GraphQLのAPIが変わる可能性があることや、クライアント側で自由にデータ取得方法が指定できるために、サーバ側の最適化が行いづらいという問題があります。元々APIはレスポンスを含めてサーバ側でコントロールしてきましたが、GraphQLでは逆になります。利点とも言えますが、開発者がその場その場の最適解を選ぶと、全体としてはアンバランスになるのは良くあることです。


もちろん、アプリケーションサーバを改善したり、データベースの構造やインデックスを見直すというのは行わなければなりません。しかしAPIサーバだけを見るのではなく、クライアント側でもできることも多数あるでしょう。提供側と利用側双方で改善し、ユーザに快適なサービスを提供するようにしましょう。

© NTT Communications Corporation All Rights Reserved.