Sentinel分布式系统的流量组件
Sentinel是阿里开源的项目,提供了流量控制、熔断降级、系统负载保护等多个维度来保障服务之间的稳定性。
官网:https://github.com/alibaba/Sentinel/wiki
1、主要特性
2、开源生态
3、Sentinel的基本概念
资源
资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,
或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。在接下来的文档中,我们都会用资源 来描述代码块。
只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方
法签名,URL,甚至服务名称作为资源名来标示资源。
规则
围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则 可以动态实时调整。
4、Sentinel的功能和设计理念
流量控制
流量控制在网络传输中是一个常用的概念,它用于调整网络包的发送数据。然而,从系统稳定性角度考
虑,在处理请求的速度上,也有非常多的讲究。任意时间到来的请求往往是随机不可控的,而系统的处
理能力是有限的。我们需要根据系统的处理能力对流量进行控制。Sentinel 作为一个调配器,可以根据 需要把随机的请求调整成合适的形状
流量控制有以下几个角度:
资源的调用关系,例如资源的调用链路,资源和资源之间的关系; 运行指标,例如 QPS、线程池、系统负载等;
控制的效果,例如直接限流、冷启动、排队等。 Sentinel 的设计理念是让您*选择控制的角度,并进行灵活组合,从而达到想要的效果。
熔断降级
除了流量控制以外,及时对调用链路中的不稳定因素进行熔断也是 Sentinel 的使命之一。由于调用关系
的复杂性,如果调用链路中的某个资源出现了不稳定,可能会导致请求发生堆积,进而导致级联错误。
在限制的手段上:
Sentinel 对这个问题采取了两种手段:
通过并发线程数进行限制
和资源池隔离的方法不同,Sentinel 通过限制资源并发线程的数量,来减少不稳定资源对其它资源的影
响。这样不但没有线程切换的损耗,也不需要您预先分配线程池的大小。当某个资源出现不稳定的情况
下,例如响应时间变长,对资源的直接影响就是会造成线程数的逐步堆积。当线程数在特定资源上堆积
到一定的数量之后,对该资源的新请求就会被拒绝。堆积的线程完成任务后才开始继续接收请求。
通过响应时间对资源进行降级
除了对并发线程数进行控制以外,Sentinel 还可以通过响应时间来快速降级不稳定的资源。当依赖的资
源出现响应时间过长后,所有对该资源的访问都会被直接拒绝,直到过了指定的时间窗口之后才重新恢
复。
Sentinel 同时提供系统维度的自适应保护能力。防止雪崩,是系统防护中重要的一环。
Sentinel 的主要工作机制如下:
对主流框架提供适配或者显示的 API,来定义需要保护的资源,并提供设施对资源进行实时统计和 调用链路分析。
根据预设的规则,结合对资源的实时统计信息,对流量进行控制。同时,Sentinel 提供开放的接 口,方便您定义及改变规则。 Sentinel
提供实时的监控系统,方便您快速了解目前系统的状态。
Sentinel HelloWorld实现
1、创建父级maven空项目,-----sentineltest
导入依赖:
<modules>
<module>sentinel-springcloud</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.bdqn</groupId>
<artifactId>sentineltest</artifactId>
<packaging>pom</packaging> //记得这里需要加packaging标签 父类型都为pom类型
<version>0.0.1-SNAPSHOT</version>
<name>sentineltest</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring-cloud.version>2020.0.4</spring-cloud.version>
<springboot.version>2.5.5</springboot.version>
<springcloudalibaba.version>2021.1</springcloudalibaba.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${springboot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<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>
2、创建新模块---- sentinel-helloworld
导入依赖:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2021.1</version>
</dependency>
2、application.yml配置文件:
server:
port: 8082
servlet:
context-path: /
spring:
application:
name: sentinel-helloWorld
cloud:
sentinel:
transport:
dashboard: localhost:8080
新建启动类SentinelHelloworldApplication :
@SpringBootApplication
@EnableAsync //支持异步调用
public class SentinelHelloworldApplication {
public static void main(String[] args) {
SpringApplication.run(SentinelHelloworldApplication.class, args);
}
}
3、controller层新建SentinelHelloWorld:定义规则和使用限流规则
/**
* @author 江江江
* @create 2021/10/12 15:00
*/
@RestController
public class SentinelHelloWorld {
/**
* 定义限流规则
* PostConstruct 构造方法执行完执行方法 定义和加载限流规则
*/
@PostConstruct
public void initFlowRules(){
List<FlowRule> rules=new ArrayList<>(); //定义限流规则集合
FlowRule rule=new FlowRule(); //定义限流规则
rule.setResource("helloworld");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS); //定义限流规则类型
rule.setCount(2); //定义QPS阙值 每秒最多通过的请求个数
rules.add(rule); //添加规则到集合
FlowRuleManager.loadRules(rules); //加载规则集合
}
}
4、测试:
Sentinel dashboard控制台搭建
Sentinel 控制台是流量控制、熔断降级规则统一配置和管理的入口,它为用户提供了机器自发现、簇点
链路自发现、监控、规则配置等功能。在 Sentinel 控制台上,我们可以配置规则并实时查看流量控制效
果。
1、下载sentinel-dashboard-1.8.1.jar
https://github.com/alibaba/Sentinel/releases/download/1.8.1/sentinel-dashboard-1.8.1.jar
2、启动 Sentinel 控制台需要 JDK 版本为 1.8 及以上版本。
java -jar sentinel-dashboard-1.8.2.jar
也可以使用这个命令
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -
Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
3、http://localhost:8080/ 访问 用户名和密码都是 sentinel
4、客户端sentinel-helloworld模块
创建AspectJ 配置类
@Configuration
public class SentinelResourceAspectConfiguration {
@Bean
public SentinelResourceAspect sentinelResourceAspect(){
return new SentinelResourceAspect();
}
}
controller层SentinelHelloWorld
@RestController
public class SentinelHelloWorld {
@Resource
private AsyncService asyncService;
@RequestMapping("helloworld")
public String helloWorld(){
try(Entry entry= SphU.entry("HelloWorld")){ //使用限流围观 HelloWorld
return "Sentinel 你好!"+System.currentTimeMillis();
} catch (Exception e) {
e.printStackTrace();
return "系统繁忙,请稍后!"; //降级处理
}
}
/**
* 返回值布尔值定义资源
* @return
*/
@RequestMapping("helloWorld2")
public String helloWorld2(){
//资源名称可使用任意业务语文的字符串
if(SphO.entry("HelloWorld2")){
//务必保证finally会被执行
try {
/**
* 被保护的业务逻辑
*/
return "Sentinel2 你好!"+System.currentTimeMillis();
}finally {
SphO.exit();
}
}else {
//资源访问阻止 被限流或被降级
//进行相应的处理操作
return "系统繁忙,请稍后!"; //降级处理
}
}
/**
* 注解方式定义资源
* @return
*/
@SentinelResource(value = "helloWorld3",blockHandler = "blockHandlerForHelloWorld3")
@RequestMapping("helloWorld3")
public String helloWorld3(){
return "Sentinel3 你好!by 注解方法@SentinelResource"+System.currentTimeMillis();
}
/**
* 原方法调用被限流、降级、系统保护的时候调用
* @param ex
* @return
*/
public String blockHandlerForHelloWorld3(BlockException ex){
ex.printStackTrace();
return "系统繁忙,请稍后!";
}
/**
* 异步支持
*/
@RequestMapping("helloWorld4")
public void helloWorld4(){
AsyncEntry asyncEntry=null;
try {
asyncEntry =SphU.asyncEntry("helloWorld4");
asyncService.doSomethingAsync();
}catch (BlockException e){
System.out.println("系统繁忙,请稍后!");
}finally {
if(asyncEntry!=null){
asyncEntry.exit();
}
}
}
}
5、创建AsyncService异步调用类以及方法
@Service
public class AsyncService {
@Async
public void doSomethingAsync(){
System.out.println("async start....");
try {
Thread.sleep(400);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("async end....");
}
}
6、新建sentinel-springcloud模块
导入依赖:
sentinel整合nacos实现配置持久化
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2021.1</version>
</dependency>
<--sentinel整合nacos实现配置持久化--!>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
配置application.yml文件
server:
port: 8082
servlet:
context-path: /
spring:
application:
name: sentinel-springcloud #设置应用名称
cloud:
sentinel:
transport:
dashboard: localhost:8080 #设置sentinel连接控制台的主机地址和端口
datasource:
ds:
nacos:
server-addr: localhost:8848 #nacos连接地址
group-id: DEFAULT_GROUP #nacos连接的分组
rule-type: flow #流控规则 rule-type配置表示该数据中的规则属于那种类型的规则(flow,degrade,authority,system, param-flow, gw-flow, gw-api-group)
data-id: java1234_sentinel # 读取配置文件的 data-id
data-type: json # 读取培训文件类型为json
controller层SentinelHelloWorld 类
@RestController
public class SentinelHelloWorld {
/**
* 注解方式定义资源
* @return
*/
@SentinelResource(value = "helloWorld_springcloud",blockHandler = "blockHandlerForHelloWorld3")
@RequestMapping("helloWorld3")
public String helloWorld3(){
return "Sentinel3 你好!by 注解方法@SentinelResource"+System.currentTimeMillis();
}
/**
* 原方法调用被限流、降级、系统保护的时候调用
* @param ex
* @return
*/
public String blockHandlerForHelloWorld3(BlockException ex){
ex.printStackTrace();
return "系统繁忙,请稍后!";
}
}
6、测试成功
进入sentinel控制台即可实时监控、以及进行编辑
流量控制(flow control),其原理是监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时
对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。
限流类型分为:
QPS: 每秒请求数限制
线程数: 资源使用线程数限制
流控模式
直接: 资源直接限流,这个就是简单的限流。
关联: 关联模式需要填写关联资源的路径,意为如果关联资源的流量超额之后,限流自己(自己为资
源名填写的路径)。
链路: 如果是链路模式需要填写入口资源,限制入口资源对自己的调用。
流控效果
快速失败: (Ruleconstant.CONTROL_BEHAVIOR_DEFAULT)方式是默认的流量控制方式,当QPS超过
任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出F1owException。这种方式适用于对系
统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时。
Warm Up: (RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热/冷启动方式。当系统长期
处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启
动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系
统被压垮。
排队等待: (RuleConstant.cONTROL_BEHAV工OR_RATE_LIMITER)方式会严格控制请求通过的间隔时
间,也即是让请求以均匀的速度通过,对应的是漏桶算法。
同一个资源可以同时有多个限流规则,检查规则时会依次检查。
熔断规则
需要对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定调用,
避免局部不稳定因素导致整体的雪崩。熔断降级作为保护自身的手段,通常在客户端(调用端)进行配
置。
启动sentinel-springcloud项目,发现sentinel控制台读取到了nacos里的配置,频繁刷新也能流控;