トラブルシューティングに関するよくある質問 - AWS SDK for Java 2.x

トラブルシューティングに関するよくある質問

アプリケーションで AWS SDK for Java 2.x を使用すると、このトピックに記載されているランタイムエラーが発生する可能性があります。根本原因を見つけてエラーを解決するには、このガイドの提案を参考にしてください。

java.net.SocketException: Connection reset」または「server failed to complete the response」エラーを修正するにはどうすればよいですか?

接続リセットエラーは、リクエストが完了する前に、ホストである AWS のサービス、または仲介者 (NAT ゲートウェイ、プロキシ、ロードバランサーなど) が接続を閉じたことを示しています。多くの原因があるため、ソリューションを見つけるには、接続が閉じられた理由を知る必要があります。通常、以下の理由によって接続が閉じられます。

  • 接続が非アクティブ。 これはストリーミングオペレーションでよく見られる動作です。一定期間データの送受信が行われないため、仲介者が接続がデッドであると判断して切断してしまうことがあります。これを防ぐには、アプリケーションがデータをアクティブにダウンロードまたはアップロードしていることを確認してください。

  • HTTP または SDK クライアントを閉じた。使用中はリソースを閉じないでください。

  • プロキシの設定ミス。設定したプロキシをバイパスして、問題が修正されるかどうかを確認してください。これにより問題が修正された場合、プロキシが何らかの理由で接続を閉じています。特定のプロキシを調べて、接続を閉じている理由を特定します。

問題を特定できない場合は、影響を受けた接続の tcpdump をネットワークのクライアントエッジで実行してみてください (たとえば、制御するプロキシの後など)。

AWS エンドポイントが TCP RST (リセット) を送信していることがわかった場合は、影響を受けるサービスに問い合わせ、リセットが発生している理由を判断できるかどうかを確認してください。問題が発生したときのリクエスト ID とタイムスタンプを提示できるように準備してください。AWS サポートチームは、アプリケーションが送受信しているバイト数とタイミングを正確に示すワイヤログを活用できる場合もあります。

「connection timeout」を修正するにはどうすればよいですか?

接続タイムアウトエラーは、ホストである AWS のサービス、または仲介者 (NAT ゲートウェイ、プロキシ、ロードバランサーなど) が、設定された接続タイムアウト内にサーバーとの新しい接続を確立できなかったことを示します。以下の項目は、この問題の一般的な原因です。

  • 設定された接続タイムアウト値が低すぎる。デフォルトでは、AWS SDK for Java 2.x での接続タイムアウトは 2 秒です。接続タイムアウト値を低く設定しすぎると、このエラーが発生する可能性があります。推奨される接続タイムアウトは、リージョン内呼び出しのみを行う場合は 1 秒、クロスリージョンリクエストを行う場合は 3 秒です。

  • プロキシの設定ミス。設定したプロキシをバイパスして、問題が修正されるかどうかを確認してください。これにより問題が解決した場合、プロキシが接続タイムアウトの原因です。特定のプロキシを調べて、問題が発生した理由を判断します。

問題を特定できない場合は、影響を受けた接続の tcpdump をネットワークのクライアントエッジで実行して (たとえば、制御するプロキシの後など)、ネットワークの問題を調査します。

java.net.SocketTimeoutException: Read timed out」を修正するにはどうすればよいですか?

読み取りタイムアウトエラーは、JVM が基盤となるオペレーティングシステムからデータを読み取ろうとしたものの、SDK を介して設定された時間内にデータが返されなかったことを示します。このエラーは、オペレーティングシステムであるAWS のサービス、または仲介者 (NAT ゲートウェイ、プロキシ、ロードバランサーなど) が JVM が想定する時間内にデータを送信できない場合に発生する可能性があります。多くの原因があるため、ソリューションを見つけるには、データが返されない理由を知る必要があります。

影響を受けた接続の tcpdump をネットワークのクライアントエッジで実行してみてください (たとえば、制御するプロキシの後など)。

AWS エンドポイントが TCP RST (リセット) を送信していることがわかった場合は、影響を受けているサービスにお問い合わせください。問題が発生したときのリクエスト ID とタイムスタンプを提示できるように準備してください。AWS サポートチームは、アプリケーションが送受信しているバイト数とタイミングを正確に示すワイヤログを活用できる場合もあります。

「Unable to execute HTTP request: Timeout waiting for connection from pool」エラーを修正するにはどうすればよいですか?

