[アップデート]CloudFrontオリジンフェイルオーバー時のタイムアウト判定条件をカスタマイズできるようになりました!

CloudFrontはオリジングループを構成することでオリジンを冗長化できます。 今回のアップデートにより、フェイルオーバー判定のタイムアウト条件をカスタマイズできるようになりました。 動画ストリーミング配信など、より素早い切り替えが必要なケースにも柔軟に対応できます。
2020.06.07

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

CloudFrontでは、オリジンをプライバリ・セカンダリのグループで定義し、障害時にセカンダリへフェイルオーバーする機能が備わっています。

今回のアップデートにより、フェイルオーバー判定に利用するタイムアウト条件を細かく設定できるようになりました。

Amazon CloudFront enables configurable origin connection attempts and origin connection timeouts

実際に、この動作を確認してみます。

CloudFront オリジンフェイルオーバー機能について

CloudFrontのオリジンフェイルオーバー機能は、プライマリ・セカンダリをグループ指定すると

  • エラー系HTTPステータスコード
  • 接続障害

発生時にプライマリからセカンダリにフェイルオーバーするというものです。

発生条件

タイプ オリジン制限 条件
エラー系HTTPステータスコード - 指定したHTTPステータスコードを受け取る
オリジンへの接続がタイムアウト - 指定したタイムアウト(1s〜10s)が指定した回数(1〜3)発生
オリジンからのレスポンスがタイムアウト カスタムオリジンのみ 指定したタイムアウト(1s〜60s)が指定した回数(1〜3)発生
Keep-alive接続がタイムアウト カスタムオリジンのみ 指定したタイムアウトが発生

フェイルオーバーのフロー

画像は公式ドキュメントから

アップデート内容

今回のアップデートでは、

  • オリジン接続時のタイムアウト時間
  • 試行回数

をカスタマイズできるようになりました。

結果、上記表の

  • オリジンへの接続がタイムアウト
  • オリジンからのレスポンスがタイムアウト

をより細かく指定できるようになりました。

やってみた

  • プライマリにはEC2(Flask)のカスタムオリジン
  • セカンダリにはS3

を利用し、フェイルオーバーを確認します。

オリジンの作成

プライマリ・セカンダリのオリジンを作成します。

カスタムオリジンの場合、と非カスタムオリジンで設定可能な項目箱となります。

カスタムオリジン

非カスタムオリジン

オリジングループの作成

Origin Groupの作成画面に移動し、追加したオリジンをプライマリ・セカンダリに登録します。

また、「Failover criteria」にはフェイルオーバー判定に利用したい HTTP ステータスコードを指定します。

Behaviorとオリジングループの紐付け

Behaviorの「Origin or Origin Group」の設定項目に、先程作成したオリジングループを指定します。

サーバープログラム

今回は、サーバー側で特定のHTTPステータスコードを返したり、ブロッキングしたかったので、Flaskで簡単なアプリを書きました。

/数字 にアクセスすると、そのHTTPステータスコードを返すメソッドを用意し、/block にアクセスすると、300秒後にHTTP 200ステータスを返します。

import time
from flask import Flask, abort
app = Flask(__name__)

@app.route('/200')
def s200():
    return 'ok'

@app.route('/403')
def s403():
    abort(403)

@app.route('/404')
def s404():
    abort(404)

@app.route('/500')
def s500():
    abort(500)

@app.route('/502')
def s502():
    abort(502)

@app.route('/503')
def s503():
    abort(503)

@app.route('/504')
def s504():
    abort(504)

@app.route('/block')
def block():
    time.sleep(300)
    return 'block'

if __name__ == '__main__':
      app.run(host='0.0.0.0', port=80)

動作確認

  1. HTTP ステータスコードのフェイルオーバー
  2. オリジンへの接続がタイムアウト
  3. レスポンスタイムアウトのフェイルオーバー

をそれぞれ確認します。

フェイルオーバー判定方法

レスポンスヘッダーの Serverから

  • プライマリ(Server: Werkzeug/1.0.1 Python/3.7.6)
  • セカンダリ(Server: AmazonS3)

を判定します。

1. HTTP ステータスコードのフェイルオーバー

プライマリからのレスポンスのHTTPステータスコードがフェイルオーバー対象の場合、直ちにセカンダリにリクエストし直します。

プライマリオリジンへ再リクエストしないため、試行回数(Origin Connection Attempts)の設定は関係ありません。

