疑難排解常見問答集 - AWS SDK for Java 2.x

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

疑難排解常見問答集

當您 AWS SDK for Java 2.x 在應用程式中使用 時,您可能會遇到本主題中列出的執行時間錯誤。使用這裡的建議來協助您找出根本原因並解決錯誤。

如何修正「java.net.SocketException:連線重設」或「伺服器無法完成回應」錯誤?

連線重設錯誤表示您的主機 AWS 服務、 或任何中介方 (例如 NAT 閘道、代理、負載平衡器) 在請求完成之前關閉連線。由於有許多原因,尋找解決方案需要您了解連線關閉的原因。下列項目通常會導致連線關閉。

  • 連線處於非作用中狀態。 這在串流操作中很常見,其中資料在一段時間內不會寫入或傳出線路,因此中介方會偵測連線是否無效並關閉它。若要避免這種情況,請確定您的應用程式主動下載或上傳資料。

  • 您已關閉 HTTP 或 SDK 用戶端。請勿在資源使用時將其關閉。

  • 設定錯誤的代理。嘗試略過您已設定的任何代理,以查看它是否修正了問題。如果此問題得到修正,代理會因為某些原因而關閉您的連線。研究您的特定代理,以判斷其關閉連線的原因。

如果您無法識別問題,請嘗試在網路的用戶端邊緣 (例如,在您控制的任何代理之後) 為受影響的連線執行 TCP 傾印。

如果您看到 AWS 端點正在傳送 TCP RST(重設),請聯絡受影響的服務,看看他們是否可以判斷重設發生的原因。準備好提供問題發生時的請求 IDs 和時間戳記。 AWS 支援團隊也可能受益於線路日誌,該日誌確切顯示應用程式傳送和接收的位元組,以及傳送和接收時間。

如何修正「連線逾時」?

連線逾時錯誤表示您的主機 AWS 服務、 或任何中介方 (例如 NAT 閘道、代理、負載平衡器) 無法在設定的連線逾時內與伺服器建立新的連線。以下項目說明此問題的常見原因。

  • 設定的連線逾時太低。根據預設, 中的連線逾時為 2 秒 AWS SDK for Java 2.x。如果您設定太低的連線逾時,您可能會收到此錯誤。如果您只進行區域內呼叫,則建議的連線逾時為 1 秒;如果您提出跨區域請求,則建議的連線逾時為 3 秒。

  • 設定錯誤的代理。嘗試略過您設定的任何代理,以查看它是否修正了問題。如果這修正了問題,代理就是連線逾時的原因。研究您的特定代理,以判斷發生這種情況的原因

如果您無法識別問題,請嘗試在網路的用戶端邊緣 (例如,在您控制的任何代理之後) 為受影響的連線執行 TCP 傾印,以調查任何網路問題。

如何修正「java.net.SocketTimeoutException:讀取逾時」?

讀取逾時錯誤表示 JVM 嘗試從基礎作業系統讀取資料,但資料並未在透過 SDK 設定的時間內傳回。如果作業系統、 AWS 服務或任何中介方 (例如 NAT 閘道、代理、負載平衡器) 無法在 JVM 預期的時間內傳送資料,就會發生此錯誤。由於有許多原因,尋找解決方案需要您了解未傳回資料的原因。

嘗試在網路的用戶端邊緣 (例如,在您控制的任何代理之後) 為受影響的連線執行 TCP 傾印。

如果您看到 AWS 端點正在傳送 TCP RST(重設),請聯絡受影響的服務。準備好提供問題發生時的請求 IDs 和時間戳記。 AWS 支援團隊也可能受益於線路日誌,該日誌確切顯示應用程式傳送和接收的位元組,以及傳送時間。

如何修正「無法執行 HTTP 請求:等待從集區連線逾時」錯誤?