このエラーは、リクエストが指定された最大時間内にプールから接続を取得できないことを示します。問題をトラブルシューティングするには、SDK クライアント側のメトリクスを有効にして、Amazon CloudWatch にメトリクスを公開することをお勧めします。HTTP メトリクスは、根本原因を絞り込むのに役立ちます。以下の項目は、このエラーの一般的な原因です。

  • 接続リーク。これを調査するには、LeasedConcurrencyAvailableConcurrency、および MaxConcurrency メトリクスを確認します。MaxConcurrency に達するまで LeasedConcurrency が増加するものの、その後減少しない場合、接続リークが発生している可能性があります。リークの一般的な原因は、S3 getObject メソッドなどのストリーミングオペレーションが閉じられていないことです。アプリケーションで、できるだけ早く入力ストリームからすべてのデータを読み取り、その後の入力ストリームを閉じることをお勧めします。次の図は、接続リークの SDK メトリクスの例を示しています。

    接続リークの可能性を示す CloudWatch メトリクスのスクリーンショット。
  • 接続プールの不足。 これは、リクエストレートが高すぎて、設定された接続プールのサイズがリクエストの需要を満たせない場合に発生する可能性があります。デフォルトの接続プールサイズは 50 で、プール内の接続が最大に達すると、HTTP クライアントは接続が利用可能になるまで受信リクエストをキューに入れます。次の図は、接続プールが不足した場合の SDK メトリクスの例を示しています。

    接続プールが不足した場合の CloudWatch メトリクスの例を示すスクリーンショット。

    この問題を軽減するには、次のいずれかのアクションを実行することを検討してください。

    • 接続プールのサイズを大きくする。

    • 取得タイムアウトを長くする。

    • リクエストレートを低くする。

    接続の最大数を増やすことで、クライアントスループットを向上させることができます (ネットワークインターフェイスが既に完全に使用されている場合を除く)。ただし、最終的には、プロセスで使用されるファイル記述子の数に対するオペレーティングシステムの制限に達する可能性があります。ネットワークインターフェイスを既に完全に使用している場合、または接続数をこれ以上増やすことができない場合は、取得タイムアウトを長くしてみてください。これにより、タイムアウトする前にリクエストが接続を取得する時間を追加できます。接続が解放されない場合でも、後続のリクエストはタイムアウトします。

    最初の 2 つのメカニズムを使用して問題を解決できない場合は、次のオプションでリクエストレートを低くします。

    • 大量のトラフィックバーストによってクライアントが過負荷にならないように、リクエストを円滑化する。

    • AWS のサービス への呼び出しをより効率化する。

    • リクエストを送信するホストの数を増やす。

  • I/O スレッドがビジー状態。この原因は、NettyNioAsyncHttpClient で非同期 SDK クライアントを使用している場合にのみ該当します。AvailableConcurrency メトリクスが低くなく、接続がプールで使用可能であることを示しているものの ConcurrencyAcquireDuration が高い場合は、I/O スレッドがリクエストを処理できていない可能性があります。future 完了エグゼキュターとして Runnable:run を渡したり、レスポンスの future 完了チェーン内で時間のかかる処理を実行したりしないよう注意してください。こうした処理は I/O スレッドをブロックする可能性があります。そうでない場合は、 eventLoopGroupBuilder メソッドを使用して I/O スレッドの数を増やすことを検討してください。参考までに、NettyNioAsyncHttpClient インスタンスの I/O スレッドのデフォルト数は、ホストの CPU コア数の 2 倍です。

  • TLS ハンドシェイクのレイテンシーが高い。AvailableConcurrency メトリクスが 0 に近く、LeasedConcurrencyMaxConcurrency より小さい場合は、TLS ハンドシェイクのレイテンシーが高いことが原因である可能性があります。次の図は、TLS ハンドシェイクのレイテンシーが高い場合の SDK メトリクスの例を示しています。

    TLS ハンドシェイクのレイテンシーが高い可能性を示す CloudWatch メトリクスのスクリーンショット。

    CRT に基づいていない Java SDK が提供する HTTP クライアントの場合は、TLS ログを有効にして TLS の問題をトラブルシューティングしてみてください。AWS CRT ベースの HTTP クライアントの場合は、AWS CRT ログを有効にしてみてください。AWS エンドポイントによる TLS ハンドシェイクの実行に時間がかかっていると思われる場合は、影響を受けているサービスにお問い合わせください

