# study
**Repository Path**: jiangbogu/study
## Basic Information
- **Project Name**: study
- **Description**: this is a study project
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 0
- **Created**: 2020-09-05
- **Last Updated**: 2022-08-05
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
---
![]()typora-root-url: ./images
---
### study
this is a study project
# Sentinel流量控制
### 1.Sentinel 导学
> 随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式服务架构的**轻量级**流量控制框架,主要以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度来帮助您保护服务的稳定性。
#### 1.1 Sentinel 的历史
> - 2012 年,Sentinel 诞生,主要功能为入口流量控制。
> - 2013-2017 年,Sentinel 在阿里巴巴集团内部迅速发展,成为基础技术模块,覆盖了所有的核心场景。Sentinel 也因此积累了大量的流量归整场景以及生产实践。
> - 2018 年,Sentinel 开源。
#### 1.2 Sentinel 基本概念
**资源**
> 资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。在接下来的文档中,我们都会用资源来描述代码块。
>
> 只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。
**规则**
> 围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。
#### 1.3 Sentinel 组成
> Sentinel 的使用主要分为两个部分:
>
> - **核心库**:主要指Java客户端,不依赖任何框架,能够运行于Java7及其以上的版本的运行环境,同时对Dubbo/Cloud等框架有较好的支持。
> - **控制台**:控制台主要负责管理推送规则,监控,集群限流分配管理,机器发现等。
#### 1.4 Sentinel特征
- **丰富的应用场景**:Sentinel承接了阿里巴巴近10年的双十一流量的核心业务场景。例如秒杀、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
- **完备的实时监控**:Sentinel同时提供实时监控功能。可以在控制台看到接入应用的单台机器秒级数据,深知500台一下的规模的集群汇总运行情况。
- **广泛的开源生态**:Sentinel提供开箱即用的与其他开源框架的整合模块。例如:SpringCloud、Dubbo、gRPC的整合,只需要引入相关的依赖包并进行简单的配置即可。
- **完善的SPI扩展点**:Sentinel提供简单易用、完善的SPI扩展接口,可以通过实现扩展接口快速的定制逻辑。例如,定制规则管理,适配动态数据源等。
### 2. Sentinel 入门
#### 2.1 流量控制&熔断降级介绍
##### 2.1.1 流量控制简介
> 流量控制在网络传输中是一个常用的概念,他用于调整网络包的发送数据。在网络传输中, 任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。我们需要根据系统的处理能力对流量进行控制。
##### 2.1.2 熔断降级简介
> 在调动系统的时候,如果调用链路中的某个资源出现了不稳定,最终会导致请求发生堆积。
>
> 而熔断降级就可以解决这个问题,所谓的熔断器就是当检测到调用链路中某个资源出现不稳定的表现,例如请求响应时间长或者异常比例升高的时候,则对这个资源的调用进行限制,让请求快速失败(fast-fail),避免影响到其他的资源而导致级联故障。
##### 2.1.3 流量控制&熔断降级实现方案
**Hystrix** **Resilience4j** **Sentinel**
三种产品对比
| | Sentinel | Hystrix | Resilience4j |
| -------------- | :--------------------------------------------------------- | :-------------------- | -------------------------------- |
| 隔离策略 | 信号量隔离(并发线程数隔离) | 线程池隔离/信号量隔离 | 信号量隔离 |
| 熔断降级策略 | 基于响应时间、异常比率、异常数 | 基于异常比率 | 基于异常比率、响应时间 |
| 实时统计实现 | 滑动窗口 | 滑动窗口 | Ring Bit Buffer |
| 动态规则配置 | 支持多种数据源 | 支持多种数据源 | 有限支持 |
| 扩展性 | 多个扩展点 | 插件的形式 | 接口的形式 |
| 基于注释的支持 | 支持 | 支持 | 支持 |
| 限流 | 基于QPS,支持基于调用关系的限流 | 有限的支持 | Rate Limiter |
| 流量整形 | 支持预热模式、匀速器模式、预热排队模式 | 不支持 | 简单的Rate Limiter模式 |
| 系统自适应保护 | 支持 | 不支持 | 不支持 |
| 控制台 | 提供开箱即用的控制台,可配置规则,查看秒级监控,机器发现等 | 简单的监控查看 | 不提供控制台,可对接其他监控系统 |
##### 2.1.4 公网Demo
公网Demo的操作主要分为三部分
- 下载公网Demo
- 公网Demo接入阿里AHAS控制台
- 定义公网Demo的流控规则
> 第一步:下载Demo


