1. 背景
api流控分为in/out两个方向,in控制调用者调入流量, out控制调出api流量。开源有比较多的限流框架,如guava ratelimiter,sentinel的集群流控。 ratelimiter单机版,不适合用在分布式场景;sentinel集群流控token服务是单机版,同时我们需要调限速,根据资源情况或者api提供者的反馈,调高,调低流限,因此自研分布式api流控组件。
本组件用于系统调出第三方api流量整型,提高api调用通过率
2. 参考和术语
ratelimiter guava流控组件
sentinel 集群流控,支持集群限流
漏桶算法:
- 一个固定容量的漏桶,按照常量固定速率流出水滴;
- 如果桶是空的,则不需流出水滴;
- 可以以任意速率流入水滴到漏桶;
- 如果流入水滴超出了桶的容量,则流入的水滴溢出了(被丢弃),而漏桶容量是不变的。
通俗的比喻,门很窄,只能通过一个人
令牌桶算法:
- 用户设定QPS为r,则每隔1/r秒一个令牌被加入到桶中
- 设定桶中最多可以存放b个令牌。如果令牌到达时令牌桶已经满了,那么这个令牌会被丢弃
- 当流量以速率v进入,从桶中以速率v取令牌,拿到令牌的流量通过,拿不到令牌流量不通过,执行等待或熔断
通俗的比喻,门很宽,门口放一个桶,桶里放着令牌,每个人要过门需要从桶里拿个令牌,凭令牌通过,桶令牌匀速投放
3. 场景视图
场景视图描述系统干了什么事,有什么价值
- 拦截器
1. 拦截client调用,申请token,执行流量控制逻辑
> retrofit/okhttp3
> httpclient
> aop
> 可扩展
2. 申请token返回调用频率太高(429),发送超限消息
- 设置api资源 资源是流控目标抽象,api看作资源,资源配置流控规则
- 申请token 令牌桶算法
- 定时重置速率作业 调度作业,依据观测速率作为经验值
- 事件监听 监听超限消息,调整rate
- 输出测量 api请求集群qps ,支持Prometheus;console(本地测试用); NopScheduledReporter(什么都不做的报告器,相当于屏蔽)
4. 技术架构
- 请求,同一个资源,任何时候,任何服务,任何实例,发出请求
- 资源的流量限制是动态的,资源提供者根据系统总体负载的变化而变更流量限制
- 拦截器 调用拦截,申请令牌,若超限发送超限消息
- 流量控制 令牌桶算法使用redis lua实现
- 流量规则 流量规则管理
- 流控速率重置作业 定时重置资源流限
- 事件监听 接收超限事件,调速
- metrics 汇集到Prometheus,聚合统计; 作为经验值数据支持
5. 流量控制算法
本组件使用令牌桶算法,观测作为经验值定时重置限制值; 资源调用反馈调速
6. 详细设计
领域模型
7. 源码
源码(付费):flowsharping.rar-Java文档类资源-优快云下载
包括流控源码,及依赖metrics-reporter,metrics输出器
测试:TestFlowSharpingMetrics,测试包括限流和metrics输出,单机可用console reporter;分布式聚合metrics需Prometheus
aop: TestFlowSharpingAspect
okhttp: FlowSharpingOkHttpInterceptorTest
httpclient: FlowSharpingHttpClientTest
8. 效果
8.1 分布式服务流控
改造sentinel的okhttp和httpclient两个是单元测试,但资源名称一样 r1
1)设置资源/桶 TestFlowRuleService.testAddRedsourceFlowRule
桶配置,限流50/分钟
使用Prometheus输出器
上面两个图表两个不同的服务,同一机器,端口不同,下面图表两机器总的流量
绿色 pass流量,红色 fail流量,紫色总流量
可以看到,流量基本稳定在50左右
关掉一个服务,总体仍然保持50设定速率
再次打开另一个服务,流量速率保持设定50
8.2 场景: 动态变更流限
8.2.1 动态变更流限通过经验速率设置, ResourceService. updateExperienceRate
8.2.1 经验速率设置
ResourceService. setExperienceRate
其中节点A okhttp,节点B httpclient,总pass上升到80附近