NoClassDefFoundErrorNoSuchMethodError、または NoSuchFieldError を修正するにはどうすればよいですか?

NoClassDefFoundError は、ランタイムにクラスをロードできなかったことを示しています。このエラーの最も一般的な原因は 2 つあります。

  • JAR が欠落しているか、クラスパスに間違ったバージョンの JAR があるため、 クラスパスにクラスが存在しない。

  • 静的イニシャライザが例外をスローしたため、 クラスをロードできなかった。

同様に、 NoSuchMethodErrorNoSuchFieldError は通常、JAR バージョンが一致しないために発生します。次の手順を実行することをお勧めします。

  1. 依存関係をチェックして、すべての SDK jar に同じバージョンを使用していることを確認します。クラス、メソッド、またはフィールドが見つからない最も一般的な理由は、新しいクライアントバージョンにアップグレードしても、古い「共有」 SDK 依存関係バージョンを引き続き使用している場合です。新しいクライアントバージョンは、新しい「共有」 SDK 依存関係にしか存在しないクラスを使用しようとする場合があります。mvn dependency:tree または gradle dependencies (Gradle の場合) を実行して、SDK ライブラリのバージョンがすべて一致することを確認します。将来的にこの問題を完全に回避するには、BOM (部品表) を使用して SDK モジュールバージョンを管理することをお勧めします。

    次は、SDK バージョンが混在している例を示しています。

    [INFO] +- software.amazon.awssdk:dynamodb:jar:2.20.00:compile [INFO] | +- software.amazon.awssdk:aws-core:jar:2.13.19:compile [INFO] +- software.amazon.awssdk:netty-nio-client:jar:2.20.00:compile

    dynamodb のバージョンは 2.20.00、aws-core のバージョンは 2.13.19 です。aws-core アーティファクトバージョンも 2.20.00 である必要があります。

  2. ログの早い段階でステートメントをチェックして、静的初期化の失敗が原因でクラスがロードに失敗したかどうかを確認します。クラスが初めてロードに失敗すると、クラスをロードできない理由を示す、より便利な別の例外がスローされる場合があります。この役立つ可能性のある例外は 1 回だけ発生し、後のログステートメントではクラスが見つからないことのみが報告されます。

  3. デプロイプロセスをチェックして、アプリケーションと一緒に必要な JAR ファイルがデプロイされていることを確認します。正しいバージョンで構築しているものの、アプリケーションのクラスパスを作成するプロセスで、必要な依存関係が除外されている可能性があります。

SignatureDoesNotMatch」エラーまたは「The request signature we calculated does not match the signature you provided」エラーを修正するにはどうすればよいですか?

SignatureDoesNotMatch エラーは、AWS SDK for Java によって生成された署名と AWS のサービス によって生成された署名が一致しないことを示します。以下の項目は、潜在的な原因です。

  • プロキシまたは仲介者がリクエストを変更している。たとえば、プロキシまたはロードバランサーは、SDK によって署名されたヘッダー、パス、またはクエリ文字列を変更する場合があります。

  • サービスおよび SDK はそれぞれ、署名する文字列を生成するときにリクエストをエンコードする方法が異なります。

この問題をデバッグするには、SDK のデバッグログを有効にすることをお勧めします。エラーを再現し、SDK が生成した正規リクエストを見つけます。ログでは、正規リクエストには AWS4 Canonical Request: ... というラベルが付けられ、署名する文字列には AWS4 String to sign: ... というラベルが付けられます。

たとえば、本番環境でのみ再現可能であるためにデバッグを有効にできない場合は、エラーが発生したときにリクエストに関する情報をログに記録するロジックをアプリケーションに追加します。その後、その情報を使用して、デバッグログを有効にした統合テストで本番環境外でエラーを再現できます。

署名する正規リクエストと文字列を収集した後、AWS 署名バージョン 4 の仕様と比較して、SDK が署名する文字列を生成した方法に問題がないかどうかを確認します。問題があると思われる場合は、AWS SDK for Java への GitHub バグレポートを作成できます。

問題が見当たらない場合は、SDK の署名文字列と、一部の AWS のサービス が失敗レスポンスの一部として返す署名文字列(Amazon S3 など)を比較できます。これが利用できない場合は、影響を受けるサービスに問い合わせて、生成された正規リクエストと署名文字列を確認して比較する必要があります。比較することで、リクエストを変更した可能性のある仲介者や、サービスとクライアント間のエンコードの違いを特定できます。

