Amazon API Gatewayのパフォーマンスオプションを理解する

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

ども、大瀧です。
APIを統合するAWSの新サービス、API Gatewayを社内総出 *1で触っています。今回はAPI Gatewayのパフォーマンスに関する仕組みと設定をご紹介します。

API Gatewayのロケーション

API GatewayはAPIサーバーのリバースプロキシとして動作するサービスのため、API Gateway自身がボトルネックになるようなアーキテクチャは望ましくありません。API Gatewayを実際に触っていると端々に"CloudFront"というキーワードが見かけられ、ForumでAWSの中の人がさらりと"API GatewayのバックエンドはCloudFrontを活用している"と公言している *2ので、API GatewayのベースアーキテクチャとしてCloudFrontのスケーラビリティが得られる、と考えて良さそうです。

CloudFrontは、世界数十カ所のエッジロケーションと呼ばれるデータセンターで提供され、DNSレイテンシーレコードによりクライアントの最寄りのエッジロケーションに自動で接続されるようになっています。API Gatewayの場合はどうでしょうか。API Gatewayは現在、バージニア北部、オレゴン、アイルランドの3リージョンで展開とAWS公式ブログにありますが、実際に日本からAPI Invoke URLにアクセスすると、3リージョンで作った全てのAPI Gatewayで以下のようにカリフォルニアのエッジロケーションのDNSレコードが返ってきます。

バージニア北部リージョンのInvoke URL

$ host XXXXXXXXXX.execute-api.us-east-1.amazonaws.com
XXXXXXXXXX.execute-api.us-east-1.amazonaws.com has address 54.192.117.77
XXXXXXXXXX.execute-api.us-east-1.amazonaws.com has address 54.192.117.60
  :
$ host 54.192.117.77
77.117.192.54.in-addr.arpa domain name pointer server-54-192-117-77.sfo9.r.cloudfront.net.
$

オレゴンリージョンのInvoke URL

$ host YYYYYYYYYY.execute-api.us-west-2.amazonaws.com
YYYYYYYYYY.execute-api.us-west-2.amazonaws.com has address 54.230.144.160
YYYYYYYYYY.execute-api.us-west-2.amazonaws.com has address 54.230.145.154
  :
$ host 54.230.144.160
160.144.230.54.in-addr.arpa domain name pointer server-54-230-144-160.sfo4.r.cloudfront.net.
$

アイルランドリージョンのInvoke URL

$ host ZZZZZZZZZZ.execute-api.eu-west-1.amazonaws.com
ZZZZZZZZZZ.execute-api.eu-west-1.amazonaws.com has address 54.192.144.151
ZZZZZZZZZZ.execute-api.eu-west-1.amazonaws.com has address 216.137.36.69
  :
$ host 54.192.144.151
151.144.192.54.in-addr.arpa domain name pointer server-54-192-144-151.sfo4.r.cloudfront.net.

この挙動は、CloudFrontのDistributionでPrice ClassをUse Only US and Europeに設定する場合と同じだったりします(日本からの最寄りのエッジロケーションが、恐らく太平洋ケーブルを介したカリフォルニアなのでしょう)。ですので、API GatewayのAPIを作成するリージョンは、パフォーマンスの面ではあまり大きな影響はないかもしれません。また、東京リージョンに展開されるときはCloudFrontのPrice Classの区分にあわせてアジア3リージョンに同時展開されるのではないでしょうか。

ちなみに、現時点での日本からのレイテンシーは概ね100ms超程度ですので、パフォーマンスが要求される用途でAPI Gatewayを利用するのは厳しいかもしれません。Endpoint URL(API Gatewayのオリジン)が日本だとさらに太平洋を往復することにもなります。

また、CloudFrontを利用しているということから、現時点ではAPI GatewayにVPC関連の設定は一切見当たりません。VPC内にInvoke URLが設定できるとオンプレミスからVPN/Direct Connectで接続する社内向けAPIにも活用できそうなので、その辺りは今後のアップデートに期待しましょう。

APIキャッシュ

API Gatewayのパフォーマンスオプションの一つとして、APIキャッシュが利用できます。その名の通り、Endpoint URLからのレスポンスをAPI Gatewayでキャッシュし、2回目以降の同じリクエストに対してキャッシュをクライアントに返送する仕組みです。キャッシュ設定は、キャッシュ容量とTTL(キャッシュ期限)の2つがあります。キャッシュ容量に応じて課金が発生することと、TTLは先にキャッシュ容量を設定、反映させて初めて設定画面が出るようになることに注意しましょう。

キャッシュ容量の設定画面