そのため、プライマリオリジンへのアクセスログは1回分です。

正常系HTTPステータスコード(200)

まずは正常系のレスポンスヘッダーです

$ curl -I dummy.cloudfront.net/200
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 13
Connection: keep-alive
Server: Werkzeug/1.0.1 Python/3.7.6
Date: Sat, 06 Jun 2020 20:22:38 GMT
X-Cache: Miss from cloudfront
Via: 1.1 04599a8a3c6eb66f23e5ae02d1ec4cf2.cloudfront.net (CloudFront)
X-Amz-Cf-Pop: FRA6-C1
X-Amz-Cf-Id: XGtd95MGV_kreMWPTF6ldgaGmGN4hVY_t5nol1dyhhbQTneFE-d0Eg==

EC2からのレスポンスです。

対応するオリジンサーバーアクセスログ

1.2.3.4 - - [06/Jun/2020 20:22:38] "HEAD /200 HTTP/1.1" 200 -

200ステータスを返しています。

異常系HTTPステータスコード(500)

次に異常系のレスポンスヘッダーです

$ curl -I dummy.cloudfront.net/500
HTTP/1.1 403 Forbidden
Content-Type: application/xml
Connection: keep-alive
Date: Sat, 06 Jun 2020 20:22:23 GMT
Server: AmazonS3
X-Cache: Error from cloudfront
Via: 1.1 2ef0748a2a8fca13fd6065b6b046c33c.cloudfront.net (CloudFront)
X-Amz-Cf-Pop: FRA6-C1
X-Amz-Cf-Id: 9FC9EKNpOirgMArN-e6DHsWKfakIojA65rZUS01Fq1loWAYV7xLLIw==

EC2からS3にフェイルオーバーしています。

対応するオリジンサーバーアクセスログ

1.2.3.4 - - [06/Jun/2020 20:22:23] "HEAD /500 HTTP/1.1" 500 -

500ステータスを返しています。

2. オリジンへの接続がタイムアウト

CloudFrontからオリジンへの通信で、指定したタイムアウト(1s〜10s)が指定した回数(1〜3)発生すると、フェイルオーバーします。

デフォルトでは

  • タイムアウト(Origin Connection Timeout)が10s
  • 試行回数(Origin Connection Attempts)が3回

のため、フェイルオーバー発生まで 10x3=30秒かかります。

CloudFrontからのHTTPアクセスをブロックして、意図的にタイムアウトを発生させます。

$ time curl -I dummy.cloudfront.net/200
HTTP/1.1 403 Forbidden
Content-Type: application/xml
Connection: keep-alive
Date: Sat, 06 Jun 2020 18:52:13 GMT
Server: AmazonS3
X-Cache: Error from cloudfront
Via: 1.1 d3039ad83798b26ecb9f9f1e666afe27.cloudfront.net (CloudFront)
X-Amz-Cf-Pop: FRA6-C1
X-Amz-Cf-Id: BYylaraUA7aC3eOJBdNsy_11vqiLn3ITPXZse1if6Rq1qcIwS-GqjA==


real    0m30.247s
user    0m0.005s
sys     0m0.005s

EC2からS3にフェイルオーバーしています。

また、リクエストの処理に30秒かかっています。

Originの設定画面で、試行回数(Origin Connection Attempts)を3回から2回に変更してみます。

$ time curl -I dummy.cloudfront.net/200
HTTP/1.1 403 Forbidden
Content-Type: application/xml
Connection: keep-alive
Date: Sat, 06 Jun 2020 18:57:02 GMT
Server: AmazonS3
X-Cache: Error from cloudfront
Via: 1.1 89c822bb1ce1445a7be6d1057088cfbf.cloudfront.net (CloudFront)
X-Amz-Cf-Pop: FRA6-C1
X-Amz-Cf-Id: T3VcoQEjcjgO_JCkP4K_DQRAR1IjPdOfavflFkHjlnUV3Intadt7Cg==


real    0m20.238s
user    0m0.003s
sys     0m0.006s

リクエストは、タイムアウト10s x 2回 = 20秒に減っています。

3. レスポンスタイムアウトのフェイルオーバー

CloudFrontからオリジンへ接続確立後のレスポンス処理で、指定したタイムアウト(1s〜10s)が指定した回数(1〜3)発生すると、フェイルオーバーします。

