本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
疑難排解常見問答集
當您 AWS SDK for Java 2.x 在應用程式中使用 時,您可能會遇到本主題中列出的執行時間錯誤。使用這裡的建議來協助您找出根本原因並解決錯誤。
如何修正「java.net.SocketException:連線重設」或「伺服器無法完成回應」錯誤?
連線重設錯誤表示您的主機 AWS 服務、 或任何中介方 (例如 NAT 閘道、代理、負載平衡器) 在請求完成之前關閉連線。由於有許多原因,尋找解決方案需要您了解連線關閉的原因。下列項目通常會導致連線關閉。
-
連線處於非作用中狀態。 這在串流操作中很常見,其中資料在一段時間內不會寫入或傳出線路,因此中介方會偵測連線是否無效並關閉它。若要避免這種情況,請確定您的應用程式主動下載或上傳資料。
-
您已關閉 HTTP 或 SDK 用戶端。確保在使用資源時不要關閉資源。
-
設定錯誤的代理。嘗試略過您已設定的任何代理,以查看它是否修正了問題。如果此問題得到修正,代理會因某些原因而關閉您的連線。研究您的特定代理,以判斷其關閉連線的原因。
如果您無法識別問題,請嘗試在網路的用戶端邊緣 (例如,在您控制的任何代理之後) 為受影響的連線執行 TCP 傾印。
如果您看到 AWS 端點正在傳送 TCP RST(重設),請聯絡受影響的服務
如何修正「連線逾時」?
連線逾時錯誤表示您的主機 AWS 服務、 或任何中介方 (例如 NAT 閘道、代理、負載平衡器) 無法在設定的連線逾時內與伺服器建立新的連線。以下項目說明此問題的常見原因。
-
設定的連線逾時太低。根據預設, 中的連線逾時為 2 秒 AWS SDK for Java 2.x。如果您設定太低的連線逾時,您可能會收到此錯誤。如果您只進行區域內呼叫,則建議的連線逾時為 1 秒;如果您提出跨區域請求,則建議的連線逾時為 3 秒。
-
設定錯誤的代理。嘗試略過您設定的任何代理,以查看它是否修正了問題。如果這修正了問題,代理就是連線逾時的原因。研究您的特定代理,以判斷發生這種情況的原因
如果您無法識別問題,請嘗試在網路的用戶端邊緣 (例如,在您控制的任何代理之後) 為受影響的連線執行 TCP 傾印,以調查任何網路問題。
如何修正「java.net.SocketTimeoutException:讀取逾時」?
讀取逾時錯誤表示 JVM 嘗試從基礎作業系統讀取資料,但資料並未在透過 SDK 設定的時間內傳回。如果作業系統、 AWS 服務或任何中介方 (例如 NAT 閘道、代理、負載平衡器) 無法在 JVM 預期的時間內傳送資料,就會發生此錯誤。由於有許多原因,尋找解決方案需要您了解未傳回資料的原因。
嘗試在網路的用戶端邊緣 (例如,在您控制的任何代理之後) 為受影響的連線執行 TCP 傾印。
如果您看到 AWS 端點正在傳送 TCP RST(重設),請聯絡受影響的服務
如何修正「無法執行 HTTP 請求:等待從集區連線逾時」錯誤?
此錯誤表示請求無法在指定的最長時間內從集區取得連線。若要疑難排解問題,建議您啟用 SDK 用戶端指標,將指標發佈至 Amazon CloudWatch。HTTP 指標有助於縮小根本原因範圍。以下項目說明此錯誤的常見原因。
-
連線洩漏。您可以檢查
LeasedConcurrency、AvailableConcurrency和MaxConcurrency指標來調查此問題。如果LeasedConcurrency增加,直到達到MaxConcurrency但永遠不會減少,則可能會發生連線洩漏。洩漏的常見原因是串流操作未關閉,例如 S3getObject方法。我們建議您的應用程式盡快從輸入串流讀取所有資料,並在之後關閉輸入串流。下圖顯示連線洩漏的 SDK 指標可能看起來像什麼。
-
連線集區匱乏。 如果您的請求率太高,且已設定的連線集區大小無法滿足請求需求,就會發生這種情況。預設連線集區大小為 50,當集區中的連線達到上限時,HTTP 用戶端會將傳入請求排入佇列,直到連線可用為止。下圖顯示連線集區匱乏的 SDK 指標可能看起來像什麼。
若要緩解此問題,請考慮採取下列任何動作。
-
增加連線集區大小,
-
增加取得逾時。
-
減慢請求率。
透過增加連線數量上限,用戶端輸送量可以增加 (除非網路界面已充分利用)。不過,您最終可以對程序使用的檔案描述項數量達到操作系統限制。如果您已經完全使用網路界面,或無法進一步增加連線計數,請嘗試增加取得逾時。隨著增加,您可以在逾時之前獲得請求取得連線的額外時間。如果連線未釋出,後續請求仍會逾時。
如果您無法使用前兩個機制修正問題,請嘗試以下選項來降低請求率。
-
平滑您的請求,讓大型流量爆增不會讓用戶端超載。
-
呼叫 時更有效率 AWS 服務。
-
增加傳送請求的主機數量。
-
-
I/O 執行緒太忙碌。這僅適用於使用非同步 SDK 用戶端搭配 的情況
NettyNioAsyncHttpClient。如果 AvailableConcurrency指標不低,表示集區中有可用的連線,但ConcurrencyAcquireDuration很高,可能是因為 I/O 執行緒無法處理請求。請確定您不會傳遞Runnable:run為未來的完成執行器,並在回應未來的完成鏈中執行耗時的任務,因為這可能會封鎖 I/O 執行緒。如果不是這種情況,請考慮使用 eventLoopGroupBuilder方法增加 I/O 執行緒的數量。做為參考,NettyNioAsyncHttpClient執行個體的預設 I/O 執行緒數量是主機 CPU 核心數量的兩倍。 -
高 TLS 交握延遲。如果您的
AvailableConcurrency指標接近 0LeasedConcurrency且低於MaxConcurrency,可能是因為 TLS 交握延遲很高。下表顯示 SDK 指標在高 TLS 交握延遲時可能看起來像什麼。
對於不是以 CRT 為基礎的 Java 開發套件提供的 HTTP 用戶端,請嘗試啟用 TLS 日誌來疑難排解 TLS 問題。對於以 CRT 為基礎的 HTTP AWS 用戶端,請嘗試啟用 AWS CRT 日誌。如果您看到 AWS 端點似乎需要很長的時間來執行 TLS 交握,您應該聯絡受影響的服務
。
如何修正 NoClassDefFoundError、 NoSuchMethodError或 NoSuchFieldError?
NoClassDefFoundError 表示無法在執行時間載入類別。此錯誤的兩個最常見原因是:
-
類別不存在於 classpath 中,因為 JAR 遺失或 JAR 的錯誤版本位於 classpath 上。
-
類別無法載入,因為其靜態初始化器擲回例外狀況。
同樣地, NoSuchMethodError和 NoSuchFieldError通常由不相符的 JAR 版本造成。我們建議您執行下列步驟。
-
檢查您的相依性,以確保您使用所有 SDK jar 的相同版本。類別、方法或欄位找不到的最常見原因是當您升級至新的用戶端版本,但您繼續使用舊的「共用」開發套件相依版本時。新的用戶端版本可能會嘗試使用僅存在於較新「共用」 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。 -
儘早檢查日誌中的陳述式,以查看類別是否因為靜態初始化失敗而無法載入。類別第一次無法載入時,可能會擲回不同、更實用的例外狀況,指定無法載入類別的原因。此可能有用的例外狀況只會發生一次,因此之後的日誌陳述式只會報告找不到 類別。
-
檢查您的部署程序,以確保其與您的應用程式一起實際部署所需的 JAR 檔案。您可能會使用正確的版本建置 ,但為您的應用程式建立 classpath 的程序會排除必要的相依性。
如何修正「SignatureDoesNotMatch」錯誤或「我們計算的請求簽章與您提供的簽章不符」錯誤?
SignatureDoesNotMatch 錯誤表示 產生的簽章 適用於 Java 的 AWS SDK 和 產生的簽章 AWS 服務 不相符。以下項目說明潛在原因。
-
代理或中介方會修改請求。例如,代理或負載平衡器可能會修改 SDK 簽署的標頭、路徑或查詢字串。
-
當每個 產生要簽署的字串時,服務和 SDK 的編碼方式會有所不同。
若要偵錯此問題,建議您啟用 SDK 的偵錯記錄。嘗試重現錯誤,並尋找 SDK 產生的正式請求。在 日誌中,正式請求會標示為 AWS4 Canonical Request: ...,而要簽署的字串會標示為 AWS4 String to sign: ... 。
如果您無法啟用偵錯,例如,因為它只能在生產環境中重現,請將邏輯新增至應用程式,以便在發生錯誤時記錄請求的相關資訊。然後,您可以使用該資訊,在啟用偵錯記錄的整合測試中,嘗試在生產環境外複寫錯誤。
在您收集正式請求和要簽署的字串之後,請將它們與 AWS Signature 第 4 版規格進行比較,以判斷 SDK 產生要簽署的字串是否存在任何問題。如果似乎有問題,您可以建立 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:連線集區關閉」錯誤?
此錯誤表示基礎 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 的網路存取