此錯誤表示請求無法在指定的最長時間內從集區取得連線。若要對問題進行疑難排解,我們建議您啟用 SDK 用戶端指標,將指標發佈至 Amazon CloudWatch。HTTP 指標有助於縮小根本原因範圍。以下項目說明此錯誤的常見原因。

  • 連線洩漏。您可以檢查 LeasedConcurrencyAvailableConcurrencyMaxConcurrency指標來調查此問題。如果 LeasedConcurrency 增加直到達到 ,MaxConcurrency但從未減少,則可能會發生連線洩漏。洩漏的常見原因是串流操作未關閉,例如 S3 getObject方法。我們建議您的應用程式盡快從輸入串流讀取所有資料,並在之後關閉輸入串流。下圖顯示連線洩漏的 SDK 指標可能看起來像什麼。

    顯示可能連線洩漏的 CloudWatch 指標螢幕擷取畫面。
  • 連線集區匱乏。 如果您的請求率太高,且已設定的連線集區大小無法滿足請求需求,就會發生這種情況。預設連線集區大小為 50,當集區中的連線達到上限時,HTTP 用戶端會將傳入請求排入佇列,直到連線可用為止。下圖顯示連線集區匱乏的 SDK 指標可能看起來像什麼。

    CloudWatch 指標的螢幕擷取畫面,顯示連線集區匱乏的外觀。

    若要緩解此問題,請考慮採取下列任何動作。

    • 增加連線集區大小,

    • 增加取得逾時。

    • 減慢請求率。

    透過增加連線數量上限,用戶端輸送量可以增加 (除非網路界面已充分利用)。不過,您最終可以在程序使用的檔案描述項數量上達到操作系統限制。如果您已完全使用您的網路介面或無法進一步增加連線計數,請嘗試增加取得逾時。隨著增加,您可以獲得額外的時間,讓請求在逾時之前取得連線。如果連線未釋出,後續請求仍會逾時。

    如果您無法使用前兩個機制修正問題,請嘗試以下選項來降低請求率。

    • 平滑您的請求,讓大型流量爆增不會讓用戶端超載。

    • 呼叫 時更有效率 AWS 服務。

    • 增加主機傳送請求的數量。

  • I/O 執行緒太忙碌。這僅適用於使用非同步 SDK 用戶端搭配 的情況NettyNioAsyncHttpClient。如果AvailableConcurrency指標不低,表示集區中有可用的連線,但ConcurrencyAcquireDuration很高,可能是因為 I/O 執行緒無法處理請求。請確定您不會傳遞Runnable:run未來的完成執行器,並在回應未來的完成鏈中執行耗時的任務,因為這可能會封鎖 I/O 執行緒。如果不是這種情況,請考慮使用 eventLoopGroupBuilder方法增加 I/O 執行緒的數量。做為參考,NettyNioAsyncHttpClient執行個體的預設 I/O 執行緒數量是主機 CPU 核心數量的兩倍。

  • 高 TLS 交握延遲。如果您的AvailableConcurrency指標接近 0 LeasedConcurrency 且低於 MaxConcurrency,可能是因為 TLS 交握延遲很高。下圖顯示 SDK 指標在高 TLS 交握延遲時可能看起來像什麼。

    可能表示高 TLS 交握延遲的 CloudWatch 指標螢幕擷取畫面。

    對於非以 CRT 為基礎的 Java 開發套件提供的 HTTP 用戶端,請嘗試啟用 TLS 日誌來疑難排解 TLS 問題。對於 AWS 以 CRT 為基礎的 HTTP 用戶端,請嘗試啟用 AWS CRT 日誌。如果您看到 AWS 端點似乎需要很長的時間來執行 TLS 交握,您應該聯絡受影響的服務

如何修正 NoClassDefFoundErrorNoSuchMethodErrorNoSuchFieldError

NoClassDefFoundError 表示無法在執行時間載入類別。此錯誤的兩個最常見原因是:

  • 類別不存在於 classpath 中,因為 JAR 遺失或 JAR 的錯誤版本位於 classpath 中。

  • 類別無法載入,因為其靜態初始化器擲回例外狀況。

同樣地, NoSuchMethodErrorNoSuchFieldError通常由不相符的 JAR 版本造成。我們建議您執行下列步驟。

  1. 檢查您的相依性,以確保您使用所有 SDK jar 的相同版本。類別、方法或欄位找不到的最常見原因是當您升級至新的用戶端版本,但您繼續使用舊的「共用」開發套件相依版本時。新的用戶端版本可能會嘗試使用僅存在於較新「共用」 SDK 相依性的類別。嘗試執行 mvn dependency:treegradle 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. 早檢查日誌中的陳述式,以查看類別是否因為靜態初始化失敗而無法載入。類別第一次無法載入時,可能會擲回不同、更實用的例外狀況,指定無法載入類別的原因。此可能有用的例外狀況只會發生一次,因此之後的日誌陳述式只會報告找不到 類別。

  3. 檢查您的部署程序,以確保其與您的應用程式一起實際部署必要的 JAR 檔案。您可能會使用正確的版本建置 ,但為您的應用程式建立 classpath 的程序會排除必要的相依性。

