初始Sentinel来学习SpringCloud Alibaba的组件-熔断服务降级
Sentinel简介
Sentinel 是面向分布式服务架构的高可用流量防护组件
,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定性。
文章目录
一、前言
1. Sentinel的特点
Sentinel 具有以下特性:
- 丰富的应用场景: Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
- 完备的实时监控: Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
- 广泛的开源生态: Sentinel 提供开箱即用的与其它开源框架 / 库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
- 完善的 SPI 扩展点: Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。
2. 服务可用性问题
❓思考:当我们的服务挂掉的时候,我们首先考虑什么原因
- 激增流量打垮服务器
- 被其它服务搞垮
- 异常没有处理
总而言之:
就是缺乏高可用的防护/容错机制,尤其是针对流量的防护
2.1 服务雪崩
服务雪崩:就是指当在分布式 的微服务系统中,我们的有一个微服务A调用了微服务B和C,微服务B又调用了微服务D和E…;这个过程在软件工程你学上有一个专业的术语:扇出
:
扇出:一个模块直接调用的下级模块
;扇入:一个模块被直接调用的上级模块
在某一个时刻,在该模块的删除链路上的某一个模块请求的时间过长或者服务出现了错误,造成了该模块的某个实例不可用,那么此时,你就会发现微服务A会越来越占用计算机资源,从而导致系统越来越卡,延迟,等一系列的问题就接踵而至。这种由某一个子服务的失效而导致的整个服务体系的崩溃问题
但是,对于对于高流量的系统应用而言,某一个依赖可能会导致所有服务器上的所有资源都在几秒内饱和,比失败更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他资源紧张,这样会导致很多蝴蝶效应。但是我们不能统一的整体管理,只能对某个失败的实例进行隔离和单独管理,以便单个依赖关系的失败,不能取消整个应用程序或系统。
总结:
因为服务提供者的不可用而导致服务调用者的不可用,并逐渐放大的过程,这个过程就叫做服务雪崩效应。
2.2 常见的容错机制
2.2.1 超时机制
在不做出任何处理得情况下,服务提供者不可用会导致消费者请求线程强制停止,而造成系统资源耗尽,加入超时机制,一旦超时,就释放资源。由于资源释放速度快。一定程度上可以抑制资源的消耗的问题。
2.2.2 服务限流
2.2.3 隔离
原理:用户的请求将不在直接的访问服务,而是通过线程中的空闲线程来访问,如果线程池已满,则会通过服务降级来处理,用户的请求不会阻塞,至少有一个执行结果(例如返回友好的提示信息,而不是通过无休止的等待或者是系统崩溃)
隔离前:
隔离后:
二、Sentinel概念解释
1.流量控制
流控:流量控制,即根据流量数,并发线程数目,响应时间等,来对随即到来的流量进行调整成合适的形状,叫做流量塑性
流量控制有以下几个角度:
- 运行指标,例如QPS、并发线程数等。
- 资源的调用关系,例如资源的调用链路,资源和资源之间的关系,调用来源等。
- 控制效果,例如排队等待、直接拒绝、Warm Up(预热)等。
2.熔断降级
除流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。
由于调用关系的复杂性,如果调用链路中的某个资源不稳定,最终会导致请求发生堆积。熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。
Sentinel 熔断降级支持以下几种
熔断策略:
- 秒级 RT 模式:若持续进入 5 个请求,它们资源的平均响应时间都超过阈值(秒级平均 RT,以 ms 为单位),资源调用会被熔断。在接下的降级时间窗口(在降级规则中配置,以 s 为单位)之内,对这个方法的调用都会自动地返回(抛出 DegradeException)。
- 秒级异常比例模式:当资源的每秒异常数占通过量的比值超过阈值之后,资源进入降级状态,即在接下的降级时间窗口(在降级规则中配置,以 s 为单位))之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
- 分钟级异常数模式:当资源最近 1 分钟的异常数目超过阈值之后会进行熔断。
再生活中,我们最常见到的熔断机制就是我们的保险丝,当家里的电灯泡,如果出现温度过高,会把保险丝烧断,这样一来就保护了灯泡不会爆掉,从而避免的危险,
在一个即使我们炒股,股市的涨停与跌停,保证股民的风险在一定的范围内。以便留出足够的时间去修复
在我们的软件行业里,我们使用熔断机制来保证一个微服务被挂掉之后,会立刻将其杀掉,保证其他服务的正常运营和避免一些列的级联影响,使得影响降到最低。
服务降级发生的依赖场所: 我们服务降级通常是发生在弱依赖的关系链上
所谓的弱依赖就是指当我们的这个服务挂掉以后,不会对我们的整个服务造成影响
3. 系统保护
系统保护机制从整体维度对应用入口流量进行控制,结合应用的Load、总体平均RT、入口QPS和线程数等几个维度的监控指标,让系统的入口流量和系统的负载达到一个平衡,对多余的流量直接拒绝,让系统尽可能维持在最大吞吐量的同时保证系统整体的稳定性。
❓说明 系统保护规则是整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量,比如Web服务或Dubbo服务端接收的请求,都属于入口流量。
对于一个应用来说,每种相同的系统保护规则最多只能存在一条,即一个应用最多配置五条系统保护规则。
系统规则支持五种阈值类型:
- Load(仅对Linux、Unix-like机器生效):当系统load1超过阈值,且系统当前的并发线程数超过预计的系统容量时才会触发系统保护。预计的系统容量由系统的maxQps * minRt计算得出。
- CPU使用率:当系统CPU使用率超过阈值(0.0~1.0)即触发系统保护。
- RT:当单台机器上所有入口流量的平均RT达到阈值即触发系统保护,单位是毫秒。
- 线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
- 入口QPS:当单台机器上所有入口流量的QPS达到阈值即触发系统保护。
QPS:每秒查询率
常见的熔断器的对比
Sentnel | HyStrix | |
隔离策略 | 信号量隔离 | 线程池隔离/信号量隔离 |
熔断降级策略 | 给予响应时间的或者失败比例 | 基于失败比例 |
实施指标实现 | 滑动窗口 | 滑动窗口 |
规则配置 | 支持多种数据源 | 支持多种数据源 |
扩展性 | 多个扩展点 | 插件的形式 |
基于注解的支持 | 支持 | 支持 |
限流 | 基于QPS,支持基于调用关系的限流 | 有限的形式 |
流量整形 | 支持慢启动,匀速器模式 | 不支持 |
系统负载保护 | 支持 | 不支持 |
控制台 | 开箱即用,可配置规则,查看秒级监控,及其发现等 | 不完善 |
常见框架的适配 | Servlet,Spring Cloud, Dubbo,Grpc | Servlet,SPringleCloud Netfix |
三、NacosConfig快速开始
官网地址:https://sentinelguard.io/zh-cn/ 在官方文档中,定义的Sentinel进行资源保护的几个步骤:
参考:https://sentinelguard.io/zh-cn/docs/basic-api-resource-rule.html
- 定义资源
- 定义规则
【流控规则;降级规则】
- 检查规则是否生效
3.1 引入依赖
父工程的依赖
<!--同一版本-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.11.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring.cloud-version>Hoxton.SR8</spring.cloud-version>
<springcloudalibaba.version>2.2.4.RELEASE</springcloudalibaba.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- springCloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- springcloud alibaba -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${springcloudalibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- springBoot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- json -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
详细的版本信息,可以参考我的Nacos第一篇
子服务的pom依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.8.0</version>
</dependency>
</dependencies>
使用的是Sentinel的1.8.0版本
3.2 新建配置文件
server:
port: 8090
servlet:
context-path: "/"
规定服务的端口号和访问地址等信息
3.3 新建一个HelloWorldController的文件
@RestController
public class HelloWorldController {
@RequestMapping("/hello")
public String helloWorld() {
try (Entry entry = SphU.entry("Hello World")){ // 使用限流规则 限流资源为Hello World
return "Sentinel 马冬梅 你好!!"+System.currentTimeMillis();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
return "系统繁忙,行了大爷 您先凉快会吧!!!"; // 降级处理
}
}
/**
* 定义限流规则
* PostContruct 构造方法执行完后执行方法 定义和加载限流规则
*/
@PostConstruct
public void initFlowRules() {
List<FlowRule> rules = new ArrayList<>(); // 定义先流规则集合
FlowRule rule = new FlowRule(); // 定义限流规则
rule.setResource("Hello World"); // 定义限流资源
rule.setGrade(RuleConstant.FLOW_GRADE_QPS); // 定义限流规则类型 QPS查询率
rule.setCount(2); // 定义QPS阈值 每秒最多查询2个请求个数
rules.add(rule); // 添加规则集合
FlowRuleManager.loadRules(rules); // 加载规则集合
}
}
书写步骤严格遵循上面所讲的步骤,且配置细节参考官方文档
3.4 启动服务,访问
正常访问1s访问次数不超过2次
流控访问1s内访问2次及以上