和珅有宋朝时期的汝窑三足笔洗,这俩件是举世罕见的宝贝,全天下也找不到第三只,当时这一对就花了一万两银子。但是和珅得手后,却立马砸碎了一只,这样全天下就只剩下一只了,剩下那只的价值立刻翻了10倍!
SpringCloud Alibaba Sentinel:也被称为分布式系统的流量防卫兵
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。
Sentinel以流量为切入点,熊流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性【流量就是客户端请求】
Sentinel 的历史:
- 2012 年,Sentinel 诞生,主要功能为入口流量控制。
- 2013-2017 年,Sentinel 在阿里巴巴集团内部迅速发展,成为基础技术模块,覆盖了所有的核心场景。Sentinel 也因此积累了大量的流量归整场景以及生产实践。
- 2018 年,Sentinel 开源,并持续演进。
- 2019 年,Sentinel 朝着多语言扩展的方向不断探索,推出 C++ 原生版本,同时针对 Service Mesh 场景也推出了 Envoy 集群流量控制支持,以解决 Service Mesh 架构下多语言限流的问题。
- 2020 年,推出 Sentinel Go 版本,继续朝着云原生方向演进。
Sentinel 分为两个部分:
核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。
控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。
安装运行Sentinel
1、Sentinel控制台
下载jar包
保存的地方不能有中文和空格(我这次就有中文,吃过一次亏了。。。。)
让jar包运行起来
sentinel控制台,默认端口号是8080
如果想指定端口:
在小黑窗中执行:java -Dserver.port=8088 -jar sentinel-dashboard-1.8.1.jar
访问Sentinel控制台
Sentinel启动后,访问http://localhost:8080/,登录账号密码均为sentinel
登录成功页面,此时页面为空,因为还没有监控任何服务。sentinel是懒加载的,如果服务没有被访问,看不到该服务信息。
2、Sentinel入门案例
创建工程 cloudalibaba-sentinel-service8401
1、核心依赖
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>
2.application.yml配置文件
8719这个端口的作用
server: port: 8401 spring: application: name: cloudalibaba-sentinel-service cloud: nacos: discovery: server-addr: localhost:8848 sentinel: transport: dashboard: localhost:8080 port: 8719 #默认8719,应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用HttpServer management: endpoints: web: exposure: include: '*'
3、主启动
4、controller层写点东西,好测试
@RestController @Slf4j public class FlowLimitController{ @GetMapping("/testA") public String testA() { return "------testA"; } @GetMapping("/testB") public String testB() { return "------testB"; } }
测试
先启动本地的nacos,怎么启动看我上一篇文章,不再多说 22-07-24 西安 SpringCloud(03) SpringCloud alibaba、Nacos、CAP和Base_£小羽毛的博客-CSDN博客
再启动该工程 :cloudalibaba-sentinel-service8401
1、查看Sentinel控制台,空空如也,因为Sentinel是懒加载
查看nacos控制台,不出所料
2、执行访问
再查看Sentinel控制台,就有了
Sentinel流控规则
1、QPS 每秒查询率
通常使用QPS衡量一个接口的性能(处理能力)
是 一台服务器 每秒能够相应的查询次数,是对一个特定的查询服务器 在规定时间内 所处理流量多少的衡量标准, 即每秒的响应请求数,也即是最大吞吐能力。
当 QPS 超过某个阈值时,采取措施 流量控制。流量控制的效果包括以下几种: 直接拒绝、Warm Up、匀速排队。
2、三种流控模式
流控模式分3种:直接、关联,链路
直接 快速失败 是默认的流量控制方式
1.资源名目前呢是请求路径,一会就不这么用了,会改为资源名。现在是针对某一个请求
2.先演示最简单的“直接 快速失败”(达到限流条件时,直接抛出异常)
3.测试演示
QPS单机阈值为1表示:1秒钟内查询1次就是OK,若超过次数1,就直接-快速失败,报默认错误
关联-快速失败
当关联资源/testB的QPS阀值超过1时,就限流/testA的REST访问地址
挺考验手速,不过对我而言还不是轻而易举
3、postman里新建多线程集合组【不推荐】
当然,要是你手速不够,我们可以借助与postman。推荐使用jmeter
22-07-22 西安 SpringCloud(02) Hystrix断路器、jmeter并发测试、Gateway网关、分布式链路请求跟踪_£小羽毛的博客-CSDN博客
postman里新建多线程集合组,将请求保存到集合组
1、qq
2、运行线程集合组
3、在弹出的新窗口设置并发访问参数
这个期间去访问必然是这种结果
链路
只记录指定链路上的流量,指定资源从入口资源进来的流量达到阈值,就进行限流
4、三种流控效果
快速失败
上面演示都用的流控效果 “快速失败”,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出FlowException
直接失败,抛出异常:Blocked by Sentinel (flow limiting)
预热 Warm Up
即预热/冷启动方式。
当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。
阈值除以coldFactor(coldFactor默认值为3),经过预热时长后才会达到阈值
系统初始化的阈值为10/3约等于3,即阈值刚开始为3;然后过了5秒后阈值才慢慢升高,恢复到10【意思是5秒内阈值慢慢到达10】
测试:刚开始的时候,你只要满足了QPS大于3是可以触发快速失败那个页面的。5秒后阈值就到10了,我这手速是快,但是浏览器跟不上啊
应用场景:
秒杀系统 在开启的瞬间,会有很多流量上来,很有可能把系统打死,预热方式就是为了保护系统,可慢慢的把流量放进来,慢慢的把阈值增长到设置的阈值。
排队等待
匀速排队,让请求以均匀的速度通过,阈值类型必须设置成QPS,否则无效。对应漏桶算法
/testB每秒1次请求,超过的话就排队等待,等待的超时时间为20000毫秒
测试:点多了会打圈。表示等待。不再报“快速失败那个异常页面了”
Sentinel降级、熔断策略
慢调用比例、异常比例 、异常数
1、慢调用比例
在testA方法中线程睡眠0.3秒
@GetMapping("/testA") public String testA() { try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } return "------testA"; }
在sentinel控制台新增熔断规则如下:
当然,我没测出来。种种原因吧,连老师上课也是又不少测不出来
2、异常比例
在testA方法中手写一个异常
@GetMapping("/testA") public String testA() { int num=10/0; return "------testA"; }
在sentinel控制台修改熔断规则如下
1.发送请求,这是没有熔断之前的访问效果
2.这是触发熔断条件,熔断之后的显示
3、异常数
在sentinel控制台修改熔断规则如下
触发熔断后
热点key限流
1、@SentinelResource
之前限流出问题后,都是用sentinel系统默认的提示:Blocked by Sentinel(flow limiting)
现在使用@SentinelResource在方法出现问题后,可以找到对应的兜底方法
官网:热点参数限流 · alibaba/Sentinel Wiki · GitHub
@SentinelResource
其实在“尚医通项目-预约挂号”中,就应用到了热点key限流
热门医院 的号可能很紧张,尤其是放号的那一刻,可能有很多用户抢号,那么如何保证服务正常运行呢,因此我们需要对热门医院做流量控制,阿里 Sentinel流量控制 工具就能很好的解决我们的问题,它能根据热点值,动态控制流量。
2、热点key使用
1.新增控制器方法
简单来说,@SentinelResource注解中的俩个属性作用
value=资源名(注意资源名不要重复)
blockHandler:不管是热点限流还是非热点限流,只要该接口限流,就会是调用该属性所声明的方法
兜底方法deal_testHotKey() 参数要和接口方法的参数一致(包括),还要有一个必要参数BlockException e
@GetMapping("/testHotKey") //value 资源名,配置热点key。违法配置规则则,走blockHandler降级方法 @SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey") public String testHotKey(String p1, String p2) { return "------testHotKey"; } //兜底方法 // BlockException exception 必须得有 public String deal_testHotKey (String p1, String p2, BlockException exception){ return "------deal_testHotKey,o(╥﹏╥)o"; }
2.配置热点规则
资源名怎么设置?
如果你的接口,路径只有一段,可以直接使用路径作为资源名
如果路径有多段,不建议使用路径作为资源名
3.测试
3.1 先不使用热点key “p1”,点击测试
3.2一旦有了热点key "p1"的参与。且给我们返回的界面是我们自己定义的,再也不是那个丑不拉几的玩意
用着用着,让我测出来一个bug,我服了
这种方式传递参数,p1,p2是必传的,那个pathVarible中的required一点用没真是
1、不传参数测试 /test/testHotKey
2、传参数,但不传p1,只传p2 /test/testHotKey/?p2=1
3、传参数,带了p1,p2有没有根本不影响 /test/testHotKey/?p1=1
3、热点key- 参数例外项
热点参数的注意点,参数必须是基本类型或者String
修改热点key的配置
老师说:热点限流阈值一般要小于非热点限流阈值,目前还是理解不了、、、
当参数不包含p1,多少个请求也不会走降级处理方法。
测试当参数中包含p1的时候:
- 且当p1等于10000的时候,阈值变为3
/test/testHotKey/?p1=10000
- 且当p1不等于10000的时候,阈值就是平常的5
/test/testHotKey/?p1=1 下面口误了,是只有第6个走了降级处理
1、其它的规则也可以使用资源名控制规则(也可以使用路径控制)此时如果违反规则使用BLockHandler进行降级处理
2.其它的规则也可以使用路径控制规则:如果违反了规则使用默认的降级处理方案
value = "" 用于设置资源名称,只有根据资源名称设置的规则,才能执行blockHandler所引用降级方法
方法内部错误
方法内容异常不能使用那BLockHandler进行降级,但是有专门的方法错误降级方法,会加一个fallback属性
3.BLockHandler和fallback俩个可以同时存在
则违反规则走违反规则处理,没违反规则走异常处理
测试:
3.1.修改代码,使testHotKey资源对应的方法有异常
@GetMapping("/testHotKey") //value 资源名,配置热点key。违法配置规则则,走blockHandler降级方法 @SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey",fallback = "handleException2") public String testHotKey(@RequestParam(value = "p1",required = false) String p1, @RequestParam(value = "p2",required = false) String p2) { int age = 10/0; return "------testHotKey"; } //兜底方法 // BlockException exception 必须得有 public String deal_testHotKey (String p1, String p2, BlockException exception){ return "------deal_testHotKey,o(╥﹏╥)o"; } public String handleException2(@RequestParam(value = "p1",required = false) String p1, @RequestParam(value = "p2",required = false) String p2,Throwable throwable) { //方法参数列表和原函数一致或者可以额外多一个Throwable用于接收对应的异常 return "-----handleException2异常处理--噜啦啦"; }
3.2
3.3
系统规则
规则持久化
一旦我们重启应用,Sentinel规则将消失,生产环境需要将配置规则进行持久化
无论是通过硬编码方式来更新规则,还是通过接入 Sentinel Dashboard 后,在页面上操作更新规则,都无法避免一个问题,那就是服务重新后,规则就丢失了,因为默认情况下规则是保存在内存中的。sentinel重启,配置规则也会消失
我们在 Dashboard 上为客户端配置好了规则,并推送给了客户端。这时由于一些因素客户端出现异常,服务不可用了,当客户端恢复正常再次连接上 Dashboard 后,这时所有的规则都丢失了,我们还需要重新配置一遍规则,这肯定不是我们想要的。
1.使用nacos入库(实际中不会用)
将限流配置规则持久化进Nacos保存,只要刷新8401某个rest地址,sentinel控制台的流控规则就能看到,只要Nacos里面的配置不删除,针对8401上Sentinel上的流控规则持续有效
引入依赖
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> <version>1.7.0</version> </dependency>
修改配置文件
这里datasource后的d1是数据源名称,可以随便写,推荐使用服务名
rule-type 配置的是规则类型
#authority(授权规则)、degrade(降级规则)、flow(流控规则)、
#param(热点规则)、system(系统规则)五种规则持久化到Nacos中
在尚医通项目中,dataId是这么配置的,下面会用到,一致就好。我觉着还是用服务名好
spring.cloud.sentinel.datasource.consumer.nacos.dataId =${spring.application.name}-sentinel-rules spring.cloud.sentinel.datasource.consumer.nacos.groupId =SENTINEL_GROUP
2、在nacos控制台创建流控规则
Nacos业务规则配置
json文件 中对应在sentinel的可视化配置
[ { "resource": "/testA", "limitApp": "default", "grade": 1, "count": 1, "strategy": 0, "controlBehavior": 0, "clusterMode": false } ]
其中补充俩点:
流控模式,0-直接,1-关联, 2-链路
流控效果。0-快速失败,1-warm up 2-排队等待
3.重新启动服务,测试nacos中配置的流控规则是否生效
启动服务,在浏览器得先访问一下 http://localhost:8207/test/testHotKey
在流控规则中就有了我们刚刚配置在nacos中的配置