如何修正「SignatureDoesNotMatch」錯誤或「我們計算的請求簽章與您提供的簽章不符」錯誤?

SignatureDoesNotMatch 錯誤表示 產生的簽章 適用於 Java 的 AWS SDK 和 產生的簽章 AWS 服務 不相符。以下項目說明潛在原因。

  • 代理或中介方會修改請求。例如,代理或負載平衡器可能會修改 SDK 簽署的標頭、路徑或查詢字串。

  • 當每個 產生要簽署的字串時,服務和 SDK 的編碼方式會有所不同。

若要偵錯此問題,建議您啟用 SDK 的偵錯記錄。嘗試重現錯誤,並尋找 SDK 產生的正式請求。在 日誌中,正式請求會標示為 AWS4 Canonical Request: ...,而要簽署的字串則會標示為 AWS4 String to sign: ...

如果您無法啟用偵錯,例如,因為它只能在生產環境中重現,請將邏輯新增至應用程式,以便在發生錯誤時記錄請求的相關資訊。然後,您可以使用該資訊,在啟用偵錯記錄的整合測試中,嘗試在生產環境外複寫錯誤。

在您收集正式請求和要簽署的字串之後,請將它們與 AWS Signature 第 4 版規格進行比較,以判斷 SDK 產生要簽署的字串是否存在任何問題。如果似乎有問題,您可以建立 GitHub 錯誤報告給 適用於 Java 的 AWS SDK。

如果沒有顯示錯誤,您可以比較 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:連線集區關閉」錯誤?

此錯誤表示基礎 Apache HTTP 連線集區已關閉。以下項目說明潛在原因。

  • 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.builder().build() 如果您的程式碼已關閉單一執行個體,而且您需要使用 解析登入資料,請呼叫 來建立新的非單一執行個體DefaultCredentialsProvider

如何修正「無法從鏈結 AwsCredentialsProviderChain 中的任何供應商載入登入資料」?

此錯誤表示 AWS SDK for Java 2.x 無法透過預設 AWS 登入資料提供者鏈結中的任何登入資料提供者找到有效的登入資料。軟體開發套件會自動依特定順序搜尋登入資料,當鏈結中的所有供應商無法提供有效的登入資料時,就會發生此錯誤。

完整的錯誤訊息通常如下所示 (新增行尾和縮排以提高可讀性):

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 檢查的登入資料來源和順序。

請確定您打算使用的登入資料組態方法已在您的環境中正確設定:

對於 Amazon EC2 執行個體
  • 檢查 IAM 角色:確認 IAM 角色已連接至您的執行個體。

  • 間歇 IMDS 故障:如果您遇到間歇性故障 (通常持續幾百毫秒),這通常表示暫時性網路問題到達執行個體中繼資料服務 (IMDS)。

    解決方案:

    • 啟用偵錯記錄,以分析故障的時間和頻率

    • 考慮在您的應用程式中實作重試邏輯,以解決登入資料相關的故障

    • 檢查執行個體與 IMDS 端點之間的網路連線問題

對於容器環境

確認任務角色 (Amazon ECS) 或服務帳戶 (Amazon EKS) 已設定,且已設定必要的環境變數。

針對本機開發

檢查環境變數、登入資料檔案或 IAM Identity Center 組態是否已就緒。

針對 Web 聯合身分
  • 驗證組態:驗證 Web 身分字符檔案是否存在,以及是否已設定必要的環境變數。

  • 缺少 STS 模組相依性:如果您看到錯誤 To use web identity tokens, the 'sts' service module must be on the class path,則需要新增 STS 模組做為相依性。這在使用 Amazon EKS Pod Identity 或其他 Web 身分字符身分驗證時很常見。

    解決方案:將 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 端點時網路連線問題。

解決方案:

  • 如果您使用代理伺服器,請驗證代理組態

  • 檢查您的網路是否允許對外 HTTPS 連線至 AWS 端點

  • 啟用偵錯記錄以查看詳細的連線嘗試

  • 使用 等工具測試連線能力curl,以驗證端點 AWS 的網路存取