Stageの設定画面の[Settings]タブにあります。[Enable API cache]のチェックをオンにし、[Cache capacity]からキャッシュ容量を選択、[Save Changes]ボタンで決定します。

apigw-perf01

しばらく待ち、[Cache status]がAVAILABLEになったらOKです。

apigw-perf02

TTLは、Stageのツリーを展開してMethodをクリックしたメソッドの設定画面の[Cache]タブにあります。

apigw-perf03

既定で300秒(5分)です。キャッシュが効いているかどうかは、CloudWatchメトリクスで確認します。API GatewayのCloudWatchメトリクスは既定で無効なのでStageの設定画面の[Settings]タブで有効化しましょう。

apigw-perf04

CloudWatchでは、API GatewayのメトリクスはカスタムメトリクスのApiGatewayネームスペース(最近Backplaneネームスペースから変更されました)として確認できます。

apigw-perf05

こんな感じで、CacheHitCountCacheMissCountでヒット率を比較します。

apigw-perf06

今回は画像だとちょっと読み取りづらいですが、ひたすら同じInvoke URLにリクエストを送ったのでCacheMissCountが5分間隔で1、その他は全てCacheHitCountとしっかりキャッシュが効いていることが見て取れました。

なお、CloudFrontでのキャッシュヒット確認の常套手段であるレスポンスヘッダのX-Cacheは、API Gatewayでは常にMiss from cloudfrontになるため判別手段としては利用できません。

スロットリング

もう一つのパフォーマンスオプションとしてスロットリングがあります。API GatewayのStage毎に同時アクセス数 *3を制限する機能です。トークンバケットアルゴリズムに基づく、「バースト上限(Burst Limit)」と「レート(Rate)」の2つの設定を組み合わせます。ドキュメントには既定でどちらも1RPSが設定されるとあるのですが、実際に試すともう少しアクセスが許容されるので定かではないです。

どちらかの制限を超えるとレスポンスヘッダが429 Too Many Requests、レスポンスボディのmessagenullになります。

設定は、Stage画面の[Settings]タブの[Throttling Settings]にあります。(以下は10RPS/10RPSで設定した例)

apigw-perf07

ちなみに、動作確認のためにabhttperfsiegeといったベンチマークツールを利用しようとしたのですが、API GatewayのSSL/TLSハンドシェイクがTLSv1.2を強要するようで、軒並みハンドシェイクに失敗しエラーになってしまいました。フォーラムでも報告があります。これらのツールで上手くアクセスできるオプションを知っている方がいれば教えてください!で、今回はcurlを連続実行するシェルスクリプトを組んで試してみました。

#!/bin/bash

NUM=1
while :
do
  if [ $NUM -gt 100 ]; then
    break;
  fi
  (curl https://XXXXXXXXXX.execute-api.us-east-1.amazonaws.com/MyTestStage/greet; echo)&
  NUM=$((NUM + 1))
done

今回はバースト上限が10なので、多めの100アクセスでどうなるかの実験です。

$ ./curls.bash
{"message":"Hello from AWS Lambda!"}{"message":"Hello from AWS Lambda!"}
{"message":"Hello from AWS Lambda!"}
{"message":"Hello from AWS Lambda!"}
  :
{"message": "null"}
  :

時折{"message": "null"}が返ってくる感じで、制限がかかっている様子がわかります。素朴な実装ですが、スクリプトを少し変更し&を取ってシーケンシャルなアクセスにしてみたり、ループの合間にsleep 1を挟んでリクエスト間隔を調整すると制限の特性が見えてくると思います。

なお、今回は前述のキャッシュ設定と組み合わせてスロットリングを試してみました。様子としては先にスロットリングの制限がかかって、許可されるとキャッシュ有無が判定されるロジックのようです。本来、スロットリングはキャッシュ元を保護するための仕組みだと思うので、判定順が逆でもいいのかなぁと思ったりしました。

また、Integration TypeがLambda Functionの場合リクエストのタイミングで毎回Lambdaの起動がキックされるため、負荷テストの計測が難しい場合もあると思います。そういったときには今回のキャッシュ設定を有効にすると良いでしょう(さっきと言っていることがずれてますがw)。

まとめ

API Gatewayのロケーションの分析とパフォーマンスに関する2つのオプションをご紹介しました。いずれも、API Gatewayの目的の一つであるAPIの安定運用に役立つオプションであることがご理解いただけたのではないでしょうか。

参考URL

脚注

  1. ちょっと誇大表現
  2. AWS Developer Forums: Custom Domains: Pricing the same as ...
  3. 厳密にはRPS(Requests per Second)