前言
前两篇文件介绍了四种常见服务限流算法解析和RateLimiter+AOP自定义注解限流。我们通过自定义注解可以对我们的服务进行保护,但是这样的实现方式有没有需要完善的地方呢?
RateLimiter对服务的保护
正常情况下,ratelimiter通过对流量的限制来对服务进行保护,但是实际情况下,往往有更复杂的场景,比如A服务调用B服务超时,或者异常了,那么就没法对这种情况进行保护了。
还有就是在集群环境下,因为我们的限流是针对单个服务进行的单机版限流,所以无法对整个集群的整体流量进行限制。
因此本篇文章对阿里开源的分布式限流框架sentinel进行介绍。
sentinel
sentinel简介
官网:https://sentinelguard.io/zh-cn/docs/introduction.html
Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。
流量控制
Sentinel 可以根据需要把随机的请求调整成合适的形状,也就是进行流量整形
流量控制有以下几个角度:
- 资源的调用关系,例如资源的调用链路,资源和资源之间的关系;
- 运行指标,例如 QPS、线程池、系统负载等;
- 控制的效果,例如直接限流、冷启动、排队等。
Sentinel 的设计理念是让您自由选择控制的角度,并进行灵活组合,从而达到想要的效果。
熔断降级
除了流量控制以外,降低调用链路中的不稳定资源也是 Sentinel 的使命之一。由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳定,最终会导致请求发生堆积。这个问题和 Hystrix 里面描述的问题是一样的。
Sentinel 和 Hystrix 的原则是一致的: 当调用链路中某个资源出现不稳定,例如,表现为 timeout,异常比例升高的时候,则对这个资源的调用进行限制,并让请求快速失败,避免影响到其它的资源,最终产生雪崩的效果。
系统负载保护
Sentinel 同时提供系统维度的自适应保护能力。防止雪崩,是系统防护中重要的一环。当系统负载较高的时候,如果还持续让请求进入,可能会导致系统崩溃,无法响应。在集群环境下,网络负载均衡会把本应这台机器承载的流量转发到其它的机器上去。如果这个时候其它的机器也处在一个边缘状态的时候,这个增加的流量就会导致这台机器也崩溃,最后导致整个集群不可用。
针对这个情况,Sentinel 提供了对应的保护机制,让系统的入口流量和系统的负载达到一个平衡,保证系统在能力范围之内处理最多的请求。
Sentinel 是如何工作的
Sentinel 的主要工作机制如下:
- 对主流框架提供适配或者显示的 API,来定义需要保护的资源,并提供设施对资源进行实时统计和调用链路分析。
- 根据预设的规则,结合对资源的实时统计信息,对流量进行控制。同时,Sentinel 提供开放的接口,方便您定义及改变规则。
- Sentinel 提供实时的监控系统,方便您快速了解目前系统的状态。
springboot集成sentinel
pom引入核心依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.8.6</version>
</dependency>
先写个demo看看sentinel怎么用吧
package com.fandf.test.sentinel;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import java.util.ArrayList;
import java.util.List;
/**
* @author fandongfeng
* @date 2023/4/9 22:03
*/
public class SentinelTest {
private static void initFlowRules(){
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
//资源名称
rule.setResource("HelloWorld");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// Set limit QPS to 20.
rule.setCount(10);
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
public static void main(String[] args) {
// 配置规则.
initFlowRules();
for (int i = 0; i < 20; i++) {
//设置被保护的资源
try (Entry entry = SphU.entry("HelloWorld")) {
// 被保护的逻辑
System.out.println("hello world");
} catch (BlockException ex) {
// 处理被流控的逻辑
System.out.println("blocked!");
}
}
}
}
执行结果
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
blocked!
blocked!
blocked!
blocked!
blocked!
blocked!
blocked!
blocked!
blocked!
blocked!
@SentinelResource注解实现
1.引入pom依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
<version>1.8.6</version>
</dependency>
2.切面配置
@Bean
public SentinelResourceAspect sentinelResourceAspect() {
return new SentinelResourceAspect();
}
3.编写接口
package com.fandf.test.sentinel;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
/**
* @author fandongfeng
*/
@Slf4j
@RestController
@RequestMapping("user")
public class UserController {
@SentinelResource(value = "getUser", fallback = "getUserFallbackHandler", fallbackClass = UserController.class)
@GetMapping
public String getUser() {
log.info("user");
return "user";
}
public String getUserFallbackHandler() {
log.error("fallbackHandler");
return "您已被限流,调用失败了!";
}
@PostConstruct
public void init() {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
//资源名称
rule.setResource("getUser");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// Set limit QPS to 2.
rule.setCount(2);
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
}
后面文章我们再讲集成spring-cloud-alibaba-sentinel,以及持久化规则。