Sentinel简介
我们如何在这些业务流量变化无常的情况下,保证各种业务安全运营,系统在任何情况下都不会崩溃呢?我们可以在系统负载过高时,采用限流、降级和熔断,三种措施来保护系统,由此一些流量控制中间件诞生。例如Sentinel。
Sentinel概述
Sentinel (分布式系统的流量防卫兵) 是阿里开源的一套用于服务容错的综合性解决方案。它以流量为切入点, 从流量控制、熔断降级、系统负载保护等多个维度来保护服务的稳定性。
Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景, 例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
Sentinel核心分成两个部分
核心库(java客户端):能够运行于所有 Java 运行时环境,同时对Dubbo /Spring Cloud 等框架也有较好的支持。
控制台(Dashboard):基于spring boot开发,打包以后直接运行
安装Sentinel服务
Sentinel 提供一个轻量级的控制台, 它提供机器发现、单机资源实时监控以及规则管理等功能,其控制台安装步骤如下:
第一步:打开sentinel下载网址 下载Jar包(可以存储到一个sentinel目录),如图所示:
https://github.com/alibaba/Sentinel/releases
第二步:在sentinel对应目录,打开命令行(cmd),启动运行sentinel
java
-Dserver.port=8180
-Dcsp.sentinel.dashboard.server=localhost:8180
-Dproject.name=sentinel-dashboard
-jar
D:\TCGBIV\TOOLS\sentinel-dashboard-1.8.0.jar
检测启动过程,如图所示:
访问Sentinal服务
第一步:假如Sentinal启动ok,通过浏览器进行访问测试,如图所示:
第二步:登陆sentinel,默认用户和密码都是sentinel,登陆成功以后的界面如图所示:
Sentinel限流入门
限流的目的防止恶意请求流量、恶意攻击,或者防止流量超过系统峰值。
Sentinel集成
第一步:Sentinel 应用于服务消费方(Consumer),在消费方添加依赖如下
<!--Sentinel 应用于服务消费方(Consumer),在消费方添加依赖如下:-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--spring对Sentinel的监控,会打开一些监控的断点,深度开发必用-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
第二步:打开服务消费方配置文件application.yml,添加sentinel配置,代码如下:
spring:
cloud:
sentinel:
transport:
port: 8099 #跟sentinel控制台交流的端口,随意指定一个未使用的端口即可
dashboard: localhost:8180 # 指定sentinel控制台地址。
第三步:启动服务提供者,服务消费者,然后在浏览器访问消费者url,如图所示:
第四步:刷新sentinel 控制台,检测服务列表,如图所示:
Sentinel限流快速入门
我们设置一下指定接口的流控(流量控制),QPS(每秒请求次数)单机阈值为1,代表每秒请求不能超出1次,要不然就做限流处理,处理方式直接调用失败。
第一步:选择要限流的链路,如图所示:
第二步:设置限流策略,如图所示:
第三步:反复刷新访问消费端端服务,检测是否有限流信息输出,如图所示:
Sentinel流控规则分析
阈值类型分析
-
QPS(Queries Per Second):当调用相关url对应的资源时,QPS达到单机阈值时,就会限流。
-
线程数:当调用相关url对应的资源时,线程数达到单机阈值时,就会限流。
设置限流模式
Sentinel的流控模式代表的流控的方式,默认【直接】,还有关联,链路。
直接模式
Sentinel默认的流控处理就是【直接->快速失败】。
关联模式
当关联的资源达到阈值,就限流自己。例如设置了关联资源为/ur2时,假如关联资源/url2的qps阀值超过1时,就限流/url1接口(是不是感觉很霸道,关联资源达到阀值,是本资源接口被限流了)。这种关联模式有什么应用场景呢?我们举个例子,订单服务中会有2个重要的接口,一个是读取订单信息接口,一个是写入订单信息接口。在高并发业务场景中,两个接口都会占用资源,如果读取接口访问过大,就会影响写入接口的性能。业务中如果我们希望写入订单比较重要,要优先考虑写入订单接口。那就可以利用关联模式;在关联资源上面设置写入接口,资源名设置读取接口就行了;这样就起到了优先写入,一旦写入请求多,就限制读的请求。例如:
链路模式
假如是sentinel 1.7.2以后版本,Sentinel Web过滤器默认会聚合所有URL的入口为sentinel_spring_web_context,因此单独对指定链路限流会不生效,需要在application.yml添加如下语句来关闭URL PATH聚合,例如:
sentinel:
web-context-unify: false
链路模式只记录指定链路入口的流量。也就是当多个服务对指定资源调用时,假如流量超出了指定阈值,则进行限流。被调用的方法用@SentinelResource进行注解,然后分别用不同业务方法对此业务进行调用,假如A业务设置了链路模式的限流,在B业务中是不受影响的。例如现在设计一个业务对象,代码如下(为了简单,可以直接写在启动类内部):
@Service
public class ConsumerService{
//标注这是一个限流链路的叶子节点。
//一般来说,每一个URL会是一个节点。但是,我们可以使用@SentinelResource注解,
//来让某一个方法也会成为链路中的子节点"()"中的内容将作为链路节点的名
@SentinelResource("doGetResource")
public String doGetResource(){
return "doGetResource";
}
}
接下来我们在/consumer/doRestEcho1对应的方法中对ConsumerService中的doGetResource方法进行调用(应用consumerService对象之前,要先在doRestEcho01方法所在的类中进行consumerService值的注入)。例如:
@RestController
public class ConsumerController{
@Autowired
private ConsumerService consumerService;
//http://ip:port/consumer/doRestEcho1
@GetMapping("/consumer/doRestEcho1")
public String doRestEcho1(){
//第一次加入doGetResource方法
consumerService.doGetResource();
...
}
@GetMapping("/consumer/doRestEcho2")
public String doRestEcho2 (){
//第二次加入doGetResource方法
consumerService.doGetResource();
...
}
}
其路由规则配置如下:
增加了限流对象的链路会被限流
如果不添加限流路径的对象,仅对对象进行限流:双方都会被限流
预热
阈值除以coldFactor(默认值为3),经过预热时长后才会达到阈值。设置的单机阈值为100,预热时长为10s。那么初始并发就是100/3=33。经过10s,并发阈值增加到100
:秒杀系统在开启的瞬间,会有很多流量上来,很有可能把系统打死,预热方式就是把为了保护系统,慢慢的把阈值增长到设置的阈值。
排队等待
从字面上面就能够猜到,匀速排队,让请求以均匀的速度通过,阈值类型必须设成QPS,否则无效。比如有时候系统在某一个时刻会出现大流量,之后流量就恢复稳定,可以采用这种排队模式,大流量来时可以让流量请求先排队,等恢复了在慢慢进行处理。超过设定的时间才会设置为超时
小结
限流模式:限制某个服务的特定时常内的并发数量
关联模式:当关联的某个服务达到阈值,就会限制自身的的服务资源,将多余资源供给给对方。
链路限流的作用:只限制某一个簇点链路中的特定服务做限制,且不影响其他链路中的相同服务
预热:初始并发只有并发上限/coldFactor(默认为3),即默认33%的初始并发,进过设定数组的量后逐渐增加到上线的并发量
排队等待,设定固定的并发值,超过量级之后才会排队等待,排队时间超过等待时常才会超时无效
sentinel是什么?(阿里推出的一个流量控制平台,防卫兵)
类似Sentine的产品你知道什么?(hystrix一代微服务产品)
你了解哪些限流算法?(计数器,令牌桶,漏斗算法,滑动窗口算法...)
sentinel的默认限流算法是什么(滑动窗口算法)
你了解sentinel中的阈值应用类型吗?(线程数,ops)
默认的限流模式有哪些?(直连,关联,链路)
限流效果有哪些(快速失败,预热,排队)
sentinel为什么可以进行限流?
访问web时会有拦截器对url进行拦截,根据控流规则对流量进行控制
熔断
,如果调用链路中的某个资源不稳定,最终会导致请求发生堆积。
Sentinel 熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出 DegradeException)。
慢调用比例
慢调用熔断设置的参数说明:
最大RT | 设置的阈值,响应时间超过该阈值标记为不稳定状态应用 |
比例阈值 | 慢调用占所有的调用比例,范围0~1 |
熔断时长 | 如果发生熔断,停止服务的时间长度 |
最小请求数 | 允许通过的最小请求数,该数量内不熔断 |
熔断:当响应超时时,掐断传输链接。在设定的时间内,无法再访问服务器。若未指定异常,后台会通报异常DegradeException(降级异常),熔断时长为用户自定义设置
探测:当熔断过了定义的熔断时长,状态由熔断变成探测
关闭:如果接下来的请求小于Rt,说明慢调用已经恢复,结束熔断,状态由探测转为关闭,如果接下来一个请求大于RT,说明慢调用未恢复,继续熔断,熔断时长保持一致
注意:Sentinel默认统计的RT上限是4900ms,超出此阈值的都会算作4900ms,若需要变更此上限可以通过启动配置项-Dcsp.sentinel.statistic.max.rt=xxx来配置
系统提供了默认的异常处理机制,假如默认处理机制不满足我们需求,我们可以自己进行定义。定义方式上可以直接或间接实现BlockExceptionHandler接口,并将对象交给spring管理。
异常比例
当资源的每秒请求数大于等于最小请求数,并且异常总数占通过量的比例超过比例阈值时,资源进入降级状态。
属性 | 说明 |
异常比例阈值 | 发生的异场请求数/请求总数(0~1) |
熔断时长 | 持续停止访问的时间 |
最小请求数 | 运行通过的最小请求数,在此数量内不会熔断 |
异常比例中的状态分析如下:
熔断(OPEN):当请求数大于最小请求并且异常比例大于设置的阈值时触发熔断,熔断时长由用户设置。
探测(HALFOPEN):当超过熔断时长时,由熔断(OPEN)转为探测(HALFOPEN)
关闭(CLOSED):如果接下来的一个请求未发生错误,说明应用恢复,结束熔断,状态由探测(HALF_OPEN)变更为关闭(CLOSED)。如果接下来的一个请求继续发生错误,说明应用未恢复,继续熔断,熔断时长保持一致。
异常数量
当资源近1分钟的异常数目超过阈值(异常数)之后会进行服务降级。注意,由于统计时间窗口是分钟级别的,若熔断时长小于60s,则结束熔断状态后仍可能再次进入熔断状态。
属性 | 说明 |
异常比例阈值 | 发生的异场请求数 |
熔断时长 | 持续停止访问的时间 |
最小请求数 | 运行通过的最小请求数,在此数量内不会熔断 |
基于异常数的状态分析如下:
熔断(OPEN):当请求数大于最小请求并且异常数量大于设置的阈值时触发熔断,熔断时长由用户设置。
探测(HALFOPEN):当超过熔断时长时,由熔断(OPEN)转为探测(HALFOPEN)
关闭(CLOSED):如果接下来的一个请求未发生错误,说明应用恢复,结束熔断,状态由探测(HALF_OPEN)变更为关闭(CLOSED)如果接下来的一个请求继续发生错误,说明应用未恢复,继续熔断,熔断时长保持一致。
熔断异常自定义处理
@Component
public class ServiceBlockExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
//response.setStatus(601);
//设置响应数据的编码
response.setCharacterEncoding("utf-8");
//告诉客户端要响应的数据类型以及客户端以什么编码呈现数据
response.setContentType("text/html;charset=utf-8");
PrintWriter pw=response.getWriter();
Map<String,Object> map=new HashMap<>();
if(e instanceof DegradeException){//降级、熔断
map.put("status",601);
map.put("message", "服务被熔断了!");
}else if(e instanceof FlowException){
map.put("status",602);
map.put("message", "服务被限流了!");
}else{
map.put("status",603);
map.put("message", "Blocked by Sentinel (flow limiting)");
}
//打印异常
e.printStackTrace();
//将map对象转换为json格式字符串
String jsonStr=new ObjectMapper().writeValueAsString(map);
pw.println(jsonStr);
pw.flush();
}
}
小结
降级的策略有哪些(慢调用,异常比例,异常数)
熔断处理逻辑中的有哪些状态?(Open,HalfOpen,Closed)
熔断之后出于什么状态(熔断打开状态Open,在次访问情况依旧,会继续熔断)
熔断时长到期后处于什么部分(探测-HalfOpen)
熔断恢复正常之后,会处于什么状态?(熔断关闭-closed)
何为熔断?(让外部应用停止对服务的访问,生活中跳闸,此路不通)
为什么要熔断?(让服务器休息一下,外部应用停止对服务的访问。平均响应速度越来越慢或经常出现异常,这样可能会导致调用链堆积,最终系统崩溃)
Sentinel中限流,降级的异常什么,父类是谁?(DegradeException,BlockException)
sentinel出现异常时处理的接口是谁?(BlockExceptionHandler)
Sentinel中处理接口下默认的现实类是(DefaultBlockExceptionHandler)
加入Sentinel默认的异常处理规则不满足我们的需求怎么办(自定义)
如何自定义Sentinel的异常处理规则呢(直接或间接实现BlockExceptionHandler)
热点
热点就是经常访问的数据
设置某个数据为热点数据,对这个数据的访问进行限流
第一步:使用@SentinelResoutc(“命名限流节点”)创建一个节点
//http://ip:port/consumer/doFindById?id=10
@GetMapping("/consumer/findById")
@SentinelResource("res")
public String doFindById(@RequestParam("id") Integer id){
return "resource id is "+id;
}
第二步:服务启动后,选择要限流的热点链路,如图所示:
第三步:设置要限流的热点,如图所示:
热点限流只有QPS模式。参数索引表示网页URL?后面携带的参数,第一个参数的索引就是0,第二个是1....
单机阈值和统计时长表示此窗口在规定时间内访问的数量超过阈值,就进行限流
第四步:多次访问热点参数方法,前端会出现如下界面,如图所示:
此时后台通报的异常信息
com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException: 2
特定参数设计
配置参数例外项,如图所示:
对参数值为5时阈值为100,其它参数值阈值为1,例如当我们访问http://ip:port/consumer/doRestEcho1?id=5时的限流阈值为100。
小结面试分析
如何理解热点数据————访问频率较高的数据,热销商品,流行元素
热点限流规则是怎样的?————主要是针对参数进行限流设计
热点数据的特殊参数如何理解————针对某个特定值的特殊限流规则
对于热点数据的访问出现限流以后的底层异常是什么?————ParamFlowException
Sentinel系统规则
Load(仅对Linux生效):当load1超过阈值,且当前系统的并发现场数炒货系统容量时候才会触发系统包会,系统容量由系统的maxQps*minRt计算得出,参考值一般是CPU cores*2.5
cpu使用率:当cpu使用频率超过阈值触发保护
RT:当机器上所有入口流量的并发线程达到阈值即触发保护,单位是毫秒
线程数:机器上的线程数到达上限触发保护
入口QPS:当流量的QPS达到阈值触发系统保护
如何理解sentinel中的系统规则?(是对所有链路的一种规则控制,是一种系统保护策略)
Sentinel的常用规则有哪些?(RT,QPS,CPU,线程,Load-linux,unix)
Sentinel系统保护规则被处罚之后底层会抛出什么异常(SystemBlockException)
Sentinel授权规则
资源名:限流的作用对象
控流应用:对应的黑白名单设置的规则值,多个,隔开
授权类型:白名单(放行),黑名单(不允许访问)
第一步,定义请求解析器,队请求进行解析,判断是否符合要求
@Component
public class DefaultRequestOriginParser implements RequestOriginParser {
/**
* 定义一个请求源解析对象,并基于此对象对请求中制定数据进行解析
*然后Sentinel底层会对此接口方法的返回值基于规则定义进行解析处理
*/
//解析请求源数据
@Override
public String parseOrigin(HttpServletRequest request) {
//请求参数进行限制
//获取请求参数数据,名字可以自己写
//http://ip:port/path?orgin=app1
//return request.getParameter("origin");
//对ip进行限制
String ip = request.getRemoteAddr();
System.out.println(ip);
return ip;
}//授权规则中的黑白名单的值,来自此方法的返回值
}
第二步:定义流控规则,如图所示:
第三步:执行资源访问,检测授权规则应用
设计过程分析
小结
如何理解Sentinel中的授权规则? 对制定资源访问给出的一种简易的授权策略
Sentinel的授权规则是如何设计的? 黑(不可访问)/白(允许访问)名单
如何识别黑白名单? 在拦截器中通过调用RequestOriginParser对象的方法检测具体的规则
授权规则中RequesOriginParser类的作用是什么?
对控流应用值进行解析,检查服务访问时的传入值是否与RequestOriginParser的ParserOrigin是否一致
重点
Sentinel诞生的背景? 计算机的处理是有限的,但是并发的量是不确定的
服务中心Sentinel环境的集成,初始化? 添加依赖,sentinel配置
sentinel限流规则(阈值类型:QPS,线程数。 限流模式:关联,直接,链路)
sentinel降级,熔断的策略? 慢调用。比例异常,异常数
sentinel热点规则设计? 针对数据进行控制
Sentinel系统规则设计? 掌握全局规则定义,针对所有请求有效
sentine授权规则设计? 黑白名单
FAQ分析
为什么要限流? 服务器的处理能力是有限的,并发的量是不确定的
你了解的限流框架: Sentinel
常见的限流算法: 令牌桶,漏斗,滑动,计数
sentinel限流规则: qps,线程数
sentinel限流模式:直接,关联,链路
sentinell的降级和熔断的策略有哪些:慢调用,响应时间长,异常比例,异常占比,异常数
sentinel的热点规则中的热点数据: 流行元素,热点信息
sentinel的黑白名单:黑(不可访问,拦截)白(放行通过)