デフォルトは

  • タイムアウト(Origin Response Timeout)が30s
  • 試行回数(Origin Connection Attempts)が3回

のため、フェイルオーバー発生まで 30x3=90秒かかります。

300秒ブロックするパスを用意し

@app.route('/block')
def block():
    time.sleep(300)
    return 'block'

意図的にタイムアウトを発生させます。

$ time curl -I dummy.cloudfront.net/block
HTTP/1.1 403 Forbidden
Content-Type: application/xml
Connection: keep-alive
Date: Sat, 06 Jun 2020 18:19:20 GMT
Server: AmazonS3
X-Cache: Error from cloudfront
Via: 1.1 5076c8187f430eebe5e26fc594d6125a.cloudfront.net (CloudFront)
X-Amz-Cf-Pop: FRA2-C1
X-Amz-Cf-Id: 7zV5QYbWLteantOJTgZCMXo5avA04-wtwfLxhs8gzwXbm6Doq0EBWQ==


real    1m30.317s
user    0m0.003s
sys     0m0.009s

レスポンスを受け取るまで90秒かかり、S3にフェイルオーバーしています。

EC2サーバーには、CloudFrontで設定したタイムアウト(30秒)間隔で、試行回数(3回)のリクエストが来ています。

1.2.3.4 - - [06/Jun/2020 18:22:49] "HEAD /block HTTP/1.1" 200 -
1.2.3.4 - - [06/Jun/2020 18:23:19] "HEAD /block HTTP/1.1" 200 -
1.2.3.4 - - [06/Jun/2020 18:23:49] "HEAD /block HTTP/1.1" 200 -

CloudFrontからのレスポンス時刻は「Date: Sat, 06 Jun 2020 18:19:20 GMT」で、プライマリオリジンのアクセスログは「06/Jun/2020 18:22:49」です。

  • 18:17:49 頃にプライマリオリジンにリクエスト
  • 30秒後にタイムアウト、再度リクエストを3回繰り返す
  • 初回リクエストの90秒後の18:19:20にセカンダリオリジンにリクエストし、その時のレスポンスが「Date: Sat, 06 Jun 2020 18:19:20 GMT」
  • 18:17:49 頃のプライマリオリジンへのリクエストの300秒後のレスポンスが「06/Jun/2020 18:22:49」

というようなことが起きていたと考えられます。

次に

  • タイムアウト(Origin Response Timeout):10s
  • 試行回数(Origin Connection Attempts):2回

に変更してみます。

$ time curl -I dummy.cloudfront.net/block
HTTP/1.1 403 Forbidden
Content-Type: application/xml
Connection: keep-alive
Date: Sat, 06 Jun 2020 18:32:59 GMT
Server: AmazonS3
X-Cache: Error from cloudfront
Via: 1.1 adb1b226e6965f6206603ba087bd4a0a.cloudfront.net (CloudFront)
X-Amz-Cf-Pop: FRA2-C1
X-Amz-Cf-Id: xux6ssGdyu4Q90q6rQEIAw1bkk0XYXk18WSE_2neuxCZHtM7Cu8zxw==


real    0m20.229s
user    0m0.003s
sys     0m0.005s

レスポンスを受け取るまで20秒かかり、S3にフェイルオーバーしています。

サーバーには、CloudFrontで設定したタイムアウト(10秒)間隔で、試行回数(2回)のリクエストが来ています。

1.2.3.4 - - [06/Jun/2020 18:37:39] "HEAD /block HTTP/1.1" 200 -
1.2.3.4 - - [06/Jun/2020 18:37:48] "HEAD /block HTTP/1.1" 200 -
  • 18:32:39 頃にプライマリオリジンにリクエスト
  • 10秒後にタイムアウト、再度リクエストを2回繰り返す
  • 初回リクエストの20秒後の18:32:59にセカンダリオリジンにリクエストし、その時のレスポンスが「Date: Sat, 06 Jun 2020 18:32:59 GMT」
  • 18:32:39 頃のプライマリオリジンへのリクエストの300秒後のレスポンスが「06/Jun/2020 18:37:39」

というようなことが起きていたと考えられます。

最後に

CloudFront のオリジンフェイルオーバー機能において、フェイルオーバー判定用のタイムアウト条件を細かく制御できるようになりました。

動画ストリーミング配信のように、素早い切り替えが必要なケースでご活用ください。

それでは。

参考