リクエストの署名の背景情報については、「AWS Identity and Access Management ユーザーガイド」の「AWS API リクエストの署名」を参照してください。

例 正規リクエスト
PUT /Example-Bucket/Example-Object partNumber=19&uploadId=string amz-sdk-invocation-id:f8c2799d-367c-f024-e8fa-6ad6d0a1afb9 amz-sdk-request:attempt=1; max=4 content-encoding:aws-chunked content-length:51 content-type:application/octet-stream host:xxxxx x-amz-content-sha256:STREAMING-UNSIGNED-PAYLOAD-TRAILER x-amz-date:20240308T034733Z x-amz-decoded-content-length:10 x-amz-sdk-checksum-algorithm:CRC32 x-amz-trailer:x-amz-checksum-crc32
例 署名文字列
AWS4-HMAC-SHA256 20240308T034435Z 20240308/us-east-1/s3/aws4_request 5f20a7604b1ef65dd89c333fd66736fdef9578d11a4f5d22d289597c387dc713

java.lang.IllegalStateException: Connection pool shut down」エラーを修正するにはどうすればよいですか?

このエラーは、基盤となる Apache HTTP 接続プールが閉じられたことを示します。以下の項目は、潜在的な原因です。

  • SDK クライアントが途中で閉じられた。 SDK は、関連付けられたクライアントが閉じられたときにのみ接続プールを閉じます。使用中はリソースを閉じないでください。

  • java.lang.Error がスローされた。OutOfMemoryError などのエラーにより、Apache HTTP 接続プールがシャットダウンされます。ログでエラースタックトレースがないかを調べてください。また、 Throwable または Error をキャッチするものの、エラーが無視されて表面化していない場所についても、コードを確認してください。コードでエラーが報告されない場合は、情報がログに記録されるようにコードを書き換えます。ログに記録された情報は、エラーの根本原因を特定するのに役立ちます。

  • 閉じられた後に DefaultCredentialsProvider#create() から返された認証情報プロバイダーを使用しようとしたDefaultCredentialsProvider#create はシングルトンインスタンスを返すため、閉じられてコードが resolveCredentials メソッドを呼び出すと、キャッシュされた認証情報 (またはトークン) の有効期限が切れた後に例外がスローされます。

    次の例に示すように、DefaultCredentialsProvider が閉じられている場所をコードで確認します。

    • シングルトンインスタンスは、DefaultCredentialsProvider#close(). を呼び出すことで閉じられます。

      DefaultCredentialsProvider defaultCredentialsProvider = DefaultCredentialsProvider.create(); // Singleton instance returned. AwsCredentials credentials = defaultCredentialsProvider.resolveCredentials(); // Make calls to AWS のサービス. defaultCredentialsProvider.close(); // Explicit close. // Make calls to AWS のサービス. // After the credentials expire, either of the following calls eventually results in a "Connection pool shut down" exception. credentials = defaultCredentialsProvider.resolveCredentials(); // Or credentials = DefaultCredentialsProvider.create().resolveCredentials();
    • try-with-resources ブロックで DefaultCredentialsProvider#create() を呼び出します。

      try (DefaultCredentialsProvider defaultCredentialsProvider = DefaultCredentialsProvider.create()) { AwsCredentials credentials = defaultCredentialsProvider.resolveCredentials(); // Make calls to AWS のサービス. } // After the try-with-resources block exits, the singleton DefaultCredentialsProvider is closed. // Make calls to AWS のサービス. DefaultCredentialsProvider defaultCredentialsProvider = DefaultCredentialsProvider.create(); // The closed singleton instance is returned. // If the credentials (or token) has expired, the following call results in the error. AwsCredentials credentials = defaultCredentialsProvider.resolveCredentials();

    コードがシングルトンインスタンスを閉じており、DefaultCredentialsProvider を使用して認証情報を解決する必要がある場合は、DefaultCredentialsProvider.builder().build() を呼び出して新しい非シングルトンインスタンスを作成します。

「Unable to load credentials from any of the providers in the chain AwsCredentialsProviderChain」を修正するにはどうすればよいですか?

このエラーは、AWS SDK for Java 2.x がデフォルトの AWS 認証情報プロバイダーチェーン内の認証情報プロバイダーを通じて有効な認証情報を見つけられなかったことを示します。SDK は特定の順序で認証情報を自動的に検索します。このエラーは、チェーン内のすべてのプロバイダーが有効な認証情報を提供できなかった場合に発生します。

通常、完全なエラーメッセージは次のようになります (読みやすくするために行の末尾とインデントを追加しています)。

Unable to load credentials from any of the providers in the chain AwsCredentialsProviderChain( credentialsProviders=[ SystemPropertyCredentialsProvider(), EnvironmentVariableCredentialsProvider(), WebIdentityTokenCredentialsProvider(), ProfileCredentialsProvider(profileName=default, profileFile=ProfileFile(sections=[])), ContainerCredentialsProvider(), InstanceProfileCredentialsProvider() ]) : [ SystemPropertyCredentialsProvider(): Unable to load credentials from system settings. Access key must be specified either via environment variable (AWS_ACCESS_KEY_ID) or system property (aws.accessKeyId)., EnvironmentVariableCredentialsProvider(): Unable to load credentials from system settings. Access key must be specified either via environment variable (AWS_ACCESS_KEY_ID) or system property (aws.accessKeyId)., WebIdentityTokenCredentialsProvider(): To use web identity tokens, the 'sts' service module must be on the class path., ProfileCredentialsProvider(profileName=default, profileFile=ProfileFile(sections=[])): Profile file contained no credentials for profile 'default': ProfileFile(sections=[]), ContainerCredentialsProvider(): Cannot fetch credentials from container - neither AWS_CONTAINER_CREDENTIALS_FULL_URI or AWS_CONTAINER_CREDENTIALS_RELATIVE_URI environment variables are set., InstanceProfileCredentialsProvider(): Failed to load credentials from IMDS.]

一般的な原因と解決方法

認証情報設定を確認する

デフォルトの認証情報プロバイダーを (認証情報を明示的に設定せずに ServiceClient.create() を呼び出して) 使用する場合、SDK は特定の順序で認証情報を検索します。デフォルトの認証情報プロバイダーチェーンの仕組みを確認し、SDK が検索する認証情報ソースと順序を理解します。

使用する認証情報設定方法が環境で適切に設定されていることを確認します。

Amazon EC2 インスタンスの場合
  • IAM ロールを確認する: IAM ロールがインスタンスにアタッチされていることを確認します。

  • 断続的な IMDS 障害: 断続的な障害 (通常は数百ミリ秒継続) が発生した場合、これは通常、インスタンスメタデータサービス (IMDS) に到達する一時的なネットワークの問題を示します。

    解決方法:

    • デバッグログを有効にして障害のタイミングと頻度を分析する

    • アプリケーションに認証情報関連の障害に対する再試行ロジックを実装することを検討する

    • インスタンスと IMDS エンドポイント間のネットワーク接続の問題を確認する

コンテナ環境の場合

タスクロール (Amazon ECS) またはサービスアカウント (Amazon EKS) が設定され、必要な環境変数が設定されていることを確認します。

ローカル開発の場合

環境変数、認証情報ファイル、または IAM Identity Center が設定されていることを確認します。

ウェブ ID フェデレーションの場合
  • 設定を検証する: ウェブ ID トークンファイルが存在し、必要な環境変数が設定されていることを確認します。

  • STS モジュールの依存関係がない: エラー To use web identity tokens, the 'sts' service module must be on the class path が表示された場合は、STS モジュールを依存関係として追加する必要があります。これは、Amazon EKS Pod Identity または他のウェブ ID トークン認証を使用する場合に一般的です。

    解決方法: STS モジュールをプロジェクトの依存関係に追加します。

    • <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>sts</artifactId> </dependency>

      一部のサービスでは、aws-query-protocol 依存関係も必要になる場合があります。

      <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>aws-query-protocol</artifactId> </dependency>

ネットワークまたはプロキシの接続の問題

認証情報プロバイダーチェーンに Connection refused エラーが表示される場合、これは通常、SDK がAWS エンドポイントに到達しようとしたときにネットワーク接続の問題が発生したことを示します。

解決方法:

  • プロキシサーバーを使用している場合は、プロキシ設定を確認する

  • ネットワークが AWS エンドポイントへのアウトバウンド HTTPS 接続を許可していることを確認する

  • デバッグログを有効にして接続の試行の詳細を表示する

  • curl などのツールを使用して接続をテストし、AWS エンドポイントへのネットワークアクセスを検証する