一、上集回顾
上级文章地址:【SpringCloud】Sentinel 之流量控制_面向架构编程的博客-CSDN博客
上一篇文章我们讲解了Sentinel 流量控制、流控效果、热点参数限流的用法,统称为限流,它是一种预防措施,可以尽量避免因高并发而引起的服务故障。
但是,服务还会因为其它原因而故障,生产环境上的情况多种多样,有着一定的不可预见性,所以,我们要将这些故障控制在一定范围,要避免雪崩的发生,就要靠线程隔离(舱壁模式)和熔断降级手段了。
回顾-线程隔离与熔断降级
文章地址:【SpringCloud】Sentinel的基础概念及使用_面向架构编程的博客-CSDN博客
不管是线程隔离还是熔断降级,都是对客户端(调用方)的保护。需要在调用方发起远程调用时做线程隔离、或者服务熔断。
微服务远程调用都是基于Feign(OpenFeign)来完成的,因此我们需要将OpenFeign与Sentinel整合,在OpenFeign里面实现线程隔离和服务熔断。
二、FeignClient整合Sentinel
SpringCloud中,微服务调用都是通过Feign来实现的,因此做客户端保护必须整合OpenFeign和Sentinel
1.修改配置,开启sentinel功能
修改order-service的application.yml文件,开启Feign的Sentinel功能
feign:
sentinel:
enabled: true # 开启feign对sentinel的支持
2.编写失败降级逻辑
业务失败后,不能直接报错,而应该返回用户一个友好提示或者默认结果,这个就是失败降级逻辑。
给FeignClient编写失败后的降级逻辑
①方式一:FallbackClass,无法对远程调用的异常做处理(一般不用)
②方式二: FallbackFactory,可以对远程调用的异常做处理(主流!!!)
注意:这里将的FeignClient其实就是@FeignClient注解,用于客户端服务发现。
失败降级处理流程
(1)在feing-api项目中定义类,实现FallbackFactory接口
@Slf4j
public class UserClientFallbackFactory implements FallbackFactory<UserClient> {
@Override
public UserClient create(Throwable throwable) {
return new UserClient() {
@Override
public User findById(Long id) {
log.error("查询用于异常",throwable);
// 返回一个空的用户对象
return new User();
}
};
}
}
(2)在DefaultFeignConfiguration类中将UserClientFallbackFactory注册为一个Bean
public class DefaultFeignConfiguration {
@Bean
public Logger.Level logLevel() {
return Logger.Level.BASIC;
}
/**
* sentinel-失败降级
* 将UserClientFallbackFactory注册为一个Bean
*/
@Bean
public UserClientFallbackFactory userClientFallbackFactory() {
return new UserClientFallbackFactory();
}
}
(3)在feing-api项目中的UserClient接口中使用UserClientFallbackFactory
@FeignClient(value = "userservice", fallbackFactory = UserClientFallbackFactory.class)
public interface UserClient {
@GetMapping("/user/{id}")
User findById(@PathVariable("id") Long id);
}
(4)运行
打开Sentinel控制台,访问网址:localhost:8080/order/101
可以看到新的簇点链路:
小结
Sentinel支持的雪崩解决方案
线程隔离(仓壁模式)
降级熔断
Feign整合Sentinel的步骤
在application.yml中配置:feign.sentienl.enable=true
给FeignClient编写FallbackFactory并注册为Bean
将FallbackFactory配置到FeignClient
三、线程隔离(舱壁模式)
线程隔离的实现方式(2种)
线程池隔离
信号量隔离(Sentinel默认采用)
两者图解如下:
线程池隔离:给每个服务调用业务分配一个线程池,利用线程池本身实现隔离效果
信号量隔离:不创建线程池,而是计数器模式,记录业务使用的线程数量,达到信号量上限时,禁止新的请求。
两者的优缺点
线程池隔离
优点: 支持主动超时、支持异步调用
缺点:线程额外开销大
场景:低扇出
信号量隔离
优点: 轻量级、无额外的开销
缺点:不支持主动超时、不支持异步调用
场景:高频调用、高扇出
sentinel的线程隔离(采用信号量模式)
配置说明
在 "流控"按钮里面,之前选择的是QPS,当我们选择的是"线程数" 时,其实就是在指定 "信号量"的阈值!
线程数:是该资源能使用用的tomcat线程数的最大值。也就是通过限制线程数量,实现线程隔离(舱壁模式)。
案例需求
给 order-service服务中的UserClient的查询用户接口设置流控规则,线程数不能超过 2。然后利用jemeter测试。
具体实现
1.配置隔离规则
选择feign接口后面的流控按钮:
填写表单:
2.Jmeter压测
启动Jmeter
一次发生10个请求,有较大概率并发线程数超过2,而超出的请求会走之前定义的失败降级逻辑。
发现虽然结果都是通过了,不过部分请求得到的响应是降级返回的null信息。
Sentinel控制台的情况:
四、熔断降级
1.什么是熔断降级?
熔断降级是解决雪崩问题的重要手段!
其思路是由断路器统计服务调用的异常比例、慢请求比例,如果超出阈值则会熔断该服务。即拦截访问该服务的一切请求;而当服务恢复时,断路器会放行访问该服务的请求。
断路器控制熔断和放行是通过状态机来完成的!
2.什么是状态机?
状态机是为断路器提供熔断和放行的依据。它有3种状态,断路器会根据不同的状态执行相应的策略!
状态机的3种状态
closed:关闭状态,断路器放行所有请求,并开始统计异常比例、慢请求比例。超过阈值则切换到open状态
open:打开状态,服务调用被熔断,访问被熔断服务的请求都会被拒绝,快速失败,直接走降级逻辑。Open状态5秒后会进入half-open状态
half-open:半开状态,放行一次请求,根据执行结果来判断接下来的操作。
请求成功:则切换到closed状态(放行)
请求失败:则切换到open状态(熔断)
图解状态机工作原理
3.断路器熔断策略(三种)
断路器从close进入open,需要判断服务有没有触发熔断的条件,而该条件的判断是依据熔断策略(3种)——慢调用、异常比例、异常数
慢调用
业务的响应时长(RT)大于指定时长的请求认定为慢调用请求。在指定时间内,如果请求数量超过设定的最小数量,慢调用比例大于设定的阈值,则触发熔断。
配置说明
RT超过500ms的调用是慢调用,统计最近10s内的请求,如果请求量超过10次,并且慢调用比例不低于0.5,则触发熔断,熔断时长为5秒。然后进入half-open状态,放行一次请求做测试。
案例需求
需求:给 UserClient的查询用户接口设置降级规则,慢调用的RT阈值为50ms,统计时间为1秒,最小请求数量为2,失败阈值比例为0.4,熔断时长为5
具体实现
(1)设置慢调用
由于我们这里都是测试数据,基本上不可能出现慢调用,所以我们这里要用sleep来模拟一下。
修改user-service中的/user/{id}这个接口的业务。通过休眠模拟一个延迟时间。
@GetMapping("/{id}")
public User queryById(@PathVariable("id") Long id,@RequestHeader(value = "Truth", required = false) String truth) {
// 为了测试熔断,模拟其发生慢调用!
if (id == 1) {
try {
Thread.sleep(60); // 60ms
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
return userService.queryById(id);
}
重启user-service模块
orderId=101的订单,关联的是id为1的用户,调用时长肯定会>60ms(这里是112ms)
orderId=102的订单,关联的是id为2的用户,调用时长为非常短<50ms
(2)设置熔断规则
配置规则
超过50ms的请求都会被认为是慢请求
(3)测试
在浏览器访问:http://localhost:8088/order/101,快速刷新n次,可以发现
触发了熔断,请求时长缩短至十几ms,快速失败了,并且走降级逻辑,返回的null
再访问(5秒内):http://localhost:8088/order/102,竟然也被熔断了!!!
异常比例、异常数
含义
统计指定时间内的调用,如果调用次数超过指定请求数,并且出现异常的比例达到设定的比例阈值(或超过指定异常数),则触发熔断。
配置说明
解读:统计最近1000ms内的请求,如果请求量超过10次,并且异常比例不低于0.4,则触发熔断。
解读:统计最近1000ms内的请求,如果请求量超过10次,并且异常次数不低于2次,则触发熔断。
异常比例、异常数的使用方式与上述讲的 慢调用类似!这里就不用案例来说明了!