1.Sentinel介绍
官方文档地址:
https://sentinelguard.io/zh-cn/docs/introduction.html
https://github.com/alibaba/Sentinel/wiki/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。
2.下载Sentinel控制台
注:根据版本关系选择Sentinel版本
https://sca.aliyun.com/docs/2023/overview/version-explain/?spm=5176.29160081.0.0.748065cbd69hSu
控制台下载地址:https://github.com/alibaba/Sentinel/releases
本人Spring Cloud Alibaba版本是 2023.0.0.0-RC1所以选择Sentinel版本为sentinel-dashboard-1.8.6.jar
3.启动Sentinel控制台
通过命令:java -jar .\sentinel-dashboard-1.8.6.jar
默认端口为8080
访问控制台http://localhost:8080/#/login。 账密默认为sentinel/sentinel启动日志:
设置端口为8088 以及 修改账密为 test/123456 启动Sentinel
Powershell窗口
java '-Dserver.port=8088' '-Dsentinel.dashboard.auth.username=test' '-Dsentinel.dashboard.auth.password=123456' -jar .\sentinel-dashboard-1.8.6.jarcmd窗口
java -Dserver.port=8088 -Dsentinel.dashboard.auth.username=test -Dsentinel.dashboard.auth.password=123456 -jar D:\sentinel\sentinel-dashboard-1.8.6.jar启动日志:
更多控制台配置项可查看地址: https://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0
也可以写一个bat批处理文件,双击运行,不用每次都写命令:
4.整合Sentinel
1.引入SpringCloud Alibaba sentinel依赖
<dependencies><!-- SpringCloud Alibaba sentinel--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency>
</dependencies>
2.
添加yml配置,为项目模块设置sentinel控制台地址
配置好之后,先访问项目模块中的一个接口然后可在Sentinel控制台中查看
spring:application:name: @artifactId@profiles:active: ${profiles.active}cloud:nacos:discovery:server-addr: 127.0.0.1:8848config:server-addr: ${spring.cloud.nacos.discovery.server-addr}sentinel:transport:dashboard: 127.0.0.1:8088web-context-unify: false #流控模式为链路时将调用链路放开,不进行默认收敛
5.Sentinel控制台规则介绍
1)实时监控
查看每个接口QPS信息
2)簇点链路
实时的去拉取指定客户端(显示到sentinel控制台的服务)接口的运行情况。它一共提供两种展示模式:一种用树状结构展示资源的调用链路,另外一种则不区分调用链路展示资源的实时情况。
注意: 簇点链路监控是内存态的信息,它仅展示启动后调用过的资源。
3)流控规则(flow control)
监控应用流量的QPS或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。
应用场景:应对洪峰流量:秒杀,大促,下单,订单回流处理,付费场景,Api Gateway 网关。
通常会在服务提供端进行流控。
3.1)QPS
每秒请求数,就是说服务器在一秒的时间内处理了多少个请求。设置每秒超过2个请求便进行流控:
多余的请求被流控:
自定义流控信息:
@SentinelResource注解介绍:https://github.com/alibaba/Sentinel/wiki/%E6%B3%A8%E8%A7%A3%E6%94%AF%E6%8C%81
@GetMapping("/testUser")@SentinelResource(value = "testUser",blockHandlerClass = {BlockHandler.class},blockHandler = "flowBlockHandler")public AjaxResult user() {AjaxResult ajax = AjaxResult.success();return ajax;}
public class BlockHandler {public static AjaxResult flowBlockHandler(BlockException blockException){AjaxResult ajax = AjaxResult.error("服务器繁忙,请稍后再试");return ajax;}}
流控信息如下:
3.2)并发线程数
并发数控制通常在调用端进行配置。
用于保护业务线程池不被慢调用耗尽。Sentinel并发控制不负责创建和管理线程池,而是简单统计当前请求上下文的线程数目(正在执行的调用数目),如果超出阈值,新的请求会被立即拒绝。
QPS设置1和并发线程数设置为1区别:
QPS:每秒请求数为1。
并发线程数:当我第一个请求进来,如果一直在处理中,没有响应。其他请求会被排除。等第一个请求处理完了,其他才会进来。
接口处理逻辑睡眠2s钟:
@GetMapping("/testUser")@SentinelResource(value = "testUser",blockHandlerClass = {BlockHandler.class},blockHandler = "flowBlockHandler")public AjaxResult user() {try {Thread.sleep(2000);} catch (InterruptedException e) {throw new RuntimeException(e);}AjaxResult ajax = AjaxResult.success();return ajax;}
流控信息如下:
3.3)流控模式
基于调用关系的流量控制。调用关系包括调用方、被调用方;一个方法可能会调用其他方法,形成一个调用链路的层次关系。直接:接口调用达到设置的阈值后直接被流控抛出异常。关联:当两个接口之间具有资源争抢或者依赖关系的时候,这两个接口便有了关联。比如对数据库同一个字段的读操作和写操作存在争抢,读的速度过高会影响写的速度,写的速度过高会影响读的速度。如果放任读写操作争抢资源,则争抢本身带来的开销会降低整体的吞吐量。可使用关联限流来避免具有关联关系的资源之间过度的争抢,举例来说,read_db和write_db这两个资源分别代表数据库读写,我们可以给read_db设置限流规则来达到写优先的目的。准备两个方法:写方法addTest、读方法getTest
@GetMapping("/addTest")@SentinelResource(value = "addTest",blockHandlerClass = {BlockHandler.class},blockHandler = "flowBlockHandler")public AjaxResult addTest() {AjaxResult ajax = AjaxResult.success();return ajax;}@GetMapping("/getTest")@SentinelResource(value = "getTest",blockHandlerClass = {BlockHandler.class},blockHandler = "flowBlockHandler")public AjaxResult getTest() {AjaxResult ajax = AjaxResult.success();return ajax;}
如果addTest 接口每秒钟访问超过2次,则对getTest 进行限流。
借助JMeter进行测试
当JMmeter执行addTest时,访问getTest。会发现getTest被流控。
链路:根据调用链路入口限流。
当一个业务方法被多个请求调用,可以通过配置该方法使某一个请求进行流控。addTest 调用testFun
getTest 调用testFun
@Component
public class SysLoginService {@SentinelResource(value = "testFun",blockHandlerClass = {BlockHandler.class},blockHandler = "flowBlockHandler")public AjaxResult testFun(){return AjaxResult.success("业务方法");}
}
@GetMapping("/addTest")@SentinelResource(value = "addTest",blockHandlerClass = {BlockHandler.class},blockHandler = "flowBlockHandler")public AjaxResult addTest() {return loginService.testFun();}@GetMapping("/getTest")@SentinelResource(value = "getTest",blockHandlerClass = {BlockHandler.class},blockHandler = "flowBlockHandler")public AjaxResult getTest() {return loginService.testFun();}
对testFun方法资源进行设置,当每秒钟超过2次调用该方法资源,则对addTest进行流控。
addTest被流控:
getTest都可以正常访问:
3.4)流控效果
快速失败:默认的流控效果,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出FlowException,这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时。Warm Up(激增流量):即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过“冷启动”让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。
冷加载因子:codeFactor默认为3,即请求QPS从threshold(阈值)/3开始,经预热时长逐渐升至设定的QPS阈值。以下配置指:5秒钟后才会一次性接受10个请求:
多测几组会发现 结果会在设定的【预热时长】基础上加个2s左右。第一组测试结果:
第二组测试结果:
排队等待(脉冲流量):会严格控制请求通过的间隔时间,即让请求以均匀的速度通过。
主要用于处理间隔性突发的流量,例如消息队列,在某一秒有大量的请求到来,而接下来的几秒钟则处于空闲状态。我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求。
注:暂不支持QPS > 1000的场景。通过JMeter模拟脉冲流量
测试结果:拒绝的QPS都为0,表明在超时时间5s内,所有的QPS都被处理。
进一步验证:同样的JMeter设置,改变流控效果,设置为快速失败,会发现每秒钟超过5个请求的被流控。
4)熔断降级
通常在服务消费端进行配置。熔断降级官方介绍地址:https://github.com/alibaba/Sentinel/wiki/%E7%86%94%E6%96%AD%E9%99%8D%E7%BA%A7
概述:
除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。一个服务常常会调用别的模块,可能是另外的一个远程服务、数据库,或者第三方 API 等。例如,支付的时候,可能需要远程调用银联提供的 API;查询某个商品的价格,可能需要进行数据库查询。然而,这个被依赖服务的稳定性是不能保证的。如果依赖的服务出现了不稳定的情况,请求的响应时间变长,那么调用服务的方法的响应时间也会变长,线程会产生堆积,最终可能耗尽业务自身的线程池,服务本身也变得不可用。
4.1)熔断策略
慢调用比例:选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。最大RT:单位ms,当前资源接口允许的最大响应时间,大于当前设置的时间,就属于慢调用。
比例阈值:出现慢调用的比例(0-1之间),比如设置为0.1表示,10次请求出现一次就会熔断。
熔断时长:进入熔断状态的时长(单位s)。熔断时长过完之后,熔断器进入半开状态,如果再次请求响应时间大于设置的最大 RT,直接进入熔断状态。
最小请求数:最少请求的次数。
统计时长:单位ms,在这个时长之内请求的数目。测试:在统计时长1s请求10次,如果出现1次慢调用则进入熔断。熔断时长为10s。
接口睡眠3s:
@GetMapping("/testUser")@SentinelResource(value = "testUser",blockHandlerClass = {BlockHandler.class},blockHandler = "flowBlockHandler")public AjaxResult user() {try {Thread.sleep(3000);} catch (InterruptedException e) {throw new RuntimeException(e);}AjaxResult ajax = AjaxResult.success();return ajax;}
通过JMeter进行测试:
猜想:JMeter请求10次,在浏览器中进行第11次调用,此时会进入熔断。10s后会进行一次请求并成功,但再次请求会直接熔断。
验证结果如下:
10次都请求成功
当我在浏览器请求第11次:
10s过后请求一次:请求成功
再进行一次请求:直接熔断
异常比例:当单位统计时长内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。比例阈值:出现异常的比例(0-1之间),比如设置为0.1表示,10次请求出现一次异常就会熔断。
熔断时长:进入熔断状态的时长(单位s)。熔断时长过完之后,熔断器进入半开状态,如果再次请求还是报异常,直接进入熔断状态。
最小请求数:最少请求的次数。
统计时长:单位ms,在这个时长之内请求的数目。和慢调用比例一样的测试方法。只是java方法体内抛出的是异常,这里就不进行测试记录了。异常数:当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常数:出现异常的次数。
熔断时长:进入熔断状态的时长(单位s)。熔断时长过完之后,熔断器进入半开状态,如果再次请求还是报异常,直接进入熔断状态。
最小请求数:最少请求的次数。
统计时长:单位ms,在这个时长之内请求的数目。和异常比例一样的测试方法。只是将比例换成了次数。这里就不进行测试记录了。
5)整合OpenFeign进行降级
当服务消费者 调用 服务提供者的时候,如果服务提供者发生异常,对这个服务提供者进行降级处理。前提:nacos/sentinel/openfeign依赖都已添加。1.yml配置文件开启OpenFeign对Sentinel的支持。
#openfeign整合sentinel
feign:sentinel:enabled: true
2.添加OpenFeign接口的fallback实现类,这个类必须实现OpenFeign的接口。
3.在OpenFeign接口的@FeignClient中添加fallback配置,并指向该OpenFeign接口的fallback实现类。
4.在服务提供者方法体中加入异常代码
@RequestMapping(value = "/feignIgnore/selectUserByUserName", method = RequestMethod.GET)
public SysUser selectUserByUserName(@RequestParam(value = "userName") String userName) {int a = 1/0;return userService.selectUserByUserName(userName);
}
测试结果:断点进入降级方法。
6)热点规则
热点参数限流官方地址:https://github.com/alibaba/Sentinel/wiki/%E7%83%AD%E7%82%B9%E5%8F%82%E6%95%B0%E9%99%90%E6%B5%81
在一个接口当中,某个参数的某些值访问量大,其他的值访问量平缓,这样可以针对某些访问量大的值进行流控。以下配置为:id为5 和 6 这两个值,当每秒访问超过2次则进行限流。其他的值在每秒访问超过10次才会限流。
测试结果:
其他值:在第11次时被流控。
7)系统规则(兜底防护方案)
热点参数限流官方地址:https://github.com/alibaba/Sentinel/wiki/%E7%B3%BB%E7%BB%9F%E8%87%AA%E9%80%82%E5%BA%94%E9%99%90%E6%B5%81
Sentinel 系统自适应过载保护从整体维度对应用入口流量进行控制,结合应用的 Load、CPU 使用率、总体平均 RT、入口 QPS 和并发线程数等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。当遇到规则难配,强弱依赖难梳理时结合系统指标和服务容量,自适应动态调整流量。 系统规则支持以下的模式:
Load 自适应(仅对 Linux/Unix-like 机器生效):系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的 maxQps * minRt 估算得出。设定参考值一般是 CPU cores * 2.5。
CPU 使用率:当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏。
平均 RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。无需指定资源,直接在系统规则模块进行添加: