跳到主要内容

25、SpringCloud Alibaba Sentinel(4)流控规则

  • 流量的控制规则。
  • 在簇点链路列表中,点击/hello 后面的流控按钮:

 

出现:

 

  • 资源名:标识资源的唯一名称,默认为请求路径,也可以在客户端中使用 @SentinelResource 配置;
  • 针对来源: Sentinel 可以针对服务调用者进行限流,填写微服务名称即 spring.application.name,默认为 default,不区分来源;

阈值类型、单机阈值

QPS(Queries-per-second,每秒钟的请求数量):当调用该 api 的 QPS 达到阈值的时候,进行限流;
线程数:当调用该 api 的线程数达到阈值的时候,进行限流
是否集群:默认不集群;

流控模式

直接:当 api 调用达到限流条件的时,直接限流;
关联:当关联的资源请求达到阈值的时候,限流自己;
链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,则进行限流)。

流控效果

快速失败:直接失败;
Warm Up:根据 codeFactor(冷加载因子,默认值为 3)的值,从阈值/codeFactor,经过预热时长,才达到设置的 QPS 阈值;
排队等待:匀速排队,让请求匀速通过,阈值类型必须设置为 QPS,否则无效。

1.QPS 直接失败

演示下 QPS 直接失败设置及效果。点击簇点链路列表中/hello 请求后面的流控按钮:

 

上面设置的效果是,1 秒钟内请求/hello 资源的次数达到 2 次以上的时候,进行限流。点击新增完成该规则的设置。

 

现在,在浏览器访问:

http://localhost:8085/hello

 

 

当手速快点的时候(1 秒超过 2 次),页面返回 Blocked by Sentinel (flow limiting)。并且响应码为 429

2.线程数直接失败

2.1 添加接口

在 TestController 里面新建一个接口

//线程直接失败
@GetMapping("/thread")
public ResponseEntity<String> threadMode() throws InterruptedException {
   
     
	TimeUnit.SECONDS.sleep(1);
	return ResponseEntity.ok("hello,sentinel!") ;
}

  • 其中,我们添加了:
    TimeUnit.SECONDS.sleep(1);
  • 让线程睡 1s ,这样,更容易触发规则
  • 重启项目
  • 访问我们添加的 thread 的接口:

http://localhost:8085/thread

 

发现,页面需要等待 1s 左右才会响应,这是线程 sleep 的效果。

2.2 新增流控规则

 

 

点击新增,完成创建

 

2.3 测试该规则

浏览器快速的访问:

http://localhost:8085/thread

 

 

3.关联

访问某个接口达到一定的流控规则后,开始限制本接口

3.1 在 TestController 里面添加 api 接口

@GetMapping("/test1") 
public ResponseEntity<String> test1(){
   
      
	return ResponseEntity.ok("hello,test1") ; 
}

@GetMapping("/test2") 
public ResponseEntity<String> test2(){
   
      
	return ResponseEntity.ok("hello,test2") ; 
}

重启项目,正常的访问 test1,test2 测试:

 

 

3.2 添加规则

我们想让 test1 关联 test2,也就是说,访问 test2 接口达到某种规则后,开始限流 test1

 

上述流控规则表示:当 1 秒内访问/test2 的次数大于 2 的时候,限流/test1

 

3.3 测试规则

我们使用打开 2 个网页,密集访问/test2,然后我们手动浏览器请求/test1,看看效果

 

访问 test1:

 

发现已经开始限流了

4.链路

程序的调用可以看成为一条链路。当触发链路的某条规则后,该链路被限流

 

上图从 API 出发,可以发现有 2 条链路,分别为:

Link1–>hello–>other
Link2–>hello–>other

2 条链路在调用上,限流规则互补影响。

4.1 添加一个 Service

 

名称为(service.TestService)

 

代码为:

@Service 
public class TestService {
   
      
	public String hello(){
   
      
		return "hello" ; 
	} 
}

4.2 添加接口

@Autowired 
private TestService testService ;

@GetMapping("/link1") 
public ResponseEntity<String> link1(){
   
      
	return ResponseEntity.ok( String.format("link1,调用 test,结果为%s",testService.hello())) ; 
}

@GetMapping("/link2") 
public ResponseEntity<String> lin2(){
   
      
	return ResponseEntity.ok(String.format("link2,调用 test,结果为%s",testService.hello())) ; 
}

4.3 声明资源

我们现在把 TestService 里面的 hello 方法变成一个资源:

 

  • 注意:
  • @SentinelResource(“hello”)将该方法标识为一个 sentinel 资源,名称为 hello。然后重启测试:

 

 

4.4 添加链路规则

点击簇点链路:

 

此时我们给 hello 该资源限流:

 

 

  • 在入口资源,我们使用的是 link1,点击新增,完成对规则的添加。
  • 上述配置的意思是,当通过/link1 访问 hello 的时候,QPS 大于 2 则进行限流;言外之意就是 /link 访问 hello 请求并不受影响。

 

4.5 测试该规则

打开 link1 ,link2 接口。

 

 

快速访问 link1,再访问 link2:

 

 

访问测试 n 次,发现还是不能成功。难受!

具体的错误

5.预热 Warm Up

  • 流控效果除了直接失败外,我们也可以选择预热 Warm Up。
  • Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过”冷启动”,让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮
  • sentinel 客户端的默认冷加载因子 coldFactor 为 3,即请求 QPS 从 threshold / 3 开始,经预热时长逐渐升至设定的 QPS 阈值
  • 比如:我们给 hello 资源设置该规则。

 

 

  • 上面的配置意思是:对于/hello 资源,一开始的 QPS 阈值为 3,经过 10 秒后,QPS 阈值达到 10。
  • 新增完成后:

 

  • 快速访问/hello
    http://localhost:8085/hello

 
 

查看:

 

过程类似于下图:

 

前期在预热环境,突然的高 QPS 会导致系统直接拒绝访问,慢慢地,开始大量的介绍新的请求

 

最快的手速点刷新,一开始会常看到 Blocked by Sentinel (flow limiting)的提示,10 秒后几乎不再出现(因为你的手速很难达到 1 秒 10 下)。

6.排队等待

  • 排队等待方式不会拒绝请求,而是严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过
  • 在 TestController 里面添加接口:
private static Logger logger = LoggerFactory.getLogger(TestController.class) ;

@GetMapping("/queue") 
public ResponseEntity<String> queue(){
   
      
	logger.info("开始处理请求"); 
	return ResponseEntity.ok("ok") ; 
}

重启项目并且访问 queue 接口:

 

给 queue 添加一个限流规则:

 

点击新增完成创建

 

  • 快速访问 queue 接口,观察后台的打印:
  • 上述配置的含义是,访问/queue 请求每秒钟最多只能 1 次,超过的请求排队等待,等待超过 2000 毫秒则超时。新增该规则后,多次快速访问 localhost:8081/test1,sentinel 客户端控制台日志打印如下: