网络重试中的 指数退避抖动 算法 Exponential Backoff And Jitter

最近项目中用到了很多 RPC 调用,其中定义了一个如下的重试策略:

public static final RetryStrategy DEFAULT_RETRY_STRATEGY =
        new ExponentialBackoffAndJitterBuilder()
                .retryOn(Calls.getCommonRecoverableThrowables())
                .retryOn(RetryableSBAAGTSvcException.class)
                .withInitialIntervalMillis(RETRY_INITIAL_INTERVAL_MILLIS)
                .withMaxAttempts(RETRY_MAX_ATTEMPTS)
                .build();
 
 

关于 指数退避抖动 算法 Exponential Backoff And Jitter,参考如下两篇文章:

  • AWS 中的错误重试和指数退避
  • Exponential Backoff And Jitter

指数退避的原理是对于连续错误响应,重试等待间隔越来越长。
您应该实施最长延迟间隔最大重试次数。最长延迟间隔和最大重试次数不一定是固定值,并且应当根据正在执行的操作和其他本地因素(例如网络延迟)进行设置。

大多数指数退避算法会利用抖动(随机延迟)来防止连续的冲突。
由于在这些情况下您并未尝试避免此类冲突,因此无需使用此随机数字。但是,如果使用并发客户端,抖动可帮助您更快地成功执行请求。

以下代码演示如何在 Java 中实施此增量延迟。

public class RetryDemo {

    // 最长延迟间隔,单位是毫秒
    private static int MAX_WAIT_INTERVAL = 100000;
    // 最大重试次数
    private static int MAX_RETRIES = 5;

    public enum Results {
        SUCCESS,
        NOT_READY,
        THROTTLED,
        SERVER_ERROR
    }

    public static void main(String[] args) {
        doOperationAndWaitForResult();
    }

    // 指数退避 算法
    public static void doOperationAndWaitForResult() {

        try {
            int retries = 0;
            boolean retry = false;

            do {
                long waitTime = Math.min(getWaitTimeExp(retries), MAX_WAIT_INTERVAL);

                System.out.print("等待时间:" + waitTime + " ms \n");

                // Wait for the result.
                Thread.sleep(waitTime);

                // Get the result of the asynchronous operation.
                Results result = getAsyncOperationResult();

                if (Results.SUCCESS == result) {
                    retry = false;
                } else if (Results.NOT_READY == result) {
                    retry = true;
                } else if (Results.THROTTLED == result) {
                    retry = true;
                } else if (Results.SERVER_ERROR == result) {
                    retry = true;
                }
                else {
                    retry = false;
                }

            } while (retry && (retries++ < MAX_RETRIES));
        }
        catch (Exception ex) {
        }
    }

    // 假设每次都返回 SERVER_ERROR
    public static Results getAsyncOperationResult() {
        return Results.SERVER_ERROR;
    }

    // 根据重试的次数,返回 2 的指数的等待时间,单位是毫秒
    public static long getWaitTimeExp(int retryCount) {

        long waitTime = ((long) Math.pow(2, retryCount) * 100L);

        return waitTime;
    }

}

输出如下:

等待时间:100 ms 
等待时间:200 ms 
等待时间:400 ms 
等待时间:800 ms 
等待时间:1600 ms 
等待时间:3200 ms 

你可能感兴趣的:(网络重试中的 指数退避抖动 算法 Exponential Backoff And Jitter)