高危接口访问熔断机制

简介:

背景介绍

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

设计方案

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

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

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

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

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

通过注解@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);
AI 代码解读

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();
}
AI 代码解读

总结

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

心牧
+关注
目录
打赏
0
0
0
0
2
分享
相关文章
Redis下Lua脚本的复制模式
假设我们的Redis选择了主从架构, 和AOF持久化方式。我们执行一条写命令时, 该条命令会被发送到从服务器, 和追加到AOF文件中。当我们执行的不是一条命令, 而是Lua脚本时, 默认情况下, 整个Lua脚本的内容会进行复制, 但是存在一些特殊情况。
2376 0
Redis下Lua脚本的复制模式
解决No version of NDK matched the requested version问题
一个本来好好的项目,突然在运行的时候报错: No version of NDK matched the requested version 21.0.6113669. Versions available locally: 20.1.5948944 网上很多人建议在build.gradle中添加ndk,如下: android { ... ndkVersion '20.1.5948944' } 复制代码 也确实可以解决问题,但是本来一个对ndk版本没有强依赖的项目,现在固定在一个版本上,其他开发者也必须有这个具体版本才能正常编译运行。
1924 0
Android RecyclerView 缓存机制深度解析与面试题
本文首发于公众号“AntDream”,详细解析了 `RecyclerView` 的缓存机制,包括多级缓存的原理与流程,并提供了常见面试题及答案。通过本文,你将深入了解 `RecyclerView` 的高性能秘诀,提升列表和网格的开发技能。
179 8
Ping命令的替代工具有哪些?
【8月更文挑战第14天】Ping命令的替代工具有哪些?
635 2
从 Java 小白到大神:一文带你搞懂子类如何“继承”父类江山,开创新世界!
【6月更文挑战第16天】Java中的继承是面向对象的核心,它允许子类继承父类的属性和方法,提高代码复用。通过实例,如`Animal`和`Dog`类,显示了如何创建和覆盖方法。继承不仅简化代码,还支持多态性,是构建可扩展系统的关键。从新手到专家,掌握继承意味着掌握编程的强大工具,能解锁更复杂的系统设计和优化。
269 3
clickhouse使用及常见异常 【已解决】
clickhouse使用及常见异常 【已解决】
811 0
Android App事件交互中区分点击和长按动作以及识别手势滑动方向的讲解及实战(附源码 可直接使用)
Android App事件交互中区分点击和长按动作以及识别手势滑动方向的讲解及实战(附源码 可直接使用)
769 0
什么是raid? 在虚拟机上实现raid5。 raid和热备盘
RAID 是洋文“Redundant Array of Inexpensive Disks”的缩写,中文称之为“磁盘冗余阵列”。
870 0
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问