ゲートウェイのタイムアウトを適切に設定することは、専用ゲートウェイの安定性と良好なユーザーエクスペリエンスにとって極めて重要です。不適切な設定は、予期しない接続リセット、リクエストのバックログ、さらには連鎖的な障害を引き起こす可能性があります。このトピックでは、専用ゲートウェイの 2 つのコアなタイムアウトタイプ、アイドル接続タイムアウトとリクエストタイムアウトについて説明します。Java、Go、Alibaba Cloud Elastic Algorithm Service (EAS) SDK のクライアント設定の推奨事項、コードサンプル、および一般的なタイムアウト問題の分析を提供し、より安定した効率的なサービスを構築するのに役立ちます。
背景情報
なぜタイムアウトを設定するのか?
分散システムでは、サービスはしばしば長い呼び出しチェーンを持ちます。どの時点での遅延や障害も、リクエストチェーン全体を遅くしたり、失敗させたりする可能性があります。タイムアウトメカニズムは、これらの問題を解決するのに役立ちます。適切なタイムアウトを設定することで、次のことが可能になります。
リソースの枯渇を防ぐ: クライアントやゲートウェイが応答しないバックエンドサービスを無期限に待機するのを防ぎます。この実践により、接続やスレッドなどのリソースが拘束されるのを避け、連鎖的な障害につながるのを防ぎます。
ユーザーエクスペリエンスの向上: 長く応答しない待機よりも、フェイルファストのアプローチの方が優れています。このアプローチは、ユーザーに即座にフィードバックを提供し、リトライや他のアクションを取ることができます。
システムの安定性を確保する: リソースを迅速に解放することで、タイムアウトは遅いまたは失敗したサービスがシステムリソースを枯渇させるのを防ぎ、システム全体の安定性を保護します。
アイドル接続タイムアウトの設定
アイドル接続タイムアウトは、非アクティブな持続的接続がゲートウェイによって閉じられるまで開いたままにできる最大時間を指定します。この設定は、接続プールを管理し、非アクティブなリソースを解放するために不可欠です。
設定の推奨事項
専用ゲートウェイには、以下の固定アイドル接続タイムアウトがあり、変更することはできません。
サーバーとしてのゲートウェイ (クライアント向き):
600 秒に固定されています。クライアントとゲートウェイ間の接続がこの期間を超えてアイドル状態である場合、ゲートウェイはその接続を閉じます。クライアントとしてのゲートウェイ (モデルサービス向き):
30 秒に固定されています。ゲートウェイとバックエンドモデルサービス間の接続がこの期間を超えてアイドル状態である場合、ゲートウェイはその接続を閉じます。
クライアントのアイドル接続タイムアウトを、専用ゲートウェイのアイドル接続タイムアウトである 600 秒未満の値に設定します。この実践により、クライアントが接続を積極的に管理して閉じるようになり、ゲートウェイがすでに閉じた接続をクライアントが使用しようとしたときに発生するエラーを防ぎます。
次の図は接続パスを示しています。
クライアント設定の例
以下の例は、さまざまなプログラミング言語でクライアントのアイドル接続タイムアウトを管理または設定する方法を示しています。
これらの例は参考用であり、本番環境で直接使用してはなりません。システムのトラフィック、負荷、および使用しているクライアントの特定のバージョンに基づいてパラメーターを設定する必要があります。
Java
Apache HttpClient 4.x を使用する場合: Apache HttpClient の接続マネージャーは、closeIdleConnections() メソッドを定期的に呼び出すことでアイドル接続を管理します。この操作を実行するには、別のスレッドを開始する必要があります。
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.client.config.RequestConfig;
import java.util.concurrent.TimeUnit;
public class HttpClientIdleTimeout {
public static void main(String[] args) throws InterruptedException {
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setDefaultMaxPerRoute(20); // 例: ルートごとの最大接続数
cm.setMaxTotal(100); // 例: 合計最大接続数
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(5000) // 例: 接続タイムアウト 5 秒
.setSocketTimeout(10000) // 例: データ読み取りタイムアウト 10 秒
.build();
try (CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(cm)
.setDefaultRequestConfig(requestConfig)
.build()) {
// アイドル接続を定期的にクリーンアップするためのバックエンドスレッドを開始します
Thread cleanerThread = new Thread(() -> {
try {
while (!Thread.currentThread().isInterrupted()) {
Thread.sleep(5000); // 例: 5 秒ごとにチェック
// 500 秒以上アイドル状態の接続を閉じます (ゲートウェイのアイドルタイムアウト 600 秒未満)
cm.closeIdleConnections(500, TimeUnit.SECONDS);
// 期限切れの接続を閉じます (例: サーバーによって閉じられた接続)
cm.closeExpiredConnections();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 割り込みステータスをリセットします
}
});
cleanerThread.setDaemon(true); // メインスレッドが終了したときに終了するようにデーモンスレッドとして設定します
cleanerThread.start();
// HTTP リクエストを実行します...
// 例: httpClient.execute(new HttpGet("http://your-gateway-url"));
// プログラムがしばらく実行されるのをシミュレートします
Thread.sleep(60000); // 例: 1 分間実行
// クリーナーのスレッドを停止します (実際のアプリケーションでは、アプリケーションのシャットダウン時に正常に停止する必要があります)
cleanerThread.interrupt();
} catch (Exception e) {
e.printStackTrace();
}
}
}Go
Go の net/http パッケージは、Transport 構造体を通じて接続プールを詳細に制御します。IdleConnTimeout の値が 600 秒未満であることを確認してください。
package main
import (
"net/http"
"time"
)
func main() {
// カスタム Transport を作成
tr := &http.Transport{
MaxIdleConns: 100, // アイドル接続の最大数
IdleConnTimeout: 500 * time.Second, // アイドル接続タイムアウト、例: 500 秒 (600 秒未満)
DisableKeepAlives: false, // Keep-Alive を有効にする
}
}EAS SDK (Java)
Alibaba Cloud EAS SDK では、クライアント設定でアイドル接続のクリーンアップを有効にし、アイドル接続タイムアウトを設定できます。
import com.aliyun.openservices.eas.predict.http.PredictClient;
import com.aliyun.openservices.eas.predict.http.HttpConfig;
public class EasSdkTimeoutJava {
public static void main(String[] args) {
// 1. グローバルクライアント設定
HttpConfig httpConfig = new HttpConfig();
// アイドル接続のクリーンアップスイッチを有効化、単位:ミリ秒。クライアントの状況に応じて設定することを推奨します。
httpConfig.setConnectionCleanupInterval(5000);
// アイドル接続タイムアウトをゲートウェイのアイドルタイムアウト 600 秒未満に設定
httpConfig.setIdleConnectionTimeout(500);
PredictClient client = new PredictClient(httpConfig);
client.setEndpoint("your-eas-service-endpoint");
client.setModelName("your-model-name");
// client.setToken("your-token"); // 認証が必要な場合
...
}
}リクエストタイムアウトの設定
リクエストタイムアウトは、TCP 接続の確立、リクエストの送信から完全な応答の受信まで、リクエストのライフサイクル全体をカバーします。これは最も一般的なクライアント側のタイムアウトです。
設定の推奨事項
ビジネスニーズに基づいてリクエストタイムアウトを調整できます。以下の推奨事項は参考用であり、厳密なルールではありません。本番環境では、フォールトトレランス、応答時間、潜在的なネットワークジッターなどの要因を考慮して、ビジネスシナリオに最適な設定を見つける必要があります。
専用ゲートウェイのリクエストタイムアウト設定: サービスのビジネスロジックと予想される処理時間に基づいて、合理的なタイムアウトを設定します。
デフォルト値: 10 分 (600 秒)。
ユーザー定義設定 (現在、Application Load Balancer (ALB) ベースの専用ゲートウェイではサポートされていません): サービス設定ファイルで、
metadata.rpc.keepaliveフィールドを設定することで、特定のサービスのリクエストタイムアウトをカスタマイズできます。ゲートウェイはこの値を読み取り、リクエストタイムアウトとして適用します。詳細については、「メタデータパラメーターの説明」をご参照ください。重要短命な接続は、リクエストタイムアウトとアイドル接続タイムアウトの両方によって制約されます。専用ゲートウェイのアイドル接続タイムアウトは 600 秒に固定されているため、600 秒を超えるリクエストタイムアウトを設定しても効果はありません。10 分を超える長時間実行タスクには、次のいずれかのソリューションを使用できます。
ストリーミング: 大容量ファイルのダウンロードや AI コンテンツ生成などのシナリオ向け。
WebSocket: リアルタイムの双方向通信シナリオ向け。
クライアントのリクエストタイムアウト設定: サーバーがまだリクエストを処理している間にクライアントがタイムアウトする誤ったタイムアウトエラーを避けるために、クライアントのリクエストタイムアウトをサーバーのリクエストタイムアウトよりわずかに長く設定できます。
一般的な推奨事項は
クライアントタイムアウト = サーバータイムアウト + 小さなバッファー (例: 1〜5 秒)です。このバッファーは、わずかなネットワーク遅延やサーバー側の処理時間の変動を考慮します。
次の図は接続パスを示しています。
クライアント設定の例
以下の例は、さまざまなプログラミング言語でクライアント側のリクエストタイムアウトを設定する方法を示しています。
これらの例は参考用であり、本番環境で直接使用してはなりません。システムのトラフィック、負荷、および使用しているクライアントの特定のバージョンに基づいてパラメーターを設定する必要があります。
Java
Apache HttpClient 4.x の使用:
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
public class ApacheHttpClientTimeout {
public static void main(String[] args) {
// 推奨されるクライアントリクエストタイムアウトは、ゲートウェイのリクエストタイムアウト (デフォルトで 600 秒) と同等か、わずかに大きくする必要があります。ここでは 610 秒に設定されています。
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(5000) // 例: 接続タイムアウト、ミリ秒単位
.setSocketTimeout(610000) // データ転送タイムアウト (読み取りタイムアウト)、ミリ秒単位 (610 秒)
.build();
}
}Go
Go の net/http パッケージは、リクエストタイムアウトを設定するいくつかの方法を提供します。最も一般的な方法は、http.Client の Timeout フィールドを設定するか、context.WithTimeout を使用して単一のリクエストのタイムアウトを設定することです。
package main
import (
"context"
"fmt"
"io"
"net/http"
"time"
)
func main() {
// 推奨されるクライアントリクエストタイムアウトは、ゲートウェイのリクエストタイムアウト (デフォルトで 600 秒) と同等か、わずかに大きくする必要があります。ここでは 610 秒に設定されています。
client := &http.Client{
Timeout: 610 * time.Second, // リクエスト全体に対するタイムアウト
}
req, err := http.NewRequest("GET", "http://your-gateway-url", nil)
if err != nil {
fmt.Println("Error creating request:", err)
return
}
// 単一のリクエストに対してより短いタイムアウトを設定することもできます
ctx, cancel := context.WithTimeout(req.Context(), 610*time.Second) // 610 秒
defer cancel()
req = req.WithContext(ctx)
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error sending request:", err)
// タイムアウトエラーかどうかを確認します
if t, ok := err.(interface{ Timeout() bool }); ok && t.Timeout() {
fmt.Println("Request timed out!")
}
return
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error reading response body:", err)
return
}
fmt.Printf("Response Status: %s\n", resp.Status)
fmt.Printf("Response Body: %s\n", body)
}EAS SDK (Java)
Alibaba Cloud EAS SDK では、グローバルクライアント設定またはリクエストレベルで接続タイムアウトと読み取りタイムアウトを設定できます。
import com.aliyun.openservices.eas.predict.http.PredictClient;
import com.aliyun.openservices.eas.predict.http.HttpConfig;
public class EasSdkTimeoutJava {
public static void main(String[] args) {
// 1. グローバルクライアント設定
HttpConfig httpConfig = new HttpConfig();
// 接続タイムアウト
httpConfig.setConnectTimeout(5);
// 推奨されるクライアントリクエストタイムアウトは、ゲートウェイのリクエストタイムアウト (デフォルトで 600 秒) と同等か、わずかに大きくする必要があります。ここでは 610 秒に設定されています。
httpConfig.setReadTimeout(610); // 読み取りタイムアウト
}
}よくある質問
Q: 不適切なアイドル接続タイムアウト設定
シナリオ 1: クライアントのアイドル接続タイムアウトが、専用ゲートウェイのサーバー側のアイドル接続タイムアウトより大きい (クライアントのアイドルタイムアウト > 600 秒)
問題: クライアントは接続がまだ有効であると想定しますが、専用ゲートウェイは非アクティブのためにすでに接続を閉じています。クライアントがこの接続を再利用しようとすると、リクエストは失敗します。
一般的なクライアントエラー:
Connection reset by peerBroken pipejava.net.SocketException: Connection reset(Java)requests.exceptions.ConnectionError: ('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer'))(Python requests)read: connection reset by peer(Go)クライアントは
HTTP 503 Service Unavailableエラーを受け取ることがあります。このエラーは通常、クライアントが閉じた接続を再利用しようとし、ゲートウェイが新しい接続を確立したり、リクエストをバックエンドサービスに時間内に転送したりできない場合に発生します。
シナリオ 2: 専用ゲートウェイのクライアント側のアイドル接続タイムアウトが、モデルサービスのアイドル接続タイムアウトより大きい (モデルサービスのアイドルタイムアウト < 30 秒)
問題: 専用ゲートウェイは接続がまだ有効であると想定しますが、バックエンドのモデルサービスは非アクティブのためにすでに接続を閉じています。ゲートウェイがこの接続を再利用してリクエストを転送しようとすると、接続が壊れていることを発見します。
潜在的な専用ゲートウェイエラー: ゲートウェイのログには、前のセクションで説明したクライアントエラーと同様の接続リセットエラーが表示されます。
潜在的なクライアントエラー: クライアントは通常、専用ゲートウェイから
HTTP 503エラーコードを受け取ります。このエラーは、ゲートウェイがリクエストをバックエンドサービスに転送できなかったことを示します。
Q: 不適切なリクエストタイムアウト設定
シナリオ 1: クライアントのリクエストタイムアウトが専用ゲートウェイのリクエストタイムアウトより短い
問題: クライアントに設定されたリクエストタイムアウトが短すぎます。これにより、クライアントは完全な応答を受け取る前に接続を中止し、ビジネス運用を妨げる頻繁な誤ったタイムアウトエラーを引き起こします。
重要一部のシナリオでは、クライアントがフェイルファスト戦略を実装するために意図的に短いリクエストタイムアウトを設定することがあります。したがって、推奨されるタイムアウト値は参考用であり、特定のニーズに基づいて調整できます。クライアントのタイムアウトは、必ずしもサーバー側のタイムアウトより大きくする必要はありません。このアドバイスは一般的なユースケースに適用されます。特定のビジネスコンテキストに合わせて調整する必要があります。
一般的なクライアントエラー:
クライアントは、次のような独自のタイムアウト例外を頻繁にスローします。
java.net.http.HttpTimeoutException(JavaHttp Client)java.net.SocketTimeoutException: Read timed out(JavaApache HttpClient)requests.exceptions.ReadTimeout(Pythonrequests)context deadline exceeded(Go、context.WithTimeoutまたはClient.Timeoutによってトリガー)
シナリオ 2: 専用ゲートウェイのリクエストタイムアウトが、実際のモデルサービスの処理時間より短い
問題: モデルサービスへのリクエストを転送するために専用ゲートウェイで設定されたタイムアウト (デフォルト 10 分またはカスタム値) が、モデルサービスが実際にリクエストを処理するために必要な時間よりも短いです。その結果、ゲートウェイはモデルサービスが終了する前に待機を停止し、クライアントにタイムアウトエラーを返します。
クライアント側のエラー: クライアントは通常、専用ゲートウェイから
HTTP 504 Gateway Timeoutエラーを受け取ります。このエラーは、ゲートウェイがバックエンドサービスからの応答を待っている間にタイムアウトしたことを示します。モデルサービスが内部タイムアウトをどのように処理し、ゲートウェイにエラーを報告するかに応じて、クライアントはHTTP 502 Bad GatewayまたはHTTP 500 Internal Server Errorエラーを受け取ることもあります。モデルサービスの状態: モデルサービスはまだリクエストを処理している可能性があります。モデルサービスのログにはタイムアウトエラーは表示されませんが、タイムアウト後にゲートウェイがモデルサービスへの接続を閉じた場合、リクエストが中断されたことを示す場合があります。
トラブルシューティングの推奨事項: これらのエラーをトラブルシューティングするには、クライアント、ゲートウェイ、およびモデルサービスのログを確認できます。
クライアントログの確認: クライアントによってスローされた特定の例外タイプとスタックトレースを確認します。
専用ゲートウェイログの確認: ゲートウェイのリクエストログを調べ、失敗したリクエストに関連するエラーコードと転送ステータスに特に注意を払います。
モデルサービスログの確認: ゲートウェイが
5xxエラーコードを返す場合、モデルサービスのログを調べて、内部エラーが発生したか、処理に時間がかかりすぎたかを確認できます。