こんにちは、システム開発事業部の加藤です
CloudFrontのデフォルト設定では60秒でタイムアウトするようになっています
この制限の挙動について検証しました
概要
CloudFrontのデフォルト設定では60秒でタイムアウトするようになっています
この制限の挙動について検証しました
検証で利用した構成
EC2とCloudFrontを構築
EC2
- EC2(AL2023) + Apache + PHP-FPM + PHP
- パブリックサブネットに配置
- Apacheのタイムアウトを60秒以上に設定する
- PHPのタイムアウトを60秒以上に設定する
- PHPの出力バッファリングを無効(リアルタイムで出力する動きの再現のため)
1# php.iniを変更
2output_buffering = 0
- Apacheでデータをすぐにクライアントにデータを返すように設定(php-fpmの利用の場合)
1# httpd.confを変更
2<Proxy unix:/run/php-fpm/www.sock|fcgi://localhost>
3 ProxySet flushpackets=on timeout=300
4</Proxy>
CloudFront
オリジンのタイムアウト時間の設定を最大値にする
検証シナリオ
CloudFront経由でEC2に接続した時にEC2から60秒以上レスポンスがない場合
結果
タイムアウトして接続できない
オリジンサーバー(EC2)からCloudFrontに対して60秒以上レスポンスがない場合はタイムアウトする
検証内容
実行したスクリプトは以下
1<?php
2// スクリプトが60秒以上の遅延
3sleep(65); // 65秒間スリープ
4echo "Response after 65 seconds";
5?>
EC2に直接アクセスして実行した場合
レスポンスが帰ってくることを確認
1$ curl http://ec2-52-199-123-36.ap-northeast-1.compute.amazonaws.com/cloudfront-test/no-response.php
2
3Response after 65 seconds
CloudFront経由でのアクセスの場合
タイムアウトする
1$ curl https://d1zg773tvuk57c.cloudfront.net/cloudfront-test/no-response.php
2
3<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
4<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
5<TITLE>ERROR: The request could not be satisfied</TITLE>
6</HEAD><BODY>
7<H1>504 ERROR</H1>
8<H2>The request could not be satisfied.</H2>
9<HR noshade size="1px">
10CloudFront attempted to establish a connection with the origin, but either the attempt failed or the origin closed the connection.
11We can't connect to the server for this app or website at this time. There might be too much traffic or a configuration error. Try again later, or contact the app or website owner.
12<BR clear="all">
13If you provide content to customers through CloudFront, you can find steps to troubleshoot and help prevent this error by reviewing the CloudFront documentation.
14<BR clear="all">
15<HR noshade size="1px">
16<PRE>
17Generated by cloudfront (CloudFront)
18Request ID: Il3-xdnBXHFOQ-95GmGm4Nyb5FpXRMiNqoVHIAaUFyYnlQWPK0ZcYg==
19</PRE>
20<ADDRESS>
21</ADDRESS>
22</BODY></HTML>%
Cloudfront経由でEC2で ファイルをアップロードした時にアップロードに60秒以上時間がかかるとどうなるか (アップロードトラフィックが流れてる時にどうなるか)
結果
問題なし、アップロード可能
継続的にCloudFrontからオリジンサーバーに対して、リクエストデータが流れている状況では、タイムアウトを発生させずに処理を継続
検証した内容
実行したスクリプトは以下
1<?php
2// アップロードされたファイルを保存
3if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_FILES['file'])) {
4 if ($_FILES['file']['error'] !== UPLOAD_ERR_OK) {
5 echo "Failed to upload file with error code: " . $_FILES['file']['error'];
6 exit;
7 }
8
9 $uploadDir = '/var/www/html/uploads/';
10 $uploadFile = $uploadDir . basename($_FILES['file']['name']);
11 if (move_uploaded_file($_FILES['file']['tmp_name'], $uploadFile)) {
12 echo "Upload complete";
13 } else {
14 echo "Failed to move uploaded file";
15 }
16} else {
17 echo "No file upload";
18}
19?>
EC2に直接の場合
1$ curl --limit-rate 1m -w "Time: %{time_total}s\n" -X POST -F file=@/Users/ryota/Desktop/100MB.jpg http://ec2-52-199-123-36.ap-northeast-1.compute.amazonaws.com/cloudfront-test/upload-file-over-time.php
2
3Upload completedTime: 100.092001s
CloudFront経由の場合
問題なし
1$ curl --limit-rate 1m -w "Time: %{time_total}s\n" -X POST -F file=@/Users/ryota/Desktop/100MB.jpg https://d1zg773tvuk57c.cloudfront.net/cloudfront-test/upload-file-over-time.php
2
3Upload completedTime: 100.009124s
CloudFront経由でEC2で 接続した時にEC2から30秒ごとレスポンスがある場合
結果
問題なし
オリジンサーバーから、CloudFrontに対してレスポンスデータが流れている状況では、タイムアウトを発生させずに処理を継続
最後のレスポンスから60秒以上レスポンスがない場合はタイムアウトする
検証内容
実行したスクリプトは以下
1<?php
2// 無限ループで30秒ごとにレスポンス
3// 2分経ったらタイムアウト
4$time = 0;
5while (true) {
6 echo "response at " . date("H:i:s") . "\n";
7 ob_flush();
8 flush();
9 sleep(30);
10 $time += 30;
11 if ($time > 120) {
12 break;
13 }
14}
15?>
EC2に直接アクセス
1$ curl http://ec2-52-199-123-36.ap-northeast-1.compute.amazonaws.com/cloudfront-test/response-every-30sec.php
2
3response at 0 seconds
4response at 30 seconds
5response at 60 seconds
6response at 90 seconds
7response at 120 seconds
CloudFront経由の場合
問題なし
1 $ curl https://d1zg773tvuk57c.cloudfront.net/cloudfront-test/response-every-30sec.php
2
3response at 0 seconds
4response at 30 seconds
5response at 60 seconds
6response at 90 seconds
7response at 120 seconds
2分経ったら60秒以上の遅延を挟むように変更
1<?php
2// 無限ループで30秒ごとにレスポンス
3// 2分経ったら、61秒間の遅延を挟んで終了
4$time = 0;
5while (true) {
6 echo "response at " . $time . " seconds\n";
7 ob_flush();
8 flush();
9 sleep(30);
10 $time += 30;
11 if ($time === 120) {
12 sleep(61);
13 echo "Response after 61 seconds";
14 break;
15 }
16}
17?>
EC2に直接
最後のレスポンスまで出力
1$ curl http://ec2-52-199-123-36.ap-northeast-1.compute.amazonaws.com/cloudfront-test/response-every-30sec.php
2
3response at 0 seconds
4response at 30 seconds
5response at 60 seconds
6response at 90 seconds
7Response after 61 seconds
CloudFront経由の場合
最後のレスポンスから60秒以上レスポンスがない場合は切られる
1 $ curl https://d1zg773tvuk57c.cloudfront.net/cloudfront-test/response-every-30sec.php
2
3response at 0 seconds
4response at 30 seconds
5response at 60 seconds
6response at 90 seconds
7
CloudFront経由でEC2で 60秒以上時間がかかるファイルダウンロードの場合
結果
問題なし、ダウンロードできる
検証内容
実行したスクリプトは以下
1<?php
2$filePath = "/var/www/html/uploads/100MB.jpg";
3
4if (!file_exists($filePath)) {
5 die('File not found.');
6}
7
8$fileSize = filesize($filePath);
9
10header('Content-Type: image/jpeg');
11header('Content-Length: ' . $fileSize);
12
13// 1秒ごとに1MBずつ出力
14$handle = fopen($filePath, 'rb');
15$chunkSize = 1024 * 1024;
16while (!feof($handle)) {
17 echo fread($handle, $chunkSize);
18 flush();
19 sleep(1); // 1秒遅延
20}
21
22fclose($handle);
23exit;
24?>
25
26
EC2から直接
1$ curl http://ec2-52-199-123-36.ap-northeast-1.compute.amazonaws.com/cloudfront-test/download-file-over-time.php -o 100MB.jpg
2
3 % Total % Received % Xferd Average Speed Time Time Time Current
4 Dload Upload Total Spent Left Speed
5100 100M 0 100M 0 0 799k 0 --:--:-- 0:02:08 --:--:-- 79286
CloudFront経由
1分以上かかっているが、ダウンロードできている、問題なし
1$ curl https://d1zg773tvuk57c.cloudfront.net/cloudfront-test/download-file-over-time.php -o 100MB.jpg
2
3 % Total % Received % Xferd Average Speed Time Time Time Current
4 Dload Upload Total Spent Left Speed
5100 100M 0 100M 0 0 993k 0 --:--:-- 0:01:43 --:--:-- 762k
まとめ
オリジンサーバーとCloudFront間で60秒間以内にデータが流れている場合は、タイムアウトしないことが確認できました