Backends For Frontends入門

Backends For Frontendsの概要

Backends For Frontends(以下BFF)とは、デスクトップやモバイルなどのクライアントごとに実装されたAPI Gatewayのことです。まずはAPI Gatewayについて説明していきます。

API Gateway

API Gatewayには以下のような役割があります。

  • リクエストのルーティング
  • APIコンポジション(バックエンドのAPIを複数呼び出して、その結果を集約する)
  • プロトコルの変換
  • 認証・認可
  • リクエストの制限
  • キャッシュ
  • メトリックの収集
  • リクエストログの出力

かなり多くの役割がありますが、これらすべてを1つのサーバで実装するという訳ではありません。認証・認可を共通基盤として切り出したり、リクエストのルーティングはクラウドサービスのロードバランサを使用したりすることがあると思います。API Gatewayはクライアントとバックエンドのマイクロサービスの間に存在するレイヤだと考えた方がよいでしょう。

API Gatewayが存在しない場合、問題がいくつか発生します。主な問題はパフォーマンスの低下でしょう。クライアントがAPIコンポジションを行う場合、大量のリクエストがインターネットを経由することになります。LANとモバイルネットワークでは100倍ほどの差があると考えられます。クライアントが並列にリクエストすればよいという考えもあるかもしれませんが、モダンなブラウザでもTCP同時接続数は6なので、HTTP/1.1での通信だと並列にリクエストしてもパフォーマンスの改善が難しいケースがあります。また、API Gatewayが存在しないのであれば、クライアントがバックエンドのサービスそれぞれの位置を知る必要があります。そのため、クライアントはService Discoveryし、その後で必要なデータ取得のためのリクエストをすることになります。

BFFの文脈だと、API Gatewayの役割の中で焦点が当たるのは主にAPIコンポジションだと思います。BFFが返すべきAPIコンポジションの結果はクライアントごとに大きく異なるからです。次はBFFがどのような考えに基づいて開発されたのかについて説明します。

BFFの歴史的背景

Microservices Patterns によると、BFFは当時SoundCloud社に所属していたPhil Calçadoたちによって考案されました。(BFFという命名はNick Fisherが行ったようです。)SoundCloud社ではデスクトップのWebとモバイルで1つAPI Gatewayを共有していました。API Gatewayがあるものの、デスクトップのWebとモバイルの両方で使える汎用的な作りだったこともあり、クライアントは大量にリクエストする必要があり、パフォーマンスの問題がありました。その問題を解決するため、クライアントごとに専用のAPI Gateway(BFF)を用意することを考案しました。BFFはクライアントが必要とするデータを返すため、クライアントはリクエスト数が減り、コードがシンプルになったようです。

SoundCloud社の事例の詳細は Phil Calçadoの”The Back-end for Front-end Pattern (BFF)”という記事を参照ください。

BFFのメリット

BFFを採用することでいくつかメリットがあります。上に書いたように、クライアントのリクエスト数を減らすことできます。また、それぞれのBFFを独立してスケールさせることもできます。例えば、デスクトップのWebとモバイルのアクセス数に大きな乖離がある場合でも、柔軟に対応できます。
BFFは対象のクライアントが必要とする形式のデータを返すため、クライアントでAPIコンポジションする必要はなくなります。そのため、クライアントのコードはシンプルになるでしょう。

BFFのデメリット

各クライアントが必要とするデータの中に共通している箇所がある場合、BFFごとに処理が重複してしまうというデメリットがあります。これはBFFというよりマイクロサービスを開発していると発生する事象だと思います。

APIコンポジションを実装する上の注意点

外部からのリクエストはBFFを経由することになります。バックエンドのマイクロサービスの処理がいくら速くてもBFFの処理が遅ければ、クライアントのユーザビリティを低下させます。そのため、BFFはマイクロサービスに対して非同期で並列にリクエストした方がよいです。

また、一部のレスポンスが長時間返ってこないケースや、リトライしても一部のリクエストが失敗するケースを考慮する必要があります。「マイクロサービスAがn秒以内にレスポンスを返さなかったら、マイクロサービスA以外のレスポンスを組み合わせてクライアントに返す」などの仕様を決めておくとよいでしょう。このようなケースを考慮すべきなのはBFFに限った話ではありませんが、BFFはよりクライアントに近いので考慮が漏れた際、ユーザに直接的な影響をもたらしてしまいます。

参考

Software engineer