Sentinel入门与进阶:微服务流量控制的最佳实践 ( 二 )
4.流量控制
4.1. 什么是流量控制
流量控制在网络传输中是一个常用的概念,它用于调整网络包的发送数据。然而,从系统稳定性角度考虑,在处理请求的速度上,也有非常多的讲究。任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。我们需要根据系统的处理能力对流量进行控制。Sentinel 作为一个调配器,可以根据需要把随机的请求调整成合适的形状,如下图所示:
流量控制有以下几个角度:
- 资源的调用关系,例如资源的调用链路,资源和资源之间的关系;
- 运行指标,例如 QPS、线程数等;
- 控制的效果,例如直接限流(快速失败)、冷启动(Warm Up)、匀速排队(排队等待)等。
Sentinel 的设计理念是让您自由选择控制的角度,并进行灵活组合,从而达到想要的效果。
配置如下:
4.2. QPS流量控制
每秒查询率QPS(Query Per Second):每秒响应请求数。在互联网领域,这个指标和吞吐量区分相似。
当 QPS 超过某个阈值的时候,则采取措施进行流量控制。
流量控制的效果包括以下几种:直接拒绝、Warm Up、匀速排队。
4.2.1. 直接拒绝(快速失败)
直接拒绝(RuleConstant.CONTROL_BEHAVIOR_DEFAULT
)方式是默认的流量控制方式,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出FlowException
。这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时。
这里做一个最简单的配置:
阈值类型选择:QPS
单机阈值:3
综合起来的配置效果就是,该接口的限流策略是每秒最多允许3个请求进入。
点击新增按钮之后,可以看到如下界面:
在浏览器访问, 并疯狂刷新,出现如下信息:
4.2.2. Warm Up(预热)
Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP
)方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。
在浏览器访问, 并疯狂刷新,开始会被 拒绝 , 5秒后, 通过的请求数据增加
可以发现前几秒会发生熔断,几秒钟之后就完全没有问题了
4.2.3. 匀速排队(排队等待)
匀速排队(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER
)方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。
4.2.3.1.修改代码
package com.yuan.scasentineldashboard.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
@RestController
@RequestMapping("/sentinelTest")
public class TestController {
private int count = 1;
@RequestMapping("/sayHello")
public String sayHello(){
System.out.println("count:" + count++ + ", date:" + new Date());
return "hello";
}
}
4.2.3.2.配置postman 并测试
在postman中,新建一个collection(这里collection名称是sentinel),并把一个请求添加到该collection
请求添加成功后,点击run按钮:
配置每隔100ms发送一次请求,一共发送20个请求:
点击“run sentinel”按钮
查看 控制台, 打印 1s 打印很多次
4.2.3.3.设置 匀速排队 限流
测试配置如下:1s处理一个请求,排队等待,等待时间20s。
再通过 postman 运行测试
查看控制台,效果如下:可以看到基本每隔1s打印一次
4.2.4. 关联限流
关联限流:当关联的资源请求达到阈值时,就限流自己。
4.2.4.1.修改代码
package com.yuan.scasentineldashboard.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
@RestController
@RequestMapping("/sentinelTest")
public class TestController {
private int count = 1;
@RequestMapping("/sayHello")
public String sayHello(){
System.out.println("count:" + count++ + ", date:" + new Date());
return "hello";
}
@RequestMapping("/relationReq")
public String relationReq(){
return "relation";
}
}
4.2.4.2.分别为两个请求配置限流
sayHello 请求
relationReq 请求配置 关联限流, 关联 sayHello 请求
4.2.4.3.测试
通过 postman 对sayHello发请求:每个200ms发送一次请求,一共发送50个。每秒钟超过了3次 , 触发 sayHello限流
在浏览器中访问http://localhost:9000/sentinelTest/relationReq 已经被限流。
4.3. 线程数限流
**并发线程数限流用于保护业务线程数不被耗尽。**例如,当应用所依赖的下游应用由于某种原因导致服务不稳定、响应延迟增加,对于调用者来说,意味着吞吐量下降和更多的线程数占用,极端情况下甚至导致线程池耗尽。为应对太多线程占用的情况,业内有使用隔离的方案,比如通过不同业务逻辑使用不同线程池来隔离业务自身之间的资源争抢(线程池隔离)。这种隔离方案虽然隔离性比较好,但是代价就是线程数目太多,线程上下文切换的 开销比较大,特别是对低延时的调用有比较大的影响。Sentinel 并发线程数限流不负责创建和管理线程池,而是简单统计当前请求上下文的线程数目,如果超出阈值,新的请求会被立即拒绝,效果类似于信号量隔离。
4.3.1.修改代码
package com.yuan.scasentineldashboard.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
@RestController
@RequestMapping("/sentinelTest")
public class TestController {
private int count = 1;
@RequestMapping("/sayHello")
public String sayHello(){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("count:" + count++ + ", date:" + new Date());
return "hello";
}
@RequestMapping("/relationReq")
public String relationReq(){
return "relation";
}
}
4.3.2.设置限流
配置如下:如果请求的并发数超过一个就限流
4.3.3.测试
postman配置如下:每 10 ms 发一个请求
同时在浏览器访问:出现限流
更多推荐
所有评论(0)