基于流控策略的优雅退避机制

更新时间:

基于流控策略的优雅退避机制介绍。

说明

新增重试机制(重试机制)及流控策略。

核心库 aliyun-java-sdk-core 从 4.6.0 版本开始支持重试机制(重试机制),以及提供基于流控策略的优雅退避方案。Maven 依赖如下:

<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>aliyun-java-sdk-core</artifactId>
    <version>4.6.0</version>
</dependency>
重要
  1. 并非所有产品 API 都支持基于流控策略的优雅退避机制,具体有哪些支持可参考各个产品接口文档的流控信息一栏,例如:ECS 的 DescribeHpcClusters 接口文档:流控信息

  2. 不管云产品的接口是否支持流控退避策略,您都可在 SDK 中设置开启流控退避机制,若接口不支持,则 SDK 的退避与静默管控则不生效,与不开启的状态一致。但请注意,该方式存在风险,可能存在接口某一天突然开启了流控退避的情况,导致您在调用中触发流控突然导致静默,增大排查难度。

  3. 请在开启流控退避策略之后,依然保持对调用异常的监控,不能完全依赖于流控退避策略,以此导致漏查风险的状况。

  4. 以下介绍,均是基于接口已支持流控退避的情况

基于流控策略的优雅退避机制

基于流控策略的优雅退避,简单说分为两种策略:

  • 重试退避策略

  • 流控静默策略

重试机制中已讲,重试时间间隔是根据指数退避来的,使用的 EqualJitter(指数退避)算法计算出下次重试等待时间。除此之外,我们还提供了基于流控的优雅退避时间计算机制。

开启流控控制

默认关闭流控策略的控制,若要开启,则可使用以下两种方式:

  1. 配置 RetryPolicy

RetryPolicy retryPolicy = RetryPolicy.builder()
                .maxNumberOfRetries(3) // 最大重试次数
                .maxDelayTimeMillis(20 * 1000) // 最大重试间隔时间,单位为毫秒,超过这个时间则不再重试
                //.retryConditions(retryConditions) // 触发重试策略
                .enableAliyunThrottlingControl(true) // 使用阿里云流控策略进行控制 
                //.throttlingConditions(throttlingConditions) // 限制重试策略
                .build();

request.setSysRetryPolicy(retryPolicy);
  1. 使用默认 RetryPolicy 策略

// 默认策略,入参为 enableAliyunThrottlingControl,true 表示开启,false 表示关闭
RetryPolicy retryPolicy = RetryPolicy.defaultRetryPolicy( 
true 
);

request.setSysRetryPolicy(retryPolicy);

开启流控控制的优势

  1. 减少不必要的重试,降低系统消耗

  2. 更加准确利用退避时间,优雅地进行重试

高阶

重试退避策略:基于流控策略下的退避时间计算

开启流控策略的控制能力后,退避时间计算逻辑为:

  1. 如果没有触发流控,就一直用EqualJitter计算重试时间间隔;

  2. 如果触发了流控,则取流控剩余时间和 EqualJitter 计算结果的最大值做时间间隔,时间如果大于最大重试时间间隔的限制,则直接抛异常,并且将流控剩余时间记录在缓存池中,以供流控静默策略使用。

流控静默策略

开启流控策略的控制能力后,当触发流控限制,服务端则会在返回头(Header)中返回流控剩余的 quota 信息,即针对【用户】维度、【API + 用户】维度,返回给客户端以下信息:API 调用剩余次数、限流剩余时间等。其中当被限流时,API 调用剩余次数则为 0。

说明

两个维度在 Header 中对应的 Key 值为:

  • 【API + 用户】维度X-RateLimit-User-API

  • 【用户】维度:X-RateLimit-User

针对【API + 用户】维度举例说明:

"X-RateLimit-User-API" : "Remain:1,Limit:2,Time:1000,TimeLeft:122,Reset:1637835220000"

Remain:剩余量,int 类型,如果为 -1,则表示剩余量足够;如果已经被流控,则返回0;

Limit:流控的阈值上限,int 类型
Time:流控的时间跨度,long 类型,单位毫秒
TimeLeft:本流控周期剩余时间,long 类型,单位毫秒
Reset:流控下一次周期开始时间,long 类型,毫秒时间戳

而 SDK 会对流控剩余时间进行管理,在这个时间段里,若发起调用或者重试调用将会受到限制,如果这个时间大于最大重试间隔时间,则直接抛错,若不大于最大间隔重试时间,则会静默等待直到允许发起调用或重试。

开启流控调试

在能力开启的条件下,除了遇到流控限制的情况会返回 Header 中的流控剩余的 quota 信息外,还可以在正常调用时要求返回该 quota 信息,只需要在请求头中加 X-RateLimit-Mode 字段值为 debug 即可:

request.putHeadParameter("X-RateLimit-Mode", "debug");

这样就会在每次接口调用的返回头中拿到剩余 quota 信息。