sentinel 限流及熔断
为什么要限流呢?对于一些突发流量,如双11大促,甚至恶意攻击,这时系统的访问量远远超出系统的承受能力,如果不做任何保护措施, 服务器资源会耗尽,进而系统不可用。
限流就是限制系统访问量,以牺牲部分用户的可用性为代价,保证系统可用性。
常见的限流算法
计数器算法
计数器算法 实现简单存在临界问题,窗口切换时 会出现临界问题,可以用如短信发生频次限制等场景。
滑动窗口
滑动窗口算法是对计数器算法改进,将固定窗口中分割多个小时间窗口,统计每个小时间窗口记录总数,滑动窗口更加平滑,很好的解决了临界问题。
令牌桶算法
有个固定容量的令牌桶 用来存储令牌,系统以固定的速率 向令牌桶中添加令牌,超出容量的令牌会被丢弃。
用户请求时,先需要从令牌桶中获取令牌, 如果令牌桶中没有令牌则拒绝该请求,否则消耗一个令牌,请求被接收。
限流原理:当请求速度大于令牌生成的速度时, 桶内令牌不断被消耗,直到耗尽,从而触发限流。
适用于需要处理突发流量的场景,允许在短时间突发流量的处理
漏桶算法
有个固定容量的漏桶,存放用户请求的。
用户请求需要经过漏桶,桶满了,则拒绝请求, 漏桶里请求以固定速率流出,流出的请求被处理,漏桶算法处理速度是恒定的,
适用于需要平滑流量的场景,可以有效防止突发流量导致的网络拥塞,当流量高于处理速度时,部分请求会有一定的延迟。
Sentinel 应用
Sentinel是一款轻量级流量控制组件,可以轻松实现流量整形 、熔断保护机制,有效提升系统的健壮性和可用性。
Sentinel提供了灵活的规则配置方式,
-
控制台配置
-
扩展点配置
Sentinel Dashboard
下载指定的版本sentinel-dashboard.jar, 执行下面命令启动,启动成功后,http://{ip}:8080/ 进入控制台,默认用户名/密码:sentinel/sentinel,即可进入管理控制台
bash
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.8.jar
代码配置规则方式
Sentinel 支持SPI方式配置规则。
-
实现 InitFunc接口
-
resources/META-INF/services 下添加文件
com.alibaba.csp.sentinel.init.InitFunc 内容实现类全路径
bash
com.codetonight.rule.CustomerRuleInitFunc
java
public class CustomerRuleInitFunc implements InitFunc {
@Override
public void init() throws Exception {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setCount(5);
rule.setResource("customer");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setLimitApp("default");
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
}
配置文件
配置Sentinel Dashboard ip和端口
bash
spring.cloud.sentinel.transport.dashboard=yourIp:8080
限流使用方式
-
SphU.entry(资源名称)
触发限流规则会抛出 BlockException,捕获该异常进行熔断处理、服务降级等逻辑
-
SphO.entry(资源名称)
触发限流规则 该方法会返回 false,需要与SphO.exit();搭配使用
- @SentinelResource(value = "资源名称",blockHandler = "blockHandler")
触发限流会调用blockHandler, blockHandler指定的方法,在原来参数列表上多了BlockException, 可以在blockHandler实现熔断逻辑、服务降级。
示例代码
java
@GetMapping("/testBlock")
public String testBlock(){
try(Entry entry = SphU.entry("hello")){
return "OK";
}catch (BlockException e){
return "BlockException";
}
}
@GetMapping("/testBlock2")
public String testBlock2(){
if(SphO.entry("hello")){
SphO.exit();
return "OK";
}else {
return "BlockException";
}
}
@GetMapping("/say")
@SentinelResource(value = "hello",blockHandler = "blockHandlerHello")
public String say(){
return "Hello world";
}
public String blockHandlerHello(BlockException e){
if(e != null){
e.printStackTrace();
}
return "限流了";
}
<!-- Spring Cloud Alibaba Sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
总结
通过sentinel组件很容易对相关接口进行限流,只需要配置相应的规则即可,sentinel提供了Sentinel Dashboard,在控制台调整规则的参数,无需重启应用即可生效。使用方式支持注解方式 @SentinelResource,可以做到对业务代码无入侵。