第二步 本地代码演练
wget https://ahasoss-cn-hangzhou.oss-cn-hangzhou.aliyuncs.com/sdk/latest/ahas-sentinel-sdk-demo.jar
java -Dahas.namespace=default -Dproject.name=AppName -Dahas.license=669f0a77e53d48778f492bf644e659e2 -jar
ahas-sentinel-sdk-demo.jar
> 第三步 到应用高可用服务控制台查看具体信息

### 3. Sentinel流量控制降级入门
Sentinel本地应用流控降级实现分为三步:
1. 创建本地应用
2. 搭建本地Sentinel控制台
3. 本地应用接入本地Sentinel控制台
##### 3.1 本地应用搭建
**整体流程分析**
1. 创建SpringBoot项目
2. 在项目的pom.xml文件中引入sentinel-core依赖坐标
3. 创建TestController,定义使用流量规则
4. 运行测试
**具体流程**
**1. 创建SpringBoot项目,名称为sentinel-quick-start**
**2. 在项目中引入sentinel-core的依赖坐标**
```xml
study
com.gujiangbo
1.0-SNAPSHOT
../pom.xml
4.0.0
study-sentinel-quick-start
1.0-SNAPSHOT
jar
1.8
com.alibaba.csp
sentinel-core
1.7.2
org.springframework.boot
spring-boot-starter-web
RELEASE
compile
```
2. **创建Controller**
```java
package com.gujiangbo.sentinel.controller;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
@RestController
public class HelloController {
@GetMapping("sayHello")
public String sayHello() {
/**
* 使用限流规则
*/
try {
//限流入口
Entry hello = SphU.entry("Hello");
return "hello Sentinel !";
} catch (BlockException e) {
e.printStackTrace();
return "系统繁忙,请稍后重试";//限流或者降级处理
}
}
/**
* 自定义限流规则
*/
@PostConstruct//当前类的构造函数执行完毕之后再执行的方法
public void initFlowRules() {
//1.创建限流规则集合
List rules = new ArrayList();
//2.创建限流规则
FlowRule flowRule = new FlowRule();
//定义资源,标识Sentinel对哪个资源生效
flowRule.setResource("Hello");
//定义限流规则类型,QPS
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
//QPS设置限流值,每秒通过的请求个数
flowRule.setCount(2);
//3.将限流规则存放到集合中
rules.add(flowRule);
//4.加载限流规则
FlowRuleManager.loadRules(rules);
}
}
```
3. **启动服务**
```java
@SpringBootApplication
public class SentinelApplication {
public static void main(String[] args) {
SpringApplication.run(SentinelApplication.class, args);
}
}
```
```clojure
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.4.2)
2021-01-26 21:12:39.227 INFO 11516 --- [ main] c.g.sentinel.SentinelApplication : Starting SentinelApplication using Java 1.8.0_151 on gujiangbodeMacBook-Pro.local with PID 11516 (/Users/gujiangbo/IdeaProjects/study/study-sentinel-quick-start/target/classes started by gujiangbo in /Users/gujiangbo/IdeaProjects/study)
2021-01-26 21:12:39.233 INFO 11516 --- [ main] c.g.sentinel.SentinelApplication : No active profile set, falling back to default profiles: default
2021-01-26 21:12:41.713 INFO 11516 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2021-01-26 21:12:41.723 INFO 11516 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2021-01-26 21:12:41.724 INFO 11516 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.41]
2021-01-26 21:12:41.818 INFO 11516 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2021-01-26 21:12:41.820 INFO 11516 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2410 ms
INFO: Sentinel log output type is: file
INFO: Sentinel log charset is: utf-8
INFO: Sentinel log base directory is: /Users/gujiangbo/logs/csp/
INFO: Sentinel log name use pid is: false
2021-01-26 21:12:42.202 INFO 11516 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2021-01-26 21:12:42.486 INFO 11516 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2021-01-26 21:12:42.503 INFO 11516 --- [ main] c.g.sentinel.SentinelApplication : Started SentinelApplication in 5.142 seconds (JVM running for 7.762)
2021-01-26 21:13:12.223 INFO 11516 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2021-01-26 21:13:12.224 INFO 11516 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2021-01-26 21:13:12.225 INFO 11516 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms
```
4. **浏览器访问controller**
**设定每秒请求限流为2次。频繁刷新容易报错。**


5. **Sentinel本地日志**

##### 3.2 本地Sentinel控制台
> Sentinel提供一个轻量级的开源控制台,它提供机器发现以及健康状况管理、实时监控(单机或者集群)、规则管理和推送的功能。
**本地控制台的搭建**
1. **下载Sentinel控制台的jar包**
下载地址:https://github.com/alibaba/Sentinel/releases/download/1.7.2/sentinel-dashboard-1.7.2.jar
2. **启动Sentinel控制台**
启动Sentinel控制台需要JDK1.8以上版本
使用以下命令启动控制台:
> java -Dserver.port=9000 -jar sentinel-dashboard-1.7.2.jar

