系统:windows10
开发工具:IntelliJ IDEA、maven
JDK:1.8+
拿旅游景点举个示例,每个旅游景点通常都会有最大的接待量,不可能无限制的放游客进入,比如故宫每天只卖八万张票,超过八万的游客,无法买票进入,因为如果超过八万人,景点的工作人员可能就忙不过来,过于拥挤的景点也会影响游客的体验和心情,并且还会有安全隐患;只卖N张票,这就是一种限流的手段。
流量控制在网络传输中是一个常用的概念,它用于调整网络包的发送数据。在网络传输时,任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。我们需要根据系统的处理能力对流量进行控制。
在调用系统的时候,如果调用链路中的某个资源出现了不稳定,最终会导致请求发生堆积,如下图:
而熔断降级就可以解决这个问题,所谓的熔断降级就是当检测到调用链路中某个资源出现不稳定的表现,例如请求响应时间长或异常比例升高的时候,则对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联故障。
Hystrix
**主页地址:**https://github.com/Netflix/Hystrix/
Hystrix源自Netflix API团队于2011年开始的弹性工程工作。2012年,Hystrix不断发展和成熟,Netflix内的许多团队都采用了它。如今,每天在Netflix上通过Hystrix执行数以千亿计的线程隔离和数以千计的信号隔离调用。这大大提高了正常运行时间和弹性。
Resilience4j
主页地址:https://github.com/resilience4j/resilience4j
Resilience4j是受Netflix Hystrix启发的轻量级容错库,但专为Java 8和函数式编程而设计。轻巧,因为该库仅使用Vavr,而Vavr没有任何其他外部库依赖项。相比之下,Netflix Hystrix对Archaius具有编译依赖性,而Archaius具有更多外部库依赖性。
Sentinel
主页地址:https://github.com/alibaba/Sentinel
Sentinel 是阿里巴巴出品的面向分布式服务架构的轻量级流量控制组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护等多个维度来保障微服务的稳定性。
竞品对比
Sentinel | Hystrix | resilience4j | |
---|---|---|---|
隔离策略 | 信号量隔离(并发线程数隔离) | 线程池隔离/信号量隔离 | 信号量隔离 |
熔断降级策略 | 基于响应时间、异常比率、异常数 | 基于异常比率 | 基于异常比率、响应时间 |
实时统计实现 | 滑动窗口 | 滑动窗口 | Ring Bit Buffer |
动态规则配置 | 支持多种数据源 | 支持多种数据源 | 有限支持 |
扩展性 | 多个扩展点 | 插件的形式 | 接口的形式 |
基于注解的支持 | 支持 | 支持 | 支持 |
限流 | 基于 QPS,支持基于调用关系的限流 | 有限的支持 | Rate Limiter |
流量整形 | 支持预热模式、匀速器模式、预热排队模式 | 不支持 | 简单的 Rate Limiter 模式 |
系统自适应保护 | 支持 | 不支持 | 不支持 |
控制台 | 提供开箱即用的控制台,可配置规则、查看秒级监控、机器发现等 | 简单的监控查看 | 不提供控制台,可对接其它监控系统 |
Sentinel概述
Sentinel 是阿里巴巴出品的面向分布式服务架构的轻量级流量控制组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护等多个维度来保障微服务的稳定性。
主页地址:https://github.com/alibaba/Sentinel
Sentinel历史
Sentinel组成
Sentinel 的使用主要分为两个部分:
Sentinel 具有以下特征:
资源
资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。
规则
规则指的是围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。
为了方便理解Sentinel,Sentinel提供了公网Demo来帮助我们快速熟悉Sentinel,步骤分为两步,具体如下:
阿里云的AHAS控制台需要注册登陆到阿里云平台并进行开通才能使用,具体如下:
阿里云地址:https://www.aliyun.com
1.注册
注册之后需要进行实名认证
如果是个人推荐“个人实名认证”,如果是企业推荐“企业/政府实名认证”。这里选择个人实名认证。
个人实名认证有“个人支付宝授权认证”和“个人扫脸认证”,这里选择“个人支付宝授权认证”,认证速度会比较快。
2.登录
登录之后,可以进行绑定邮箱,也可以选择暂不绑定。
3.开通应用高可用服务
在阿里云中找到“产品分类”中的"开发与运维"中的”应用高可用服务AHAS“选项
选择“免费开通”。
选择“立即开通”。开通成功之后,点击“管理控制台”,进入管理控制平台。
公网Demo的操作主要分为三步,具体如下:
1.公网Demo下载
在控制台顶部的地域列表中,选择地域为公网 。
在控制台左侧导航栏选择“流量防护”中的“应用防护”,会弹出应用列表。
点击右侧的“新应用接入”按钮,弹出接入新应用的界面,选择接入语言“Java“,选择接入方式”体验Demo“。
可以根据下面提供的下载Demo包的指令下载公网Demo,通过启动Demo的指令启动公网Demo,之后点击“我已完成上述步骤”按钮,完成公网Demo的接入操作。
公网Demo下载地址:https://ahasoss-cn-hangzhou.oss-cn-hangzhou.aliyuncs.com/sdk/latest/ahas-sentinel-sdk-demo.jar
如果没有网络,也可以到课程资料的“资料”目录下的“公网Demo”目录下找到提前准备好的ahas-sentinel-sdk-demo.jar来进行使用。
2.公网Demo接入阿里云AHAS控制台
执行以下指令启动公网Demo
java -Dahas.namespace=default -Dproject.name=SentinelDemo -Dahas.license=f7a69fd45e9d4135884ea1a6554faaa6 -jar ahas-sentinel-sdk-demo.jar
通过阿里云AHAS管理控制平台可以看到如下效果:
3.定义流控规则
在应用列表页面单击流控降级 SentinelDemo 的应用卡片,进入应用概览页面。
在控制台左侧导航栏中单击“监控详情”。在该应用的监控详情页面,单击 function_0 资源卡片右上角的“+”
在新增规则对话框中,设置单机QPS阈值为 10,然后单击新建。
这样流控规则就设置好了,这是在查看function_0的标签,会有以下效果:
返回应用列表页面,查看SentinelDemo应用的情况,会发现多了一个流量控制规则,并且规则生效了
Sentinel本地应用流控降级实现分为三步:
整体流程分析
具体流程
1.创建springboot项目,名称为sentinel_quick_start
2.在项目的pom.xml文件中引入sentinel-core的依赖坐标
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.1.4.RELEASEversion>
<relativePath/>
parent>
<groupId>com.itheima.sentinelgroupId>
<artifactId>sentinel_quick_startartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>sentinel_quick_startname>
<description>Demo project for Spring Bootdescription>
<properties>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cspgroupId>
<artifactId>sentinel-coreartifactId>
<version>1.7.2version>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
单元测试我们不需要,所以将单元测试的依赖坐标和单元测试类删除。
3.创建TestController,定义使用限流规则
这里我们定义OPS类型的限流规则,每秒可接受的请求最多为2个,超过则返回给页面“系统繁忙,请稍候”,不超过则返回给页面“Hello Sentinel!”。
@RestController
public class TestController {
@GetMapping("hello")
public String hello(){
//1.进行限流控制
try (Entry entry = SphU.entry("Hello")){//限流入口
return "Hello Sentinel!";//被保护的资源
} catch (BlockException e) {
e.printStackTrace();
return "系统繁忙,请稍候";//被限流或者降级的处理
}
}
/**
* 定义限流规则
* @PostConstruct :在构造函数执行完毕后执行
*/
@PostConstruct
public void initFlowRules(){
//1.创建存放限流规则的集合
List<FlowRule> rules = new ArrayList<FlowRule>();
//2.创建限流规则
FlowRule rule = new FlowRule();
//定义资源
rule.setResource("Hello");
//定义限流规则类型,RuleConstant.FLOW_GRADE_QPS:OPS类型
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
//定义OPS每秒最多只能通过的请求个数
rule.setCount(2);
//将限流规则添加到集合中
rules.add(rule);
//3.加载限流规则
FlowRuleManager.loadRules(rules);
}
}
4.运行测试
通过浏览器访问http://localhost:8080/hello,慢速刷新,则持续显示”Hello Sentinel”;快速刷新则会交替出现”Hello Sentinel”和“系统繁忙,请稍候”。这说明对“Hello"资源限流成功。我们还可以通过查看日志获取限流详情,日志文件的位置可以在控制台找到(图中红框处)。
在该目录下找到com-itheima-sentinel-sentinel_quick_start-SentinelQuickStartApplication-metrics.log.yyyy-MM-dd文件,查看该文件内容如下所示:
Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理、实时监控(单机和集群),规则管理和推送的功能。
本地控制台搭建步骤
1.下载Sentinel控制台jar包
下载地址:https://github.com/alibaba/Sentinel/releases/download/1.7.2/sentinel-dashboard-1.7.2.jar
2.启动Sentinel控制台
启动 Sentinel 控制台需要 JDK 版本为 1.8 及以上版本。
使用如下命令启动控制台:
java -Dserver.port=9000 -jar sentinel-dashboard-1.7.2.jar
3.访问Sentinel控制台
通过浏览器打开http://localhost:9000/即可访问Sentinel控制台,默认用户名和密码都是sentinel
但是此时本地应用还没有接入到Sentinel控制台进行管理,所以接下来就要将本地应用接入到Sentinel控制台。
本地应用是以客户端的身份来接入控制台,具体步骤如下:
1.在本地应用的pom.xml文件中引入依赖
<dependency>
<groupId>com.alibaba.cspgroupId>
<artifactId>sentinel-transport-simple-httpartifactId>
<version>1.7.2version>
dependency>
2.在本地应用的JVM启动参数
-Dcsp.sentinel.dashboard.server=localhost:9000 :设置Sentinel控制台的主机地址和端口
-Dproject.name=SentinelQuickStart :设置本地应用在Sentinel控制台中的名称
3.运行测试
重启本地应用并重新通过浏览器访问http://localhost:8080/hello,快慢速刷新几次,查看控制台中的实时监控情况。
需要注意的是应用配置好了与控制台的连接参数之后,并不会主动连接上控制台,需要触发一次应用的规则才会开始进行初始化,并向控制台发送心跳和应用规则等信息。
此外还需要注意的是,Sentinel提供了两种设置流控规则的方式
Sentinel除了基本的定义资源的方式之外,还有其他的定义资源的方式,具体如下:
Sentinel中的SphU 包含了 try-catch 风格的 API。用这种方式,当资源发生了限流之后会抛出 BlockException。这个时候可以捕捉异常,进行限流之后的逻辑处理,而我们在入门案例中就使用的此种方式进行定义资源,关键代码如下:
try (Entry entry = SphU.entry("Hello")){//使用限流规则监控保护资源
return "Hello Sentinel!";//被保护的资源
} catch (BlockException e) {
e.printStackTrace();
return "系统繁忙,请稍候";//被限流或者降级的处理
}
Sentinel中的SphO 提供 if-else 风格的 API。用这种方式,当资源发生了限流之后会返回 false
,这个时候可以根据返回值,进行限流之后的逻辑处理。
1.在sentinel_quick_start项目中创建TestBooleanController,在TestBooleanController中使用返回布尔值的方式定义资源
@RestController
public class TestBooleanController {
@GetMapping("boolean")
public boolean hello() {
//1..进行限流控制
if (SphO.entry("Sentinel_Boolean")) {//限流入口
try {
//被保护的资源
System.out.println("访问成功");
return true;
} finally {
//SphO.entry(xxx)需要与 SphO.exit()方法成对出现,否则会导致调用链记录异常,抛出ErrorEntryFreeException异常
SphO.exit();//限流出口,
}
} else {
//被限流或者降级的处理
System.out.println("系统繁忙,请稍候");
return false;
}
}
}
注意:
SphO.entry(xxx)需要与 SphO.exit()方法成对出现,否则会导致调用链记录异常,抛出ErrorEntryFreeException异常。
2.运行测试
在Sentinel控制的中增加关于“Sentinel_Boolean”资源的流控规则
通过浏览器访问http://localhost:8080/boolean,慢速刷新,则持续显示”true”;而Idea打印台显示“访问成功”,快速刷新则会交替出现“true”和“false”,打印台则会交替出现“访问成功”和“系统繁忙,请稍候”,这说明使用返回布尔值方式对“Sentinel_Boolean"资源限流成功。
Sentinel 支持异步调用链路的统计。在异步调用中,需要通过 SphU.asyncEntry(xxx) 方法定义资源,并通常需要在异步的回调函数中调用 exit 方法。
1.在本地应用的引导类中添加@EnableAsync,表示springboot项目开始异步调用支持
@SpringBootApplication
@EnableAsync
public class SentinelQuickStartApplication {
public static void main(String[] args) {
SpringApplication.run(SentinelQuickStartApplication.class, args);
}
}
2.创建AsyncService编写异步调用的方法
@Service
public class AsyncService {
//@Async表示方法为异步调用方法
@Async
public void hello(){
System.out.println("异步开始-----");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("完成异步----");
}
}
3.创建TestAsyncController,实现异步调用限流控制
@RestController
public class TestAsyncController {
@Autowired
private AsyncService asyncService;
@GetMapping("async")
public void hello() {
//1.进行限流控制
AsyncEntry asyncEntry = null;
try {
asyncEntry = SphU.asyncEntry("Sentinel_Async");//限流入口
asyncService.hello();//异步方法调用
} catch (BlockException e) {//被限流或者降级的处理
System.out.println("系统繁忙,请稍候");
}finally {
if (asyncEntry != null){
asyncEntry.exit();//限流出口,
}
}
}
}
4.运行测试
在Sentinel控制的中增加关于“Sentinel_Async”资源的流控规则
通过浏览器输入http://localhost:8080/async,慢速刷新,查看Idea的打印台,会发现打印台会打印出“异步开始-”;快速刷新可以查看Idea的打印台,则会发现打印台会交替打印出“异步开始”和“系统繁忙,请稍候”,这也说明对“Sentinel_Boolean"资源限流成功。
Sentinel 支持通过 @SentinelResource 注解定义资源并配置 blockHandler函数来进行限流之后的处理。
1.在本地应用的pom.xml文件中引入依赖
因为Sentinel中使用AspectJ 的扩展用于自动定义资源、处理 BlockException 等,所以需要在项目中引入sentinel-annotation-aspectj依赖。
<dependency>
<groupId>com.alibaba.cspgroupId>
<artifactId>sentinel-annotation-aspectjartifactId>
<version>1.7.2version>
dependency>
2.创建AspectJ 的配置类
@Configuration
public class SentinelAspectConfiguration {
@Bean
public SentinelResourceAspect sentinelResourceAspect() {
return new SentinelResourceAspect();
}
}
3.创建TestAnnController,实现限流控制
@RestController
public class TestAnnController {
//定义限流资源和限流讲解回调函数
@SentinelResource(value = "Sentinel_Ann", blockHandler = "exceptionHandler")
@GetMapping("ann")
public String hello() {
return "Hello Sentinel!";
}
// blockHandler函数,原方法调用被限流/降级/系统保护的时候调用
public String exceptionHandler(BlockException ex) {
ex.printStackTrace();
return "系统繁忙,请稍候";
}
}
4.运行测试
在Sentinel控制的中增加关于“Sentinel_Ann”资源的流控规则
通过浏览器输入http://localhost:8080/ann,慢速刷新,则持续显示”Hello Sentinel”;快速刷新则会交替出现”Hello Sentinel”和“系统繁忙,请稍候”。这说明对“Sentinel_Ann"资源限流成功。
为了减少开发的复杂程度,我们对大部分的主流框架,例如 Web Servlet、Dubbo、Spring Cloud、gRPC、Spring WebFlux、Reactor 等都做了适配。您只需要引入对应的依赖即可方便地整合 Sentinel。
为了减少开发的复杂程度,我们对大部分的主流框架,例如 Web Servlet、Dubbo、Spring Cloud、gRPC、Spring WebFlux、Reactor 等都做了适配。您只需要引入对应的依赖即可方便地整合 Sentinel。
如果要实现SpringCloud和Sentinel的整合,可以通过引入 Spring Cloud Alibaba Sentinel 来更方便地整合 Sentinel。
Spring Cloud Alibaba是阿里巴巴提供的,致力于提供微服务开发的一站式解决方案。Spring Cloud Alibaba 默认为 Sentinel 整合了 Servlet、RestTemplate、FeignClient 和 Spring WebFlux。Sentinel 在 Spring Cloud 生态中,不仅补全了 Hystrix 在 Servlet 和 RestTemplate 这一块的空白,而且还完全兼容了 Hystrix 在 FeignClient 中限流降级的用法,并且支持运行时灵活地配置和调整限流降级规则。
案例
需求
使用SpringCloud+Sentinel实现访问http://localhost:8080/ann路径的流量控制。
具体步骤
1.创建springboot项目,在项目中引入spring-cloud-starter-alibaba-sentinel依赖
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
<version>2.1.0.RELEASEversion>
dependency>
2.在项目中创建TestController
@RestController
public class TestController {
//定义限流资源和限流讲解回调函数
@SentinelResource(value = "Sentinel_SpringCloud", blockHandler = "exceptionHandler")
@GetMapping("ann")
public String hello() {
return "Hello Sentinel!";
}
// blockHandler函数,原方法调用被限流/降级/系统保护的时候调用
public String exceptionHandler(BlockException ex) {
ex.printStackTrace();
return "系统繁忙,请稍候";
}
}
3.在application.properties中配置本地项目接入本地控制台
# 设置应用的名称
spring.application.name=SpringCloudSentinel
# 设置Sentinel连接控制台的主机地址和端口
spring.cloud.sentinel.transport.dashboard=localhost:9000
4.运行测试
在Sentinel控制的中增加关于“Sentinel_SpringCloud”资源的流控规则
启动本地应用并重新通过浏览器访问http://localhost:8080/ann,快慢速刷新几次,查看控制台中的实时监控情况。
Sentinel 适配了 Feign组件。如果想使用,除了引入 spring-cloud-starter-alibaba-sentinel
的依赖外还需要 2 个步骤:
feign.sentinel.enabled=true
spring-cloud-starter-openfeign
依赖使 Sentinel starter 中的自动化配置类生效;案例
需求
实现sentinel_feign_client微服务通过Feign访问sentinel_feign_provider微服务的流量控制
创建sentinel_parent、eureka_server、sentinel_feign_provider、sentinel_feign_client工程,并在sentinel_feign_client中使用feign访问sentinel_feign_provider服务。
1.创建父工程sentinel_parent,在父工程的pom.xml文件中对SpringCloud依赖的进行管理
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>Greenwich.RELEASEversion>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
2.创建子工程eureka_server工程,作为注册中心
2.1.在pom.xml文件中引入依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
dependency>
dependencies>
2.2.引导类中添加Eureka的服务注解
//声明当前应用是Eureka注册中心服务
@EnableEurekaServer
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
2.3.配置文件配置eureka
#设置服务端口
server:
port: 9010
#设置eureka服务的名称
spring:
application:
name: eureka-server
#eureka配置
eureka:
client:
service-url:
# eureka 服务地址,如果是集群的话;需要指定其它集群eureka地址
defaultZone: http://127.0.0.1:9010/eureka
# 不注册自己
register-with-eureka: false
# 不拉取服务
fetch-registry: false
2.4.运行测试
启动项目,通过浏览器访问http://127.0.0.1:9010/,如果能看到如下界面就说明eureka注册中心已经配置成功
3.创建子工程sentinel_feign_provider,作为服务的提供方
3.1.在pom.xml文件中引入依赖
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
dependencies>
3.2.引导类中添加Eureka客户端注解
@EnableDiscoveryClient //开启Eureka客户端发现功能
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
3.3.在application.yml文件中进行配置
#tomcat端口
server:
port: 9011
#应用的名称
spring:
application:
name: sentinel_feign_provider
#eureka的配置
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:9010/eureka #要注册到的注册中心的地址
3.4.创建controller,方便sentinel_feign_client进行调用
@RestController
public class ProviderController {
@GetMapping("hello")
public String hello(){
return "Hello Sentinel!";
}
}
3.5.运行测试
启动项目,查看项目是否注册到eureka注册中心中
浏览器输入http://localhost:9011/hello,查看是否能访问成功。
4.创建子工程sentinel_feign_client
4.1.在pom.xml文件中引入依赖
项目中要使用Fegin来进行访问sentinel_fegin_provider微服务,所以需要额外引入spring-cloud-starter-openfeign依赖,整合sentinel还需要引入spring-cloud-starter-alibaba-sentinel依赖。
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
dependencies>
4.2.引导类中添加Eureka客户端注解
@EnableDiscoveryClient //开启Eureka客户端发现功能
@SpringBootApplication
@EnableFeignClients //开启feign功能
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
4.3.在application.yml文件中进行配置
在application.yml文件中要专门开启 Sentinel 对 Feign 的支持。
#tomcat端口
server:
port: 9012
#应用的名称
spring:
application:
name: sentinel-feign-client
cloud:
sentinel:
transport:
dashboard: localhost:9000
#eureka的配置
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:9010/eureka #要注册到的注册中心的地址
4.4.创建Feign代理接口
@FeignClient(value="sentinel-feign-provider")
public interface FeignAgent {
@GetMapping("/hello")
String hello();
}
4.5.创建controller,使用Feign访问sentinel_feign_provider微服务。
@RestController
public class TestController {
@Autowired
private FeignAgent feignAgent;
@GetMapping("hello")
public String hello(){
return feignAgent.hello();
}
}
4.6.运行测试
启动项目,查看项目是否注册到eureka注册中心中。
浏览器输入http://localhost:9012/hello,查看是否能访问成功。
整合sentinel
1.在sentinel_feign_client工程的pom.xml中引入Spring Cloud Alibaba Sentinel依赖
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
<version>2.1.0.RELEASEversion>
dependency>
2.在application.yml中开启Sentinel对Feign的支持
# sentinel控制台的主机地址和端口
spring:
cloud:
sentinel:
transport:
dashboard: localhost:9000
# 开启 Sentinel 对 Feign 的支持
feign:
sentinel:
enabled: true
3.创建FallbackService,作为流控降级回调类,并在FeignAgent进行流控降级回调配置
@Component
public class FallbackService implements FeignAgent {
@Override
public String hello() {
return "系统繁忙,请稍后";
}
}
@FeignClient(value="sentinel-feign-provider",fallback = FallbackService.class)
public interface FeignAgent {
@GetMapping("/hello")
String hello();
}
4.运行测试
启动项目,在Sentinel控制中增加关于资源的流控规则,Sentinel和Feign整合时,流控规则的编写形式为:http请求方式:协议://服务名/请求路径跟参数,例如:GET:http://sentinel-feign-provider/hello。
通过浏览器输入http://localhost:9012/hello,慢速刷新,则持续显示”Hello Sentinel”;快速刷新则会交替出现”Hello Sentinel”和“系统繁忙,请稍候”。这说明对资源限流成功。
从 1.6.0 版本开始,Sentinel 提供了 Spring Cloud Gateway 的适配模块,可以提供两种资源维度的限流:
网关微服务构建
1.创建子工程sentinel_gateway,在pom.xml文件中引入依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-gatewayartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
dependencies>
2.在引导类中配置eureka客户端开启注解
@SpringBootApplication
@EnableDiscoveryClient //开启Eureka客户端发现功能
public class GateWayApplication {
public static void main(String[] args) {
SpringApplication.run(GateWayApplication.class, args);
}
}
3.在application.yml配置文件中配置应用的端口、应用的名称、eureka配置
# 端口
server:
port: 9013
# 应用的名称
spring:
application:
name: sentinel-gateway
# eureka配置
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:9010/eureka
4.在application.yml配置文件中进行网关配置
spring:
# 网关配置
cloud:
gateway:
routes:
- id: sentinel-feign-gateway
# 路由转发路径
uri: lb://sentinel-feign-client:9012
# 断言
predicates:
- Path=/hello/**
5.运行测试
启动微服务
浏览器输入http://localhost:9013/hello,浏览器会显示出”Hello Sentinel!“的内容,表示网关微服务已经配置好。
整合sentinel
网关微服务配置好之后,就可以开始整合Spring Cloud GateWay和Sentinel了。
1.在sentinel_gateway的pom.xml中引入依赖
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
<version>2.1.0.RELEASEversion>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-alibaba-sentinel-gatewayartifactId>
<version>2.1.0.RELEASEversion>
dependency>
2.创建GatewayConfiguration配置类,配置流控降级回调操作
@Component
public class GatewayConfiguration {
@PostConstruct
public void doInit() {
//限流回调函数
GatewayCallbackManager.setBlockHandler(new BlockRequestHandler() {
//当请求被限流是调用的方法
@Override
public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
return ServerResponse.status(200).syncBody("系统繁忙,请稍候");
}
});
}
}
3…在application.yml中配置Sentinel控制台访问地址
spring:
cloud:
# sentinel控制台地址
sentinel:
transport:
dashboard: localhost:9000
4.运行测试
启动项目,在Sentinel控制中增加关于资源的流控规则,Sentinel在适配Spring Cloud Gateway时提供了两种配置资料的规则
route维度规则定义
在sentinel控制台中增加流控规则,其中API类型选择“Route ID”,API名称为网关配置的路由id,QPS阀值设置为2。
之后,在浏览器中输入http://localhost:9013/hello,慢速刷新,则持续显示”Hello Sentinel”;快速刷新则会交替出现”Hello Sentinel”和“系统繁忙,请稍候”。这说明对资源限流成功。
自定义 API 维度
在sentinel控制台的左侧菜单中选择“API管理”,在弹出的窗口中新增API分组,API名称自己定义,匹配模式选择”前缀“,匹配串设置为网关路由的断言路径。
之后,在sentinel控制台的左侧菜单中选择“流控规则”,其中API类型选择“API分组”,API名称为之前添加的API分组的名称,QPS阀值设置为2。
之后,在浏览器中输入http://localhost:9013/hello,慢速刷新,则持续显示”Hello Sentinel”;快速刷新则会交替出现”Hello Sentinel”和“系统繁忙,请稍候”。这说明对资源限流成功。
Sentinel 的所有规则都可以在内存态中动态地查询及修改,修改之后立即生效。同时 Sentinel 也提供相关 API,供您来定制自己的规则策略。
Sentinel 主要支持以下几种规则:
流量控制规则实现
流量控制(flow control),其原理是监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。
流量控制主要有两种方式
一条限流规则主要由下面几个因素组成,我们可以组合这些元素来实现不同的限流效果:
resource
:资源名,即限流规则的作用对象count
: 限流阈值grade
: 限流阈值类型(QPS 或并发线程数)limitApp
: 流控针对的调用来源,若为 default
则不区分调用来源strategy
: 调用关系限流策略controlBehavior
: 流量控制效果(直接拒绝、Warm Up、匀速排队)
RuleConstant.CONTROL_BEHAVIOR_DEFAULT
)方式是默认的流量控制方式,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出FlowException
。这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时。RuleConstant.CONTROL_BEHAVIOR_WARM_UP
)方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER
)方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。同一个资源可以同时有多个限流规则,检查规则时会依次检查。
熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出 DegradeException
)。
重要的属性
Field | 说明 | 默认值 |
---|---|---|
resource | 资源名,即限流规则的作用对象 | |
count | 阈值 | |
grade | 熔断策略,支持秒级 RT/秒级异常比例/分钟级异常数 | 秒级平均 RT |
timeWindow | 降级的时间,单位为 s | |
rtSlowRequestAmount | RT 模式下 1 秒内连续多少个请求的平均 RT 超出阈值方可触发熔断(1.7.0 引入) | 5 |
minRequestAmount | 异常熔断的触发最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断(1.7.0 引入) | 5 |
同一个资源可以同时有多个降级规则。
熔断策略详解:
这里演示如何使用平均响应时间(DEGRADE_GRADE_RT)配置规则
实现步骤
熔断降级规则设置有两种方式
平均响应时间
本地代码设置
1.导入资料中的sentinel_rule项目。
2.创建DegradeController,在其中编写修改以下代码
@RestController
public class DegradeController {
//定义限流资源和限流讲解回调函数
@SentinelResource(value = "Sentinel_Rule",fallback = "exceptionHandler")
@GetMapping("degrade")
public String hello() {
return "Hello Sentinel!";
}
// 降级方法
public String exceptionHandler() {
return "系统繁忙,请稍候";
}
}
3.在DegradeController中编写以下代码
@PostConstruct
private void initDegradeRule() {
//1.创建存放熔断降级规则的集合
List<DegradeRule> rules = new ArrayList<>();
//2.创建熔断降级规则
DegradeRule rule = new DegradeRule();
//定义资源
rule.setResource("Sentinel_Rule");
//阈值
rule.setCount(0.01);
//定义规则类型,RuleConstant.DEGRADE_GRADE_RT:熔断降级(秒级 RT)类型
/**
* 当资源的平均响应时间超过阈值(DegradeRule中的count,以ms为单位)之后,资源进入准降级状态。
* 接下来如果持续进入 5 个请求,它们的 RT 都持续超过这个阈值,
* 那么在接下的时间窗口(DegradeRule 中的 timeWindow,以 s 为单位)之内,
* 将会抛出 DegradeException。
*/
rule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
//降级的时间,单位为 s
rule.setTimeWindow(10);
//将熔断降级规则添加到集合中
rules.add(rule);
//3.加载熔断降级规则
DegradeRuleManager.loadRules(rules);
}
运行测试
通过浏览器输入http://localhost:8080/ann,慢速刷新,则持续显示”Hello Sentinel”;快速刷新多次之后则会出现“系统繁忙,请稍候”,并且之后再次刷新都显示“系统繁忙,请稍候”,等待10秒之后,则再次显示“Hello Sentinel”,这说明对资源限流成功。
在Sentinel控制台动态设置
将DegradeController中的代码设置熔断降级规则删除,重启项目,在Sentinel控制台动态设置熔断降级规则。
在Sentinel控制台的左侧菜单中选择“降级规则”,点击“新增降级规则”按钮,设置熔断降级规则,其中降级策略设选择“RT”。
之后,通过浏览器输入http://localhost:8080/ann,慢速刷新,则持续显示”Hello Sentinel”;快速刷新多次之后则会出现“系统繁忙,请稍候”,并且之后再次刷新都显示“系统繁忙,请稍候”,等待10秒之后,则再次显示“Hello Sentinel”,这说明对资源限流成功。
Sentinel 系统自适应限流从整体维度对应用入口流量进行控制,结合应用的 Load、CPU 使用率、总体平均 RT、入口 QPS 和并发线程数等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能保持最大吞吐量的同时保证系统整体的稳定性。
系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(EntryType.IN),比如 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量。
系统规则支持以下的模式
maxQps * minRt
估算得出。设定参考值一般是 CPU cores * 2.5
。重要的属性
Field | 说明 | 默认值 |
---|---|---|
highestSystemLoad | load1 触发值,用于触发自适应控制阶段 |
-1 (不生效) |
avgRt | 所有入口流量的平均响应时间 | -1 (不生效) |
maxThread | 入口流量的最大并发数 | -1 (不生效) |
qps | 所有入口资源的 QPS | -1 (不生效) |
highestCpuUsage | 当前系统的 CPU 使用率(0.0-1.0) | -1 (不生效) |
注意系统规则只针对入口资源(EntryType=IN)生效。
这里演示如何使用所有入口资源的QPS配置规则
实现步骤
系统自适应保护规则设置有两种方式
本地代码设置
创建SysController,在其中编写修改以下代码
@RestController
public class SysController {
//定义限流资源和限流讲解回调函数
@SentinelResource(entryType = EntryType.IN)
@GetMapping("sys")
public String hello() {
return "Hello Sentinel!";
}
/**
* 定义系统自适应规则
* @PostConstruct :在构造函数执行完毕后执行
*/
@PostConstruct
private void initSystemRule() {
//1.创建系统自适应规则的集合
List<SystemRule> rules = new ArrayList<>();
//2.创建系统自适应规则
SystemRule rule = new SystemRule();
//设置根据入口QPS规则
rule.setQps(2);
//将系统自适应规则添加到集合中
rules.add(rule);
//3.加载系统自适应规则
SystemRuleManager.loadRules(rules);
}
}
运行测试
通过浏览器输入http://localhost:8080/sys,慢速刷新,则持续显示”Hello Sentinel”;快速刷新则会交替出现”Hello Sentinel”和“Blocked by Sentinel (flow limiting)”。这说明系统自适应保护规则设置成功。
在Sentinel控制台动态设置
将SysController中的代码设置系统自适应保护规则删除,重启项目,在Sentinel控制台动态设置系统自适应保护规则。
在Sentinel控制台的左侧菜单中选择“系统规则”,点击“新增系统规则”按钮,设置系统自适应保护规则,其中阈值类型选择“入口QPS”。
之后,通过浏览器输入http://localhost:8080/sys,慢速刷新,则持续显示”Hello Sentinel”;快速刷新则会交替出现”Hello Sentinel”和“Blocked by Sentinel (flow limiting)”。这说明系统自适应保护规则设置成功。
很多时候,我们需要根据调用来源来判断该次请求是否允许放行,这时候可以使用 Sentinel 的来源访问控制(黑白名单控制)的功能。来源访问控制根据资源的请求来源(origin)判断资源访问是否通过,若配置白名单则只有请求来源位于白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。
重要的属性
来源访问控制规则(AuthorityRule)非常简单,主要有以下配置项:
resource
:资源名,即限流规则的作用对象。limitApp
:请求来源,对应的黑名单/白名单,多个用","分隔,如 appA,appB。strategy
:限制模式,AUTHORITY_WHITE为白名单模式,AUTHORITY_BLACK为黑名单模式,默认为白名单模式。这里演示实现Ip地址白名单和黑名单配置规则
实现步骤
授权控制规则设置有两种方式
本地代码设置
1.创建WhiteBlackController,在其中编写修改以下代码
@RestController
public class WhiteBlackController {
//定义限流资源和限流讲解回调函数
@SentinelResource(value = "Sentinel_Rule", blockHandler = "exceptionHandler")
@GetMapping("origin")
public String hello() {
return "Hello Sentinel!";
}
// blockHandler函数,原方法调用被限流/降级/系统保护的时候调用
public String exceptionHandler(BlockException ex) {
ex.printStackTrace();
return "系统繁忙,请稍候";
}
/**
* 白名单设置
*
* @PostConstruct :在构造函数执行完毕后执行
*/
@PostConstruct
private static void initWhiteRules() {
//1.创建存放授权规则的集合
List<AuthorityRule> rules = new ArrayList<AuthorityRule>();
//2.创建授权规则
AuthorityRule rule = new AuthorityRule();
//定义资源
rule.setResource("Sentinel_Rule");
//设置授权模式 RuleConstant.AUTHORITY_WHITE :白名单
rule.setStrategy(RuleConstant.AUTHORITY_WHITE);
//设置白名单
rule.setLimitApp("192.168.0.100");
//将授权规则添加到集合中
rules.add(rule);
//3.加载授权规则
AuthorityRuleManager.loadRules(rules);
}
/**
* 黑名单设置
*
* @PostConstruct :在构造函数执行完毕后执行
*/
@PostConstruct
private static void initBlackRules() {
//1.创建存放授权规则的集合
List<AuthorityRule> rules = new ArrayList<AuthorityRule>();
//2.创建授权规则
AuthorityRule rule = new AuthorityRule();
//定义资源
rule.setResource("Sentinel_Rule");
//设置授权模式 RuleConstant.AUTHORITY_BLACK :黑名单
rule.setStrategy(RuleConstant.AUTHORITY_BLACK);
//设置黑名单
rule.setLimitApp("127.0.0.1");
//将授权规则添加到集合中
rules.add(rule);
//3.加载授权规则
AuthorityRuleManager.loadRules(rules);
}
}
白名单和黑名单只要配置一个就可以满足需求。
2.创建SentinelConfig,设置请求来源解析
@Component
public class SentinelConfig {
@PostConstruct
public void init(){
//获取请求来源ip地址
WebCallbackManager.setRequestOriginParser(new RequestOriginParser() {
@Override
public String parseOrigin(HttpServletRequest httpServletRequest) {
return httpServletRequest.getRemoteAddr();
}
});
}
}
3.运行测试
通过浏览器输入http://192.168.0.100:8080/origin进行访问,则显示”Hello Sentinel”;当浏览器输入http://127.0.0.1:8080/origin,则显示”系统繁忙,请稍候”,这说明授权控制规则设置成功。
在Sentinel控制台动态设置
将WhiteBlackController中的代码设置授权控制规则删除,重启项目,在Sentinel控制台动态设置授权控制规则。
在Sentinel控制台的左侧菜单中选择“授权规则”,点击“新增授权规则”按钮,增加白名单或者黑名单。
之后,通过浏览器输入http://192.168.0.100:8080/origin进行访问,则显示”Hello Sentinel”;当浏览器输入http://127.0.0.1:8080/origin,则显示”系统繁忙,请稍候”,这说明授权控制规则设置成功。
前面不管是通过Java代码还是通过Sentinel控制台的方式去设置限流规则,都属于手动方式,不够灵活。这种方式一般仅用于测试和演示,生产环境上一般通过动态规则源的方式来动态管理限流规则。也就是说,很多时候限流规则会被存储在文件、数据库或者配置中心当中。Sentinel的DataSource
接口给我们提供了对接任意配置源的能力。
官方推荐通过控制台设置规则后将规则推送到统一的规则管理中心,客户端实现 ReadableDataSource
接口端监听规则中心实时获取变更,流程如下:
常见的实现方式有:
AutoRefreshDataSource
抽象类,然后实现 readSource()
方法,在该方法里从指定数据源读取字符串格式的配置数据。AbstractDataSource
抽象类,在其构造方法中添加监听器,并实现 readSource()
从指定数据源读取字符串格式的配置数据。这里演示如何使用zookeeper配置规则
Sentinel 针对 ZooKeeper 作了相应适配,底层可以采用 ZooKeeper 作为规则配置数据源。使用时只需添加sentinel-datasource-zookeeper
1.新建工程sentinel_zookeeper,在pom.xml文件引入依赖
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
<version>2.1.0.RELEASEversion>
dependency>
<dependency>
<groupId>com.alibaba.cspgroupId>
<artifactId>sentinel-datasource-zookeeperartifactId>
<version>1.7.2version>
dependency>
2.在application.properties中配置连接sentinel控制台
# 设置应用的名称
spring.application.name=SentinelZookeeper
# 设置Sentinel连接控制台的主机地址和端口
spring.cloud.sentinel.transport.dashboard=localhost:9000
3.创建ZookeeperSentinelConfig,设置客户端修改获取规则的地方为从zookeeper获取规则。
@Component
public class ZookeeperSentinelConfig {
/**
* 连接zookeeper获取规则
*/
@PostConstruct
public void loadRules(){
//Zookeeper 服务端的连接地址
String remoteAddress = "127.0.0.1:2181";
//Zookeeper中的数据路径
String path = "/Sentinel/zookeeper";
//构建资源
//参数1:zookeeper服务端地址
//参数2:zookeeper数据路径
//参数3:设置存放数据类型
ReadableDataSource<String, List<FlowRule>> readableDataSource = new ZookeeperDataSource<>(
remoteAddress,
path,
source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {})
);
//将数据资源注册到FlowRuleManager
FlowRuleManager.register2Property(readableDataSource.getProperty());
}
}
4.创建ZookeeperController,设置流控资源配置
@RestController
public class ZookeeperController {
//定义限流资源和限流讲解回调函数
@SentinelResource(value = "Sentinel_Zookeeper",blockHandler = "exceptionHandler")
@GetMapping("zookeeper")
public String hello() {
return "Hello Sentinel!";
}
// blockHandler函数,原方法调用被限流/降级/系统保护的时候调用
public String exceptionHandler(BlockException ex) {
ex.printStackTrace();
return "系统繁忙,请稍候";
}
}
5.创建单元测试,编写代码,模拟往zookeeper中传递规则,然后再从客户端获取
@RunWith(SpringRunner.class)
@SpringBootTest
public class SentinelZookeeperApplicationTests {
@Test
public void contextLoads() throws Exception {
//zookeeper的服务端连接地址
final String remoteAddress = "127.0.0.1:2181";
//发送的规则
//resource : 资源名
//controlBehavior:流控效果
//count:阀值
//grade:规则类型
//limitApp:调用来源
//strategy:判断根据是资源自身,还是根据其他关联资源,还是根据链路入口
final String rule = "[\n"
+ " {\n"
+ " \"resource\": \"Sentinel_Zookeeper\",\n"
+ " \"controlBehavior\": 0,\n"
+ " \"count\": 2.0,\n"
+ " \"grade\": 1,\n"
+ " \"limitApp\": \"default\",\n"
+ " \"strategy\": 0\n"
+ " }\n"
+ "]";
//创建连接zookeeper
CuratorFramework zkClient = CuratorFrameworkFactory.newClient(remoteAddress, new ExponentialBackoffRetry
(1000, 3));
//开始连接
zkClient.start();
//配置zookeeper数据路径
String path = "/Sentinel/zookeeper";
Stat stat = zkClient.checkExists().forPath(path);
//发送数据给zookeeper
if (stat == null) {
zkClient.create().creatingParentContainersIfNeeded().withMode(CreateMode.PERSISTENT).forPath(path, null);
}
zkClient.setData().forPath(path, rule.getBytes());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//关闭连接
zkClient.close();
}
}
6.运行测试
启动本地zookeeper。
启动项目,查看Idea打印台日志,查看项目是否连接了zookeeper。
在浏览器输入http://localhost:8080/zookeeper,查看页面是否能显示请求返回的“Hello Sentinel!”。
但是这个时候是没有流控规则的,也就是连续刷新,页面始终会显示“Hello Sentinel!”。
运行单元测试,向zookeeper发送流控规则,查看Idea打印台查看是否想zookeeper发送流控规则成功
之后,在浏览器输入http://localhost:8080/zookeeper,慢速刷新,则持续显示”Hello Sentinel”;快速刷新则会交替出现”Hello Sentinel!”和“系统繁忙,请稍候”。这说明对资源限流成功。
流量控制在网络传输中是一个常用的概念,它用于调整网络包的发送数据。然而,从系统稳定性角度考虑,在处理请求的速度上,也有非常多的讲究。任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。我们需要根据系统的处理能力对流量进行控制。Sentinel 作为一个调配器,可以根据需要把随机的请求调整成合适的形状,如下图所示:
流量控制设计理念
流量控制有以下几个角度:
Sentinel 的设计理念是让您自由选择控制的角度,并进行灵活组合,从而达到想要的效果。
除了流量控制以外,及时对调用链路中的不稳定因素进行熔断也是 Sentinel 的使命之一。由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳定,可能会导致请求发生堆积,进而导致级联错误。
Sentinel 和 Hystrix 的原则是一致的: 当检测到调用链路中某个资源出现不稳定的表现,例如请求响应时间长或异常比例升高的时候,则对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联故障。
熔断降级设计理念
在限制的手段上,Sentinel 和 Hystrix 采取了完全不一样的方法。
Hystrix 通过线程池隔离的方式,来对依赖(在 Sentinel 的概念中对应资源)进行了隔离。这样做的好处是资源和资源之间做到了最彻底的隔离。缺点是除了增加了线程切换的成本(过多的线程池导致线程数目过多),还需要预先给各个资源做线程池大小的分配。
Sentinel 对这个问题采取了两种手段:
和资源池隔离的方法不同,Sentinel 通过限制资源并发线程的数量,来减少不稳定资源对其它资源的影响。这样不但没有线程切换的损耗,也不需要您预先分配线程池的大小。当某个资源出现不稳定的情况下,例如响应时间变长,对资源的直接影响就是会造成线程数的逐步堆积。当线程数在特定资源上堆积到一定的数量之后,对该资源的新请求就会被拒绝。堆积的线程完成任务后才开始继续接收请求。
除了对并发线程数进行控制以外,Sentinel 还可以通过响应时间来快速降级不稳定的资源。当依赖的资源出现响应时间过长后,所有对该资源的访问都会被直接拒绝,直到过了指定的时间窗口之后才重新恢复。
Sentinel 同时提供系统维度的自适应保护能力。防止雪崩,是系统防护中重要的一环。当系统负载较高的时候,如果还持续让请求进入,可能会导致系统崩溃,无法响应。在集群环境下,网络负载均衡会把本应这台机器承载的流量转发到其它的机器上去。如果这个时候其它的机器也处在一个边缘状态的时候,这个增加的流量就会导致这台机器也崩溃,最后导致整个集群不可用。
针对这个情况,Sentinel 提供了对应的保护机制,让系统的入口流量和系统的负载达到一个平衡,保证系统在能力范围之内处理最多的请求。
Sentinel 的主要工作机制如下: