高危接口访问熔断机制

简介:

背景介绍

阿里云ECS实例的停机、重启、释放等操作都属于高风险动作,直接影响到ECS实例本身所承载的计算任务和业务。特别是大批量操作时,更加需要明确停机或释放机器的准确性,一旦批量误操作甚至导致整个网站业务线的崩溃。为了防止造成这种巨大损失的局面,针对高风险操作接口提供一种限流熔断机制,批量操作时可以有效的制止过度的错误停机、重启及释放。

设计方案

ECS实例的停机、重启及释放属于高风险操作,未来随着接口应用的深入,其他接口也可能处于高风险状态,例如安全组ACL授权操作等。为了能够让所有高风险操作都可以使用该熔断机制,所以设计的首要原则是高风险接口与熔断机制本身解耦。
需要统计添加熔断机制接口单位时间内的调用频次,设置合理的熔断上限,在不影响日常合理调用的前提下,还需要考虑正常且正确的批量调用,需要提供临时白名单策略。白名单内的用户不受熔断机制限制,需要认真确认实例信息,以免造成大量错误停机、重启或释放的情况。
针对接口熔断类功能需要添加开关进行控制,并逐个地域进行开放,便于观察各接口的熔断情况和调整接口的熔断上限,通关开关的控制可以应对熔断机制带来的突发状况。比如熔断机制不合理,导致接口调用收到严重限制,没有接口只能通过回滚代码的方式进行恢复,时效性低并且存在风险。
设计方案的基本原则:

  • 需要熔断的接口与限流熔断机制之间解耦合;
  • 提供白名单策略,应对超过熔断上限的合理调用;
  • 提供开关策略统一控制各接口的熔断机制;

注解和切面(Annotation+Spect)的方式实现熔断

在不对需要熔断接口的代码做任何修改的前提下,只需要在接口的方法上添加熔断注解就可以实现熔断限流的作用,熔断功能模块独立,接口本身的逻辑和代码独立,通过添加注解的方式实现高内聚低耦合。
首先,定义一个熔断的注解AccessLimit:

/**
 * 高危接口熔断机制
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AccessLimit {}

通过注解@AccessLimit获取方法参数中调用者的信息,实现一个以@AccessLimit为入口的切面,该切面实现了熔断机制的全部逻辑。以调用者的信息作为Key,利用Tair天生Key/Value存储结构的统计该调用者在当前小时内的调用次数,Tair中提供累加的incr方法:

/**
 * @param namespace
 * @param key
 * @param value
 * @param defaultValue
 * @param expireTime
 * @return
 */
Result<Integer> incr(int namespace, Serializable key, int value, int defaultValue, int expireTime);

Tair统计每个调用者Key值过期之前的调用次数,达到熔断上限时抛出异常信息,提示达到风控上线的信息,并不再进一步调用该方法,达到熔断限流的效果。

Tair中incr方法的过期时间

针对同一个调用者,在过期之前的单位时间内,同一方法调用一次访问次数累加一次。incr方法需要注意的是过期时间参数每次调用都会更新的,这样就会存在问题:
1、如果已经达到访问上线,并可以继续执行incr,那么从最后一次访问开始重新记录过期时间。如果在释放Key之前继续访问,将导致该接口针对该用户无法访问。
2、如果已经达到访问上线,并阻止继续执行incr,那么从最后一次访问开始重新记录过期时间,直到该Key过期才能重新继续访问。
以上两种情况统计同一用户对同一接口的访问次数均不准确。解决该问题的方式需要将调用者的Key与当前时间相结合,熔断机制限制方式为每小时N次,任意小时内任何时间取整到小时都是同一个值,将该值与调用者信息拼接作为CacheKey,一天内同一调用者在任意小时内的CacheKey都不一样,这样即使incr方法中的过期时间每次更新,仍然可以准确统计每小时内的访问上线次数。不会出现以上两种请款带来的时间延迟或持续无法访问的情况。关于Key值处理:

/**
 * 获取 cache key
 * @param key
 * @return
 */
private String getCacheKey(String key) {
    Calendar calendar = Calendar.getInstance();
    String hour = String.valueOf(calendar.get(Calendar.HOUR_OF_DAY));
    StringBuilder cacheKey = new StringBuilder(key);
    cacheKey.append("#");
    cacheKey.append(hour)
    return cacheKey.toString();
}

总结

关于接口限流的熔断机制,利用注解和切面的方式进行实现,不仅设计逻辑明确、容易理解,而且很好的体现了高内聚低耦合的设计思想。结合白名单及开关的策略,使得熔断机制的使用更加广泛、安全、灵活。

目录
相关文章
|
3月前
|
消息中间件 监控 Java
接口请求重试策略:保障稳定性的必杀技
接口请求重试策略:保障稳定性的必杀技
79 0
|
2月前
SpringRetry接口重试机制
SpringRetry接口重试机制
19 1
|
4月前
|
监控 测试技术 数据安全/隐私保护
如何集成Sentinel实现流控、降级、热点规则、授权规则总结
如何集成Sentinel实现流控、降级、热点规则、授权规则总结
80 0
|
4月前
|
数据采集 Java 调度
深入解析Java线程池的扩容机制与拒绝策略
深入解析Java线程池的扩容机制与拒绝策略
102 0
|
9月前
|
监控 Dubbo Linux
微服务 热点流控 规则-授权 系统规则 自定义返回
微服务 热点流控 规则-授权 系统规则 自定义返回
66 0
|
10月前
|
开发框架 前端开发 NoSQL
限流的非常规用途 - 解决重复提交问题
限流的非常规用途 - 解决重复提交问题
45 0
|
12月前
|
算法 NoSQL JavaScript
服务限流,我有6种实现方式…
服务限流,我有6种实现方式…
你的系统支持限流吗?
很多时候为了系统的安全性以及负载考虑,我们都会在请求量过高的时候对系统进行限流处理,那么今天我就我自己做过的一个系统里面的限流方案来介绍一下
81 0
|
Java 开发者 Sentinel
降级规则|学习笔记
快速学习降级规则
59 0
降级规则|学习笔记
|
Java 开发者 Sentinel
SentineI 服务熔断降级的策略 | 学习笔记
快速学习 SentineI 服务熔断降级的策略
96 0