全部產品
Search
文件中心

Key Management Service:使用指數退避方法對請求錯誤進行重試

更新時間:Mar 11, 2026

當您調用KMS的API時,有時會返回錯誤資訊。本文介紹了如何使用指數退避方法對請求錯誤進行重試。

背景資訊

當您調用服務介面時,有時會在某一環節出現錯誤,此時您可以在應用程式中進行重試。

一些阿里雲SDK支援通過配置,自動實現對請求的錯誤重試。例如:使用阿里雲的.NET SDK可以配置重試的策略。當自動重試方式不適用時,您可以使用本文介紹的重試方法對請求錯誤進行重試。

重試策略

請求出現錯誤時,如果是伺服器錯誤(5xx)或請求限流錯誤,則可以通過如下重試策略對請求錯誤進行重試:

  • 簡單重試。

    例如:總共重試10秒,每秒重試一次。

  • 指數退避。

    對於連續錯誤響應,重試等待間隔越來越長,您需要按照最長延遲間隔和最大重試次數進行重試。指數退避可以防止在重試過程中持續不斷地發生衝突。例如:在短時間內發出超過限流配額的請求時,通過指數退避的方式,可以有效規避持續的限流錯誤。

重要

專屬網關對API請求不設定調用次數上限,而是採用“儘力而為”的方式,即最大限度地使用執行個體計算和儲存資源來處理API請求,所以不會產生限流錯誤。

指數退避的虛擬碼

以下代碼介紹了如何使用增量延遲方法重試某個操作。

initialDelay = 200
retries = 0

DO
    wait for (2^retries * initialDelay) milliseconds

    status = CallSomeAPI()

    IF status == SUCCESS
        retry = false // Succeeded, stop calling the API again.
    ELSE IF status = THROTTLED || status == SERVER_NOT_READY
        retry = true  // Failed because of throttling or server busy, try again.
    ELSE
        retry = false // Some other error occurred, stop calling the API again.
    END IF

    retries = retries + 1

WHILE (retry AND (retries < MAX_RETRIES))

使用指數退避方法處理KMS限流

以下Java樣本介紹了如何使用指數退避的方式,處理KMS調用Decrypt介面時遇到的限流錯誤。

  • 您可以通過簡單修改,對特定類型的伺服器錯誤(例如:HTTP 503)進行重試。

  • 您可以通過精細地預估用戶端在特定時間段內發出的請求數,調整初始延遲值(initialDelay)和重試次數(maxRetries)。

說明

阿里雲帳號AccessKey擁有所有OpenAPI的存取權限,建議您使用RAM使用者進行API訪問或日常營運。強烈建議不要把AccessKey ID和AccessKey Secret儲存到工程代碼裡,否則可能導致AccessKey泄露,威脅您帳號下所有資源的安全。

本樣本以將AccessKey配置在環境變數ALIBABA_CLOUD_ACCESS_KEY_ID和ALIBABA_CLOUD_ACCESS_KEY_SECRET的方式來實現身分識別驗證為例。

import com.aliyun.kms20160120.Client;
import com.aliyun.kms20160120.models.DecryptRequest;
import com.aliyun.kms20160120.models.DecryptResponse;
import com.aliyun.tea.*;
import com.aliyun.teautil.models.RuntimeOptions;

import java.nio.charset.StandardCharsets;

public class Main {
    private static  Client kmsClient;

    private static Client kmsClient(String regionId, String accessKeyId, String accessKeySecret) throws Exception {
        com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
            .setAccessKeyId(accessKeyId)
            .setAccessKeySecret(accessKeySecret);
        config.setRegionId(regionId) ;
    return new Client(config);
    }

    private static String kmsDecrypt(String cipherTextBlob) throws Exception {
        DecryptRequest decryptRequest = new DecryptRequest()
                // 設定待解密的密文。
                .setCiphertextBlob(cipherTextBlob);
        DecryptResponse response = kmsClient.decryptWithOptions(decryptRequest, new RuntimeOptions());
        // 從響應中擷取解密後的明文。
        String plaintext = response.getBody().getPlaintext();

        System.out.println("Ciphertext (Base64): " + cipherTextBlob);
        System.out.println("Decrypted Plaintext: " + plaintext);
        return plaintext;
    }

    public static long getWaitTimeExponential(int retryCount) {
        final long initialDelay = 200L;
        long waitTime = ((long) Math.pow(2, retryCount) * initialDelay);
        return waitTime;
    }

    public static void main(String[] args) throws Exception {
        String regionId = "地區ID"; //"cn-shanghai"
        String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
        String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
        String cipherTextBlob ="a2V5LXNoaDY4M**********w=";
        int maxRetries = 5;

        kmsClient =  kmsClient(regionId, accessKeyId, accessKeySecret);

        for (int i = 0; i < maxRetries; i++) {
            try {
                String plainText = kmsDecrypt(cipherTextBlob);
                return;
            } catch (Exception e) {
                e.printStackTrace();
                if (e.getMessage().contains("Rejected.Throttling")) {//need retry
                    try {
                        Thread.sleep(getWaitTimeExponential(i + 1));
                    } catch (InterruptedException ignore) {
                    }
                } else {
                    break; // 非限流錯誤,停止重試。
                }
            }
        }
    }
}