3. **访问Sentinel控制台**
通过浏览器http://localhost:9000即可访问Sentinel控制台,用户名密码均是sentinel
##### 3.3 **应用接入控制台**
> 本地应用是以客户的身份来接入控制台,具体步骤如下:
1. **本地应用的pom.xml文件引入依赖**
```xml
com.alibaba.csp
sentinel-transport-simple-http
1.7.2
```
2. **在本地应用的VM启动参数**
-Dcsp.sentinel.dashboard.server=localhost:9000 设置Sentinel控制台的主机地址和端口
-Dproject.name=SentinelQuickStart 设置本地应用在Sentinel控制台的名称

3. **页面访问控制台并刷新**
在访问控制台之前,手动调用接口并触发规则,否则Sentinel不会主动与控制台通讯

> 需要注意的是应用配置好之后与控制台的连接参数之后,并不会主动连接控制台,需要触发一次规则才会开始进行初始化,并向控制台发送心跳和应用规则等信息。
>
> 此外还需要注意的是Sentinel提供了两种设置流控规则的方式
>
> - 在应用中使用代码编写流控规则(案例中使用的方式)
> - 在Sentinel控制台设置流控规则
在Sentinel控制台的左侧菜单中选择流控规则即可对限流规则进行调整

如何使用控制台限流规则?
> - 将代码中限流规则去除
> - 在控制台**流控规则**中新增加流控规则,注意,流控规则**资源名**要与代码中的**Hello**保持一致。否则无法触发限流规则!!
##### 3.4 Sentinel定义资源的方式
Sentinel除了基本的定义资源的方式之外,还有其他的定义资源方式。具体如下:
- 抛出异常的方式定义资源
- 返回布尔值定义资源
- 异步调用支持
- 注解方式定义资源
- 主流框架默认适配
###### 3.4.1 抛出异常的方式定义资源
Sentinel中的SphU包含了try-catch风格的API。用这种方式,当资源发生了限流之后会抛出BlockException。这个时候可以捕捉到异常,进行限流之后的逻辑处理,而我们在入门案例中使用 了这种方式定义资源。关键代码如下:
```java
try {
//限流入口
Entry hello = SphU.entry("Hello");
return "hello Sentinel !";
} catch (BlockException e) {
e.printStackTrace();
return "系统繁忙,请稍后重试";//限流或者降级处理
}
```
###### 3.4.2 **返回布尔值方式定义资源**
Sentinel的sphU提供了if-else风格的API。用这种方式,当资源发生了限流之后就会返回false.这个时候可以根据返回值,进行限流之后的逻辑处理。
测试代码如下:
```java
//1.进行限流控制
if (SphO.entry("boolean")) {//限流入口
try {
//被保护的资源
System.out.println("访问成功");
return "访问成功!";
} finally {
//sphO.entry(xxx)需要与SphO.exit()方法成对出现,否则会导致调用链记录异常,抛出ErrorEntryFreeException异常
SphO.exit();
}
} else {
//被限流或者降级的处理
System.out.println("系统繁忙,请稍后再试!");
return "系统繁忙,请稍后再试!";
}
```
###### 3.4.3 **异步调用支持**
> Sentinel支持异步调用链路的统计。在异步调用中,需要通过SphU.asyncEntry(xxx)方法定义资源,并通常需要在异步的回调函数中调用exit方法。
1. 在本地应用的引导类上添加@EnableAsync,表示SpringBoot项目开始异步调用支持
```java
@SpringBootApplication
@EnableAsync
public class SentinelApplication {
public static void main(String[] args) {
SpringApplication.run(SentinelApplication.class, args);
}
}
```
2. 创建AsyncService编写异步调用方法
```java
@Service
public class AsyncService {
@Async
public void hello() {
System.out.println("异步开始=======");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("异步调用完成======");
}
}
```
3. 创建Controller,实现异步限流控制
```java
@RestController
public class AsyncHelloController {
@Autowired
private AsyncService asyncService;
@GetMapping("async")
public void sayHello() {
//限流开始
AsyncEntry asyncEntry = null;
try {
asyncEntry = SphU.asyncEntry("Sentinel_Async");//限流入口
asyncService.hello();
} catch (BlockException e) {
System.out.println("系统繁忙,稍后再试!!!!!");
} finally {
if (asyncEntry != null) {
asyncEntry.exit();
}
}
}
/**
* 自定义限流规则
*/
/* @PostConstruct//当前类的构造函数执行完毕之后再执行的方法
public void initFlowRules() {
//1.创建限流规则集合
List rules = new ArrayList();
//2.创建限流规则
FlowRule flowRule = new FlowRule();
//定义资源,标识Sentinel对哪个资源生效
flowRule.setResource("Sentinel_Async");
//定义限流规则类型,QPS
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
//QPS设置限流值,每秒通过的请求个数
flowRule.setCount(2);
//3.将限流规则存放到集合中
rules.add(flowRule);
//4.加载限流规则
FlowRuleManager.loadRules(rules);
}*/
}
```
4. 运行测试
在Sentinel控制台增加关于Sentinel_Async资源的流控规则

