Sentinel 的限流操作是在 前几篇相关博文的代码基础上 修改的!!!!!
https://blog.youkuaiyun.com/lettuce_/article/details/102568573
限流:
当我们设计了一个函数,准备上线,这时候这个函数会消耗一些资源,处理上限是1秒服务3000个QPS,但如果实际情况遇到高于3000的QPS该如何解决呢?Sentinel提供了两种流量统计方式,一种是统计并发线程数,另外一种则是统计 QPS,当并发线程数超出某个设定的阀值,新的请求会被立即拒绝,当QPS超出某个设定的阀值,系统可以通过直接拒绝、冷启动、匀速器三种方式来应对,从而起流量控制的作用。
基本概念:
资源Resource:可以是任意对象,一个字符串、一个方法,一个类对象;
规则Rule:需要如何限制或者降级,比如按照“QPS/失败比率”做出相应的处理;
入口Entry:每次资源调用都会创建一个Entry对象,Entry 创建的时候,同时也会创建一系列功能插槽
(slot chain),链里面的slot各司其职,比如其中的FlowSlot 则用于根据预设的限流规则
以及前面 slot 统计的状态,来进行流量控制,DegradeSlot 则通过统计信息以及预设的规则,来
做熔断降级;AuthoritySlot 则根据配置的黑白名单和调用来源信息,来做黑白名单控制;
操作:
1. 添加 jar包依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>0.2.1.RELEASE</version>
</dependency>
有些博客说 引入许多依赖:
但这些 使用 spring-cloud-starter-alibaba-sentinel 一个就可以引入全部
2. 修改配置文件
和上一篇博文的配置文件一样,具体可查询上一篇博文
3. 限流方式
3.1 使用 抛异常方式:
try (Entry entry=SphU.entry("resourceName")){
//被保护的业务逻辑代码块(资源)
//do something here
}catch(BlockException e){
//阻止资源访问
//相关限流降级操作
}finally{
if (entry!=null){
entry.exit();
}
}
3.2 使用 返回Boolean 值方式:
当程序发生限流后,会返回false值,这时可根据返回值进行限流后的逻辑操作处理
if (SphO.entry("被保护的业务(资源)名")){
try{
//被保护的业务逻辑(资源)
}finally{
SphO.exit();
}
}else {
//阻止资源访问
//相关限流降级操作
}
3.3 使用 注解方式:(推荐)
主要使用 @SentinelResource 注解,该注解定义在需要限流操作的接口的方法上。
属性 | 作用 | 是否必须 |
value | 资源名称 | 是 |
entryType | entry类型,标记流量的方向,取值IN/OUT,默认是OUT | 否 |
blockHandler | 处理BlockException的函数名称。函数要求: 1. 必须是 public 2.返回类型与原方法一致 3. 参数类型需要和原方法相匹配,并在最后加 BlockException 类型的参数。4. 默认需和原方法在同一个类中。若希望使用其他类的函数,可配置 blockHandlerClass ,并指定blockHandlerClass里面的方法。 | 否 |
blockHandlerClass | 存放blockHandler的类。对应的处理函数必须static修饰,否则无法解析,其他要求:同blockHandler。 否 fallback 用于在抛出异常的时候提供fallback处理逻辑。fallback函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。函数要求:1. 返回类型与原方法一致 2. 参数类型需要和原方法相匹配,Sentinel 1.6开始,也可在方法最后加 Throwable 类型的参数。3.默认需和原方法在同一个类中。若希望使用其他类的函数,可配置 fallbackClass ,并指定fallbackClass里面的方法。 | 否 |
fallback | 用于在抛出异常的时候提供fallback处理逻辑。fallback函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。函数要求:1. 返回类型与原方法一致 2. 参数类型需要和原方法相匹配,Sentinel 1.6开始,也可在方法最后加 Throwable 类型的参数。3.默认需和原方法在同一个类中。若希望使用其他类的函数,可配置 fallbackClass ,并指定fallbackClass里面的方法。 | 否 |
fallbackClass【1.6】 | 存放fallback的类。对应的处理函数必须static修饰,否则无法解析,其他要求:同fallback。 | 否 |
defaultFallback【1.6】 | 用于通用的 fallback 逻辑。默认fallback函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。若同时配置了 fallback 和 defaultFallback,以fallback为准。函数要求:1. 返回类型与原方法一致 2. 方法参数列表为空,或者有一个 Throwable 类型的参数。3. 默认需要和原方法在同一个类中。若希望使用其他类的函数,可配置 fallbackClass ,并指定 fallbackClass 里面的方法。 | 否 |
exceptionsToIgnore【1.6】 | 指定排除掉哪些异常。排除的异常不会计入异常统计,也不会进入fallback逻辑,而是原样抛出。 | 否 |
exceptionsToTrace | 需要trace的异常 | Throwable |
TIPS
- 1.6.0 之前的版本 fallback 函数只针对降级异常(
DegradeException
)进行处理,不能针对业务异常进行处理。 - 若 blockHandler 和 fallback 都进行了配置,则被限流降级而抛出
BlockException
时只会进入blockHandler
处理逻辑。若未配置blockHandler
、fallback
和defaultFallback
,则被限流降级时会将BlockException
直接抛出。 - 从 1.4.0 版本开始,注解方式定义资源支持自动统计业务异常,无需手动调用
Tracer.trace(ex)
来记录业务异常。Sentinel 1.4.0 以前的版本需要自行调用Tracer.trace(ex)
来记录业务异常。
1. 在controller的限流方法上添加注解
@Controller
public class ProductController {
@Autowired
ProductService productService;
/**
* 被限流 的方法
* @param m
* @return
*/
//value 随便命名,后规则中会调用该名
@SentinelResource(value = "getProducts")
@RequestMapping("/getProducts")
public Object products(Model m) {
List<Product> ps = productService.listProducts();
m.addAttribute("ps", ps);
return "products";
}
}
2. 定义限流的规则类
@Component
public class RuleConfig implements CommandLineRunner {
public void initFlowRule(){
FlowRule flowRule=new FlowRule();
flowRule.setResource("getProducts");//@SentinelResource 中定义的value
flowRule.setCount(1); //限流阈值
flowRule.setGrade(1); // 限流阈值类型(QPS 或并发线程数),默认为1 QPS
//将该规则加载进 系统中
List<FlowRule> list=new ArrayList<>();
list.add(flowRule);
FlowRuleManager.loadRules(list);
}
@Override
public void run(String... args) throws Exception {
this.initFlowRule();
}
}
一条限流规则主要由下面几个因素组成:
resource:资源名,即限流规则的作用对象
count: 限流阈值
grade: 限流阈值类型(QPS 或并发线程数)
limitApp: 流控针对的调用来源,若为 default 则不区分调用来源
strategy: 调用关系限流策略
controlBehavior: 流量控制效果(直接拒绝、Warm Up、匀速排队)
为实现在项目 启动后,规则类加载进系统中运行,有两种方式:
A. 需让规则类实现springboot的 CommandLineRunner 接口,并在该类上添加@Component 注解
CommandLineRunner 详情查看:https://www.cnblogs.com/myblogs-miller/p/9046425.html
B. 使用 @Configuration 配合 @PostConstruct 注解使用(两种方式效果一样)
@Configuration
public class RuleConfig{
@PostConstruct
public void initFlowRule(){
FlowRule flowRule=new FlowRule();
flowRule.setResource("getProducts");//@SentinelResource 中定义的value
flowRule.setCount(1); //限流阈值
flowRule.setGrade(1); // 限流阈值类型(QPS 或并发线程数),默认为1 QPS
//将该规则加载进 系统中
List<FlowRule> list=new ArrayList<>();
list.add(flowRule);
FlowRuleManager.loadRules(list);
System.out.println("*************限流规则 initFlowRule() 已加载");
}
}
3. 启动项目,快速多次访问 接口出现异常,限流成功
关于出现FlowException 的解释: (FlowException 的父类为BlockException)
controlBehavior
流控策略,主要是发生拦截后具体的流量整形和控制策略,目前有三种策略,分别是:
CONTROL_BEHAVIOR_DEFAULT
这种方式是:直接拒绝,该方式是默认的流量控制方式,当 qps 超过任意规则的阈值后,新的请求就
会被立即拒绝,拒绝方式为抛出FlowException。
这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位。
CONTROL_BEHAVIOR_WARM_UP
这种方式是:排队等待 ,又称为 冷启动。该方式主要用于当系统长期处于低水位的情况下,
流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。
通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个
预热的时间,避免冷系统被压垮的情况。
CONTROL_BEHAVIOR_RATE_LIMITER
这种方式是:慢启动,又称为 匀速器模式。这种方式严格控制了请求通过的间隔时间,也即是让
请求以均匀的速度通过,对应的是漏桶算法。
这种方式主要用于处理间隔性突发的流量,例如消息队列。想象一下这样的场景,在某一秒有
大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐
渐处理这些请求,而不是在第一秒直接拒绝多余的请求。
4. 处理 FlowException 异常
创建一个 用来处理异常的类,类中定义出现异常后处理的方法,与@SentinelResource 相对应
public class BlockExceptionUtil {
public static Object returnBlockExceptionInfo(Model m, BlockException e){
Product product=new Product();
product.setId(0);
product.setName("你的访问太频繁,请稍后");
List<Product> ps = new ArrayList<>();
ps.add(product);
m.addAttribute("ps", ps);
System.out.println("BlockException 被执行");
return "products";
}
}
修改 @SentinelResource 注解
@SentinelResource(value = "getProducts",blockHandlerClass = BlockExceptionUtil.class,blockHandler = "returnBlockExceptionInfo")
注意:
- 如果不写blockHandlerClass ,则 blockHandler 引用的方法默认需要和原方法在同一个类中(@SentinelResource所在的类中)
- blockHandler 对应的方法必需为 static ,否则无法解析
- blockHandler 对应的方法 的传参中得加入 BlockException参数
快速多次访问 接口,则出现
相关的限流规则的种类及继承(实现)关系:
---Rule 【interface】 | ||
------AbstractRule【abstract class】 | ||
---------FlowRule【class】 | FlowRuleManager | 流量控制规则 |
---------AuthorityRule【class】 | AuthorityRuleManager | 来源访问控制规则 |
---------SysteRule【class】 | SysteRuleManager | 系统负载规则 |
---------DegradeRule【class】 | DegradeRuleManager | 熔断降级规则 |
---------ParamfRule【class】 | ParamfRuleManager | 热点参数规则 |