集群限流场景
场景一
假设我们要调用阿里的某个API,但是该API每秒QPS限制为50次,假设集群中存在多台机器同时调用该API的情况,如何控制整个集群中该API调用次数在50以内,避免接口报错
场景二
假设开发的系统需要提供http接口给第三方调用,为了防止第三方恶意调用接口爬取数据,我们需要限制http接口请求QPS为50
两个场景都是基于接口资源层面的限流,本文介绍Sentinel结合Ahas云上控制台实现的集群流控功能
Maven依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>ahas-sentinel-client</artifactId>
<version>1.2.1</version>
</dependency>
注意:ahas-sentinel-client 1.2.x 仅兼容 Sentinel 1.5.0 及以上版本;ahas-sentinel-client 1.1.x 仅兼容 Sentinel 1.4.1 和 1.4.2 版本。
ahas-sentinel-client 中会包含 sentinel-core 以及集群限流等必要依赖(基于 Sentinel 1.5.1 版本),以及连接 AHAS Sentinel 控制台所需模块(鉴权、通信、动态数据源等),下面基于ahas-sentinel-client 1.1.2版本做介绍
阿里云开通AHAS
开通AHAS
操作步骤如下
- 打开 AHAS 产品主页
- 在页面右上角单击登录
- 在页面上输入您的阿里云账号和密码,并单击登录
- 在产品主页上单击申请免费开通,然后在云产品开通页页面上勾选我已阅读并同意《应用高可用服务服务协议》,并单击立即开通
注意若应用运行在非阿里云 ECS 环境或本地,需要在左上角选择切换公网环境
接入新应用,获取启动参数
点击控制台左侧应用流控,进入流控界面
点击应用接入后拿到启动参数
启动参数如下,需要加到项目启动参数中
-Dproject.name=AppName -Dahas.license=<License>
其中 project.name 代表应用名(会显示在控制台),ahas.license 代表自己的授权 license,为上图中红色划线部分,自己开通AHAS后获取,本地调试时再加入如下启动参数
-Dcsp.sentinel.log.use.pid=true
上述介绍的是通过JVM启动参数的接入方式,也有通过配置文件的方式,具体可以看官方接入文档介绍
https://help.aliyun.com/document_detail/110599.html?spm=a2c4g.11186623.6.584.73bc5365yz8C36
分配 Token Server
要实现集群限流,必须配置一个Token Server,获取到令牌的机器才有权限调用接口,这一步大家先看流程,可以先不配置。
AHAS中集成了嵌入式的Token Server(即Web服务机器可以被指定为Token Server),方便使用,也有独立部署模式的Token Server,需要自己单独部署,Token Server部署方案直接摘自官方示例中的说明
https://github.com/alibaba/Sentinel/wiki/AHAS-Sentinel-集群限流控制台示例
先进入自己服务对应的Token Server列表,链接如下
点击新增Token Server按钮
选择对应ip应用,将其设为Token Server,并配置该 Token Server 的端口以及最大的 QPS 配额(用于限制资源使用,防止嵌入模式下影响应用本身)。接下来我们就在下面的选择框中为该 Token Server 分配 Token Client。选择完成后点击“保存”按钮保存分配。
保存成功后,我们就能在 Token Server 列表页面看到刚刚分配的 Token Server 了:
注册限流策略
springboot项目中可以加入如下配置,来告诉sentinel针对哪些请求做限流拦截,其他web应用参考上面链接里的接入方式
@Configuration
public class WebConfig {
@Bean
public FilterRegistrationBean sentinelFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
//过滤器配置
registration.setFilter(new CommonFilter());
//请根据实际情况配置要拦截的 URL Pattern
registration.addUrlPatterns("*.json","*.hml","*.html","/demo/*");
registration.setName("sentinelCommonFilter");
registration.setOrder(1);
return registration;
}
}
CommonFilter为Sentinel封装好的限流的公用的过滤器,如果自己需要扩展,可以extends该类,并做特殊实现,addUrlPatterns方法指明针对哪些请求做过滤
registration.addUrlPatterns("*.json","*.hml","*.html","/demo/*");
上诉配置完后,就可以重启项目了
代码实测
代码中模拟如下实现,假设FlowControlService,其调用的是第三方服务接口,我们在其需要流控的方法上添加@SentinelResource
注解,名称为限流资源名称
@Service
public class FlowControlService {
@SentinelResource("clusterFlowControl")
public int clusterFlowControlTest(int i) {
return i;
}
}
controller层代码如下
@GetMapping("flowControl")
public BaseResult flowControl() {
for (int i = 0; i < 10; i++) {
//mock接口调用
System.out.println(flowControlService.clusterFlowControlTest(i));
System.out.println("请求成功"+i);
}
System.out.println("请求成功");
return new BaseResult();
}
项目启动后,需要访问一次接口,才可以在云上控制台中看到自己的项目
访问一次controller中测试接口后,可以在控制台中看到如下日志数据:
代表sentinel初始化成功,同时,AHAS控制台中也能看到项目请求数据
先在本地启动2个一样的项目,端口分别为8080,8081,模拟项目集群部署,同时使用Jmeter不断请求2个项目中同一个接口来模拟负载均衡后的请求情况
2个项目都连上后,显示有两个机器
jmeter请求
假设不加任何流控规则,jmeter不断请求,qps一下就彪的很高,超过了10000,如图
在AHAS中新建流控规则,为了验证,集群流控是否有效,先建立单机均摊qps规则如下,阈值模式选均摊类型,即每台机器接口请求限制其qps为50,集群qps=50*2=100
再次使用jmter请求,qps请求数据如图,通过qps始终为100,请求不通过部分会报异常
为了测试集群流控效果,需要完成两点
- 修改流控规则中阈值模式为总体阈值
- 配置tokenServer,tokenServer在AHAS中仅提供嵌入应用的形式
下面修改流控规则,将集群总qps设置为50,如图
在配置TokenServer,配置链接为
选择一台机器作为TokenServer,并分配集群中其他机器为Token Client
再次使用jmeter请求,看下结果
可以看到qps被限制在了50,集群限流生效
AHAS集群流控优缺点
个人觉得AHAS控制台集成集群流控,有如下优缺点
优点:
- 集成简单,不需自己对接配置中心
- TokenServer嵌入集群中机器,无需单独部署
缺点
- TokenServer无法做到failOver,未实现高可用,应用重启后需手动重新分配TokenServer
- AHAS上限流功能有限制,量大了时间长了要收费,并且限制使用,免费用户都是小白鼠了
接下来会尝试接入开源Sentinel控制台,并整合Apollo配置中心,单独部署TokenServer实现集群流控,到时再做分享