6. 测试结果
###### 3.4.4 **注解方式定义资源**
> Sentinel支持通过@SentinelResource注解定义资源并配置blockHandler函数来进行限流之后的处理
1. 在本应用中的pom.xml中引入支持的注解依赖Sentinel-annotation-aspectj依赖
```xml
com.alibaba.csp
sentinel-annotation-aspectj
1.7.2
```
2. 创建Aspectj的配置类
```java
@Configuration
public class SentinelAspectConfiguration {
@Bean
public SentinelResourceAspect sentinelResourceAspect() {
return new SentinelResourceAspect();
}
}
```
3. 创建AnnHelloController,实现限流控制
```java
@RestController
public class AnnHelloController {
@SentinelResource(value = "Sentinel_Ann", blockHandler = "exceptionHandler")
@GetMapping("ann")
public String hello() {
return "this is sentinel annotation say Hello World !!";
}
/**
* 自定义降级处理
* @param blockException
* @return
*/
public String exceptionHandler(BlockException blockException) {
blockException.printStackTrace();
return "系统繁忙,请稍后再试!";
}
}
```
4. Sentinel控制台对资源名添加降级策略
5. 页面每秒访问超过三次触发降级策略

- @SentinelResource注解用来标识资源是否被限流、降级等。上述例子该注解的属性’Sentinel_Ann‘表示资源名。
###### 3.4.5 主流框架的默认适配
> 为了减少开发的复杂程度,我们对大部分的主流框架例如:Web Servlet、Dubbo、SpringCloud、gRPC、Spring WebFlux、Reactor等做了适配。只需要引用对应的依赖即可方便的整合Sentinel.
### 4.Sentinel高级
#### 4.1 Sentinel和SpringCloud整合
> 如果要实现SpringCloud与Sentinel的整合,可以引入Spring Cloud Alibaba Sentinel来方便的整合Sentinel。
>
> Spring CloudAlibaba是阿里巴巴提供的,致力于提供微服务开发的一站式解决方案。Spring Cloud Alibaba 默认为Sentinel整合Servlet、RestTemplate、FeignClient和Spring WebFlux。Sentinel在Spring Cloud生态中,不仅补全了Hystrix 在Servlet和RestTemplate这一块的空白,而且还完全兼容了Hystrix和FeignClient中限流降级的用法,并且支持运行时灵活地配置和调整限流降级的规则。
**案例**
使用Spring Cloud + Sentinel 实现访问 http://localhost:8080/ann 路径的流量控制
**具体步骤**
1. 创建SpringCloud 项目,在项目引入spring-cloud-starter-alibaba依赖
```xml
com.alibaba.cloud
spring-cloud-alibaba-sentinel
2.1.0.RELEASE
```
2. 在项目中创建TestController
```java
@RestController
public class TestController {
@GetMapping("hello")
@SentinelResource(value = "Sentinel_SpringCloud", blockHandler = "exceptionHandler")
public String hello() {
return "Hello World !!";
}
public String exceptionHandler(BlockException ex) {
ex.printStackTrace();
return "触发熔断机制!服务器异常,请稍后再试!";
}
}
```
3. 在application.properties中添加本地项目配置并接入本地控制台
```properties
# 项目名称
spring.application.name=SpringCloudSentinel
# 设置Sentinel连接控制台的ip和端口
spring.cloud.sentinel.transport.dashboard=localhost:9000
```
4. 运行测试
> 在Sentinel控制台中增加Sentinel_SpringCloud资源的流控规则
#### 4.2 Sentinel 对Feign 的支持
Sentinel适配了Feign组件,如果想使用,除了引入spring-cloud-starter-alibaba-sentinel的依赖外,还需要两个步骤:
- 配置文件打开Sentinel对Feign的支持,feign-sentinel.enable=true
- 加入spring-cloud-starter-openfeign依赖Sentinel starter中的自动化配置类生效
添加依赖
```xml
org.springframework.cloud
spring-cloud-starter-alibaba-sentinel
0.2.1.RELEASE
```
需要在配置文件中开启 sentinel 对 feign 的支持:
```properties
feign.sentinel.enabled=true
```