赞
踩
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。 ==Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护==等多个维度保护服务的稳定性。
用来代替Hystrix
Sentinel 具有以下特征:
Sentinel 的主要特性:
Hystrix:
Sentinel:
约定 > 配置 > 编码
都可以写在代码里面,但是我们本次还是大规模的学习使用配置和注解的方式,尽量少写代码
官方文档:Spring Cloud Alibaba Reference Documentation (spring-cloud-alibaba-group.github.io)
服务使用中的各种问题:
Sentinel 分为两个部分:
地址:
前提:java8环境OK + 8080端口不能被占用
运行命令:
java -jar sentinel-dashboard-1.7.1.jar
<dependencies> <!-- 后续做Sentinel的持久化会用到的依赖--> <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> <!-- springcloud alibaba nacos 依赖,Nacos Server 服务注册中心 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!--openfeign--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <!-- springboot整合Web组件 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!-- 日常通用jar包 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity --> <groupId>springcloud</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency> </dependencies>
启动成功之后,Sentinel控制台空空如也
原因:Sentinel采用懒加载,执行一次即可
测试:快速点击访问:http://localhost:8401/testA
解释:关联的资源达到阈值时,就限流自己
配置及说明:当关联资源/testB的qps阀值超过1时,就限流/testA的Rest访问地址,
使用postman新建多线程集合组:
运行后发现testA挂了,点击访问:http://localhost:8401/testA
只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)【API级别的针对来源】
直接失败,抛出异常:Blocked by Sentinel (flow limiting)
Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。详细文档可以参考 流量控制 - Warm Up 文档,具体的例子可以参见 WarmUpFlowDemo
通常冷启动的过程系统允许通过的 QPS 曲线如下图所示:
默认 coldFactor 为 3,即请求QPS从(阈值 / 3) 开始,经多少预热时长才逐渐升至设定的 QPS 阈值
系统配置系统初始化的阀值为10 / 3 约等于3,即阀值刚开始为3;然后==过了5秒后阀值才慢慢升高恢复到10==。效果为:开始访问 localhost:/testA 时每秒请求别超过10/3个才能正常访问,5秒后可以接受的请求可以达到每秒10次。
秒杀系统在开启的瞬间,会有很多流量上来,很有可能把系统打死,预热方式就是把为了保护系统,可慢慢的把流量放进来,慢慢的把阀值增长到设置的阀值
匀速排队,让请求以均匀的速度通过,阀值类型必须设成QPS,否则无效
设置含义:/testA每秒1次请求,超过的话就排队等待,等待的超时时间为20000毫秒
说明:匀速排队,阈值必须设置为QPS
匀速排队(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。详细文档可以参考流量控制 - 匀速器模式 ,具体的例子可以参见 PaceFlowDemo。
除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。一个服务常常会调用别的模块,可能是另外的一个远程服务、数据库,或者第三方 API 等。例如,支付的时候,可能需要远程调用银联提供的 API;查询某个商品的价格,可能需要进行数据库查询。然而,这个被依赖服务的稳定性是不能保证的。如果依赖的服务出现了不稳定的情况,请求的响应时间变长,那么调用服务的方法的响应时间也会变长,线程会产生堆积,最终可能耗尽业务自身的线程池,服务本身也变得不可用。
现代微服务架构都是分布式的,由非常多的服务组成。不同服务之间相互调用,组成复杂的调用链路。以上的问题在链路调用中会产生放大的效果。复杂链路上的某一环不稳定,就可能会层层级联,最终导致整个链路都不可用。因此我们需要对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩。熔断降级作为保护自身的手段,通常在客户端(调用端)进行配置。
RT(平均响应时间,秒级)
平均响应时间超出阈值且在时间窗口内通过的请求>=5,两个条件同时满足后触发降级
窗口期过后关闭断路器
RT最大4900(更大的需要通过-Dcsp.sentinel.statistic.max.rt=XXXX才能生效)
异常比列(秒级)
异常数**(分钟级)**
平均响应时间(DEGRADE_GRADE_RT):当1s内持续进入5个请求,对应时刻的平均响应时间(秒级)均超过阈值( count,以ms为单位),那么在接下的时间窗口(DegradeRule中的timeWindow,以s为单位)之内,对这个方法的调用都会自动地熔断(抛出DegradeException )。注意Sentinel 默认统计的RT上限是4900 ms,超出此阈值的都会算作4900ms,若需要变更此上限可以通过启动配置项-Dcsp.sentinel.statistic.max.rt=xxx来配置。
注意:Sentinel 1.7.0才有平均响应时间(DEGRADE_GRADE_RT
),Sentinel 1.8.0的没有这项,取而代之的是慢调用比例 (SLOW_REQUEST_RATIO
)。
慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。熔断降级 · alibaba/Sentinel Wiki · GitHub
如图为Sentinel1.7.0的降级规则为RT策略流程图
在controller中加入textD
配置:当1s内持续进入5个请求(默认5个请求),对应时刻的平均响应时间(秒级)均超过0.2s( count,以ms为单位),那么在接下的时间窗口1s之内,对这个方法的调用都会自动地熔断
测试
异常比例(DEGRADE_GRADE_EXCEPTION_RATIO):当资源的每秒请求量 >= 5,并且==每秒异常总数占通过量的比值超过阈值( DegradeRule中的 count)==之后,资源进入降级状态,即在接下的时间窗口( DegradeRule 中的 timeWindow,以s为单位)之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是[0.0, 1.0],代表0% -100%。
异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。熔断降级 · alibaba/Sentinel Wiki · GitHub
接下来讲解Sentinel 1.7.0
如图为Sentinel1.7.0的降级规则为异常比例策略流程图
在controller中加入textE
测试
单独访问一次:localhost:8401/testE
Jmeter压测:
结论
按照上述配置,单独访问一次,必然来一次报错一次(int age = 10/0),调一次错一次;开启jmeter后,直接高并发发送请求,多次调用达到我们的配置条件了。
断路器开启(保险丝跳闸),微服务不可用了,不再报错error而是服务降级了
异常数( DEGRADE_GRADF_EXCEPTION_COUNT ):当资源近1分钟的异常数目超过阈值之后会进行熔断。注意由于统计时间窗口是分钟级别的,若timeWindow小于60s,则结束熔断状态后可能再进入熔断状态。
说明:假设时间窗口期为10秒,设置的异常数不能超过5,统计阶段第1秒的时候有5个异常,服务熔断后进入时间窗口期,时间窗口期结束,但是一分钟还没结束,那么此时的异常数还是5个,又进入熔断状态。
注意,与Sentinel 1.8.0相比,有些不同(Sentinel 1.8.0才有的半开状态),Sentinel 1.8.0的如下:
异常数 (ERROR_COUNT):当单位统计时长(默认一分钟)内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。
如图为Sentinel1.7.0的降级规则为异常数策略流程图
由于异常数是按照分钟统计的,时间窗口一定要大于等于60秒。
何为热点:热点即经常访问的数据,很多时候我们==希望统计或者限制某个热点数据中访问频次最高的 Top N 数据,并对其访问进行限流==或者其它操作:
热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。
兜底方法,分为 系统默认 和 客户自定义 两种。
之前的案例,限流出问题后,都是用sentinel系统默认的提示: Blocked by Sentinel (flow limiting)
我们能不能自定?类似hystrix,某个方法出问题了,就找对应的兜底降级方法?
结论 - 从HystrixCommand到@SentinelResource
在controller中加入:
说明:@SentinelResource(value = “testHotKey”,blockHandler = “deal_testHotKey”)方法 testHotKey 里面第一个参数只要QPS超过每秒1次,马上降级处理,异常用了我们自己定义的兜底方法。
配置说明:在1秒的窗口时间内,访问次数超过1的话,就开启限流
测试:快速点击,携带参数p1
测试:快速点击,携带参数p2
上述案例演示了第一个参数p1,当QPS超过1秒1次点击后马上被限流
特例情况:我们期望p1参数当它是某个特殊值时,它的限流值和平时不一样
特例:假如当p1的值等于5时,它的阈值可以达到200
热点参数的注意点,参数必须是基本类型或者String
配置如下:
pom文件增加:
<!-- 引入自己定义的api通用包,可以使用payment对象-->
<dependency>
<groupId>springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
@RestController
public class RateLimitController {
@GetMapping("/byResource")
@SentinelResource(value = "byResource",blockHandler = "handleException")
public CommonResult byResource(){
return new CommonResult(200,"按资源名称限流测试OK",new Payment(2020L,"serial001"));
}
public CommonResult handleException(BlockException exception){
return new CommonResult(444,exception.getClass().getCanonicalName()+"\t 服务不可用");
}
}
快速点击测试:localhost:8401/byResource
此时关闭服务8401,查看Sentinel控制台,流控规则消失,即为临时
@GetMapping("/rateLimit/byUrl")
public CommonResult byUrl(){
return new CommonResult(200,"按url限流测试",new Payment(2020L,"serial002"));
}
快速点击:localhost:8401/rateLimit/byUrl
public class CustomerBlockHandler {
public static CommonResult handlerException1(BlockException exception){
return new CommonResult(4444,"按用户自定义,global handlerException.......1");
}
public static CommonResult handlerException2(BlockException exception){
return new CommonResult(4444,"按用户自定义,global handlerException.......2");
}
}
//根据用户自定义流控规则进行限流,且实现全局流控规则
@GetMapping("/rateLimit/customerBlockHandler")
@SentinelResource(value = "customerBlockHandler",
blockHandlerClass = CustomerBlockHandler.class,
blockHandler = "handlerException2")
public CommonResult customerBlockHandler(){
return new CommonResult(200,"按用户自定义",new Payment(2020L,"serial003"));
}
注意:两个配置不能同时生效
在设置了 URL地址流控的前提下,设置按资源名称流控无效
即:URL地址流控优先级大于资源名称流控
sentinel整合ribbon+spenFeign+fallback
启动nacos和sentinel,新建cloudalibaba-provider-payment9003/9004两个服务提供者
<dependencies> <!-- springcloud alibaba nacos 依赖 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!-- springboot整合Web组件 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!-- 日常通用jar包 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity --> <groupId>com.atguigu.springcloud</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency> </dependencies>
新建cloudalibaba-consumer-nacos-order84
<dependencies> <!-- 后续做Sentinel的持久化会用到的依赖 --> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> </dependency> <!-- sentinel --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> <!-- springcloud alibaba nacos 依赖 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <!-- springboot整合Web组件 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!-- 日常通用jar包 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity --> <groupId>com.atguigu.springcloud</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency> </dependencies>
测试
测试id为4
测试id为5
sentinel新增服务降级规则,是服务降级、是服务降级
若一分钟内异常数超过2,则开启断路器,在80秒的时间窗口内,使用自定义的兜底方法,80秒一过,恢复默认的异常报错页面
测试
测试:
第一、二次访问异常路径,显示的是配置fallback的兜底方法
第三次访问异常路径,显示的是配置blockHandler的方法
测试
<!-- sentinel整合openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
主启动激活feign
9003和9004服务提供者controller新增:
测试时发现如果只给一个微服务加延时,另一个不加,会一直调用没有延时的微服务,所以要么两个都加延时或者停掉一个
测试结果:服务降级
目前的sentinel 当重启以后,数据都会丢失,和 nacos 类似原理。需要持久化。它可以==被持久化到 nacos 的数据库中。==
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
resource:资源名称
limitApp:来源应用
grade:阈值类型,0表示线程数,1表示QPS,
count:单机阈值,
strategy:流控模式,0表示直接,1表示关联,2表示链路
controlBehavior:流控效果,0表示快速失败,1表示Warm Up,2表示排队等待;
cIusterM0de是否集群
总结: 就是在 sentinel 启动的时候,去 nacos 上读取相关规则配置信息,实际上它规则的持久化,就是第三步,粘贴到nacos上保存下来,就算以后在 sentinel 上面修改了,重启应用以后也是无效。
快速点击:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。