一、 Spring Cloud Alibaba Sentinel简介

1 简介

Sentinel 是面向分布式服务架构的高可用流量防护组件,主要以流量为切入点,从限流、流量控制、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定性。

2 发展历史

2012 年,Sentinel 诞生,主要功能为入口流量控制。
2013-2017 年,Sentinel 在阿里巴巴集团内部迅速发展,成为基础技术模块,覆盖了所有的核心场景。Sentinel 也因此积累了大量的流量归整场景以及生产实践。
2018 年,Sentinel 开源,并持续演进。
2019 年,Sentinel 朝着多语言扩展的方向不断探索,推出 C++ 原生版本,同时针对 Service Mesh(服务网格) 场景也推出了 Envoy 集群流量控制支持,以解决 Service Mesh 架构下多语言限流的问题。
2020 年,推出 Sentinel Go 版本,继续朝着云原生方向演进。

3 特性

丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI(Service Provider Interface) 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。
Sprinig Cloud Alibaba Sentinel服务限流 - 图1

4 Sentinel功能和设计理念

4.1 流量控制

流量控制是互联网应用非常重要的一个概念。Sentinel作为流量控制适配器可以把随机过来的流量调整成合适的形状。当超出服务器上限会丢弃部分请求。
Sprinig Cloud Alibaba Sentinel服务限流 - 图2

4.2 熔断降级

灾难性雪崩效应是在服务链条中可能出现的问题。熔断降级是在服务链条中不可缺少的一部分。熔断降级就是Sentinel的一大功能。
Sentinel中熔断降级功能和Hystrix的原则是一样的。当服务和服务请求超时或资源不足时,会让本次调用进行快速降级或熔断。保证整个链条的完整性。
Sentinel和Hystrix在处理熔断的手段是完全不一样的。Hystrix主要是通过线程池隔离或信号量隔离,虽然能够实现彻底的隔离,但是增加了线程切换的成本。

4.3 通过控制资源的并发数进行限流

Sentinel通过控制资源的并发数,来减少不稳定资源对其他资源的影响。当某个资源请求响应变长以后,就会逐渐累积线程数,当线程数到达一定的数量后就会拒绝其他的请求。这样不但没有线程切换的消耗,也不需要预先分配线程池的大小(或信号量的大小)

4.4 针对慢调用或异常进行降级

Sentinel可以根据响应时间或异常等不稳定因素进行熔断。当调用的资源出现响应时间变长,就会拒绝访问,直到调用资源逐渐恢复。

4.5 系统自适应保护机制

无论是单机应用还是集群应用都会有一个负载上限,当超过负载上限就会导致单机或集群应用崩溃。Sentinel会自动监听整个单机或集群应用的入口,让入口流量达到负载均衡,保证系统在能力范围内处理最多请求。

二、 基于Docker安装Sentinel Dashboard

  1. 拉取镜像
    # docker pull bladex/sentinel-dashboard
    2. 创建并运行容器
    # docker run —name sentinel -d -p 8858:8858 —restart=always bladex/sentinel-dashboard
    默认控制台默认用户名和密码都是sentinel(全小写)
    3. 访问dashboard
    在windows浏览器输入 http://192.168.8.128:8858 会出现下面页面。
    默认用户名和密码都是sentinel
    Sprinig Cloud Alibaba Sentinel服务限流 - 图3

    三、 搭建Spring Boot项目并交给Sentinel进行控制

    搭建一个具有简单控制器的Web项目。
    在pom中引入sentinel依赖,并在配置文件中配置交给Sentinel进行管理。

    1 新建Maven项目

    新建项目sentineldemo

    2 配置pom.xml

    | <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.6.RELEASE</version> <relativePath/>
    </parent><dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.2.3.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
    | | —- |

3 新建配置文件

新建application.yml.
l spring.cloud.sentinel.transport.dashboard 指定了sentinel控制台的ip和端口地址;
l spring.cloud.sentinel.transport.port代表sentinel客户端和控制台通信的端口,默认为8719,如果这个端口已经被占用,那么sentinel会自动从8719开始依次+1扫描,直到找到未被占用的端口。

server:
port: 8080
spring:
application:
name: sentinel-client
cloud:
sentinel:
transport:
dashboard: 192.168.8.128:8858
port: 8719

4 新建控制器

新建com.bjsxt.controller.SentinelController

@RestController
public class SentinelController {
@RequestMapping(“/hello”)
public String demo(){
return “hello-world”;
}
}

5 新建启动类

新建com.bjsxt.SentineldemoApplication

@SpringBootApplication
public class SentineldemoApplication {
public static void main(String[] args) {
SpringApplication.run(SentineldemoApplication.class, args);
}
}

6 访问控制器

在浏览器多次访问输入http://localhost:8080/hello
在Sentinel Dashboard中会出现一个名称为sentinel-client项。
Sprinig Cloud Alibaba Sentinel服务限流 - 图4

四、 Sentinel Dashboard - 实时监控

Sentinel Dashboard 提供了通过可视化简单方便的控制所有控制,学习好Dashboard,就掌握绝大多数Sentinel的功能。
实时监控功能主要显示服务的QPS。包含通过QPS和拒绝QPS
Sprinig Cloud Alibaba Sentinel服务限流 - 图5

五、 Sentinel Dashboard - 簇点链路 - 流控

簇点链路显示了当前服务中所有URL.并可以对每个URL进行流控、降级、热点、授权操作。
Sprinig Cloud Alibaba Sentinel服务限流 - 图6
l 资源名:标识资源的唯一名称,默认为请求路径,也可以在客户端中使用@SentinelResource配置;
l 针对来源:Sentinel可以针对服务调用者进行限流,填写微服务名称即spring.application.name,默认为default,不区分来源;
l 阈值类型、单机阈值:

Ø QPS(Queries-per-second,每秒钟的请求数量):当调用该api的QPS达到阈值的时候,进行限流;
Ø 线程数:当调用该api的线程数达到阈值的时候,进行限流。
Ø 是否集群:默认不集群;

l 流控模式:

ü 直接:当api调用达到限流条件的时,直接限流;
ü 关联:当关联的资源请求达到阈值的时候,限流自己;
ü 链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,则进行限流)。
l 流控效果:

v 快速失败:直接失败;
v Warm Up(预热):根据codeFactor(冷加载因子,默认值为3)的值,从阈值/codeFactor(除法),经过预热时长,才达到设置的QPS阈值;
v 排队等待:匀速排队,让请求匀速通过,阈值类型必须设置为QPS,否则无效。

1 快速失败

Sprinig Cloud Alibaba Sentinel服务限流 - 图7

按照上图所示,填写单机阈值为2,并点击新增按钮。会在Sentinel Dashboard中流控规则中出现我们建立的规则。
Sprinig Cloud Alibaba Sentinel服务限流 - 图8
在浏览器中快速访问3次,当1秒内访问超过2次后会直接决绝。
Sprinig Cloud Alibaba Sentinel服务限流 - 图9

2 warm up

warm up 模式可以防止突然出现大量请求。
按照下图单机阈值设置6.刚开始QPS只能是阈值/3,经过预热时长逐渐到达阈值。
Sprinig Cloud Alibaba Sentinel服务限流 - 图10
使用Apache jmeter进行测试。设置5秒40个请求
Sprinig Cloud Alibaba Sentinel服务限流 - 图11
会发现前期只能访问2个其他请求直接决绝,后面逐渐能访问6个。


Sprinig Cloud Alibaba Sentinel服务限流 - 图12

3 排队等待

排队等待,只要请求不超过设置的超时时间,就会一直等待。除非已经超过超时时间了。
Sprinig Cloud Alibaba Sentinel服务限流 - 图13

六、 Sentinel Dashboard - 簇点链路 - 降级


RT:响应时间,单位毫秒。指请求及响应的时间。最大RT :300,表示如果请求及响应时间超过300毫秒则为慢调用。
比例阈值:取值[0.0-1.0],0表示0%,1.0表示100%。表示慢调用出现的比例。
最小请求数:进行判断的最小请求的数量。
熔断时长:当满足熔断条件后,熔断时间。
熔断策略:
慢调用比例:按照响应时间进行判断,比例,数量进行判断。
异常比例:按照异常比例进行判断。
异常数量:按照异常的数量进行判断。
Sprinig Cloud Alibaba Sentinel服务限流 - 图14

在代码控制器接口中添加休眠1秒。

@RestController
public class SentinelController {
@RequestMapping(“/hello”)
public String demo(){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return “hello-world”;
}
}


使用Jmeter测试发现被Sentinel进行降级。

七、 Sentinel Dashboard - 簇点链路 - 热点

热点规则要求必须在控制器方法中给资源名称,否则不生效。

@RestController
public class SentinelController {
@RequestMapping(“/hello”)
@SentinelResource(“abc”)
public String demo(String name){
return “hello-world”+name;
}
}


对资源名称为选择abc的热点
Sprinig Cloud Alibaba Sentinel服务限流 - 图15
对abc添加热点规则
Sprinig Cloud Alibaba Sentinel服务限流 - 图16
测试效果,发现访问/hello时QPS阈值为1
在热点规则中进行编辑
Sprinig Cloud Alibaba Sentinel服务限流 - 图17


点击高级选项,按照下图进行填写。设置参数值为abc。阈值为2.表示参数为abc时不受上面单机阈值的影响。
Sprinig Cloud Alibaba Sentinel服务限流 - 图18

八、 Sentinel Dashboard - 簇点链路 - 授权规则

授权规则是设置可访问服务的黑名单和白名单。
在被调用方添加配置类,根据ip进行限流。

@Component
public class MyParser implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest httpServletRequest) {
String remoteAddr = httpServletRequest.getRemoteAddr();
System.out.println(remoteAddr);
return remoteAddr;
}
}


Sprinig Cloud Alibaba Sentinel服务限流 - 图19

九、 系统规则

系统规则是对整个系统进行设置的规则。
阈值类型包含以下五种:
l Load 自适应(仅对 Linux/Unix-like 机器生效):系统的 load 作为启发指标,进行自适应系统保护。当系统 load超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的 maxQps minRt 估算得出。设定参考值一般是 CPU cores 2.5。
l CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏。
l 平均 RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
l 并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
l 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。

十、 @SentinelResource简介

Sentinel提供了@SentinelResouce注解来定义资源,并提供了异常回退和Block回退。
异常回退:在标注了@SentinelResouce注解的方法,发生了Java异常时的回退处理。
Block回退:@SentinelResource资源访问不符合Sentinel控制台定义的规则的回退。当没有定义Block回退时默认为Blocked by Sentinel (flow limiting)

十一、 案例演示

整个案例基础实现效果为:sentinel-consumer通过OpenFeign调用sentinel-provider的/provider控制器。
在这个基础上,通过在sentinel-consumer的service方法中添加异常进行演示fallback功能。在Sentinel控制台添加Qps演示block功能。
演示@SentinelResouce时一个项目即可演示。此处搭建两个项目为了演示下OpenFeign的调用。sentinel-provider中也可以添加@SentinelResource注解实现fallback和block功能。

1 新建Provider

新建一个Maven项目,命名为sentinel_provider

1.1 配置pom.xml

<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.6.RELEASE</version> <relativePath/>
</parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.2.3.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>

1.2 新建配置文件

新建application

server:
port: 8081
spring:
application:
name: sentinel-provider
cloud:
nacos:
discovery:
server-addr: 192.168.8.128:8848

1.3 新建控制器

新建com.bjsxt.controller.ProviderController

@RestController
public class ProviderController {
@RequestMapping(“/provider”)
public String provider(){
return “provider”;
}
}

1.4 新建启动类

新建com.bjsxt.ProviderApplication

@SpringBootApplication
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class,args);
}
}

1.5 在Nacos中观察是否注册成功

Sprinig Cloud Alibaba Sentinel服务限流 - 图20

2 新建Consumer项目

新建sentinel_consumer项目

2.1 配置pom.xml

<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.6.RELEASE</version> <relativePath/>
</parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version>2.2.3.RELEASE</version> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.2.3.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>

2.2 新建配置文件

新建application.yml

server:
port: 8083
spring:
application:
name: sentinel-consumer
cloud:
nacos:
discovery:
server-addr: 192.168.8.128:8848
sentinel:
transport:
dashboard: 192.168.8.128:8858
port: 8719

2.3 新建OpenFeign接口

新建com.bjsxt.feign.ProviderFeign

@FeignClient(“sentinel-provider”)
public interface ProviderFeign {
@RequestMapping(“/provider”)
public String provider();
}

2.4 新建service及实现类

新建com.bjsxt.service.ConsumerService及实现类。
在consumer()方法上添加了@SentinelResource注解。
value : 名称任意,此名称作为Sentinel中资源名称。
fallback:出现异常的降级方法。
blockHandler: 触发Sentinel规则后方法名。方法必须包含BlockException参数

public interface ConsumerService {
String consumer();
}
@Service
public class ConsumerServiceImpl implements ConsumerService {
@Autowired
private ProviderFeign providerFeign;
@SentinelResource(value = “suiyi”,fallback = “myFallback”,blockHandler = “myBlockHandler”) @Override
public String consumer() {
return providerFeign.provider();
}
public String myFallback(){
return “myfallback-method”;
}
public String myBlockHandler(BlockException block){
return “myBlockHandler”;
}
}

2.5 新建控制器

新建com.bjsxt.controller.ConsumerController

@RestController
public class ConsumerController {
@Autowired
private ConsumerService consumerService;

@RequestMapping(“/consumer”)
public String consumer(){
return consumerService.consumer();
}
}

2.6 新建启动类

新建com.bjsxt.ConsumerApplication

@SpringBootApplication
@EnableFeignClients
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class,args);
}
}

2.7 在Nacos中观察是否注册成功

Sprinig Cloud Alibaba Sentinel服务限流 - 图21

3 测试fallback效果

在sentinel-consumer的service实现类中添加一行代码,让方法出现异常。

@SentinelResource(value = “suiyi”,fallback = “myFallback”,blockHandler = “myBlockHandler”)
@Override
public String consumer() {
int i = 5/0;
return providerFeign.provider();
}


访问时发现。页面输出myfallback-method,说明调用了myFallback方法。
Sprinig Cloud Alibaba Sentinel服务限流 - 图22

4 测试block效果

在Sentinel中添加规则
Sprinig Cloud Alibaba Sentinel服务限流 - 图23
去掉sentinel-consumer中service的异常代码。
在浏览器中快速刷新3次,发现第三次输出下面效果
Sprinig Cloud Alibaba Sentinel服务限流 - 图24

十二、 持久化具体规则

Sentinel中各种流量控制可以借助持久化工具进行存储。
示例中利用:Nacos配置中心存储相关配置。

1 在Nacos中新建分布式配置

Sprinig Cloud Alibaba Sentinel服务限流 - 图25

[
{
“resource”: “/demo”,
“limitApp”: “default”,
“grade”: 1,
“count”: 6,
“strategy”: 0,
“controlBehavior”: 0,
“clusterMode”: false
}
]

resource:资源名,即限流规则的作用对象
limitApp:流控针对的调用来源,若为 default 则不区分调用来源
grade:限流阈值类型(QPS 或并发线程数);0代表根据并发线程数量来限流,1代表根据QPS来进行流量控制
count:限流阈值
strategy:流控模式,调用关系限流策略(0-直连,1-关联,2-链路)
controlBehavior:流量控制效果(0-快速失败、1-Warm Up、2-排队等待)
clusterMode:是否为集群模式
更详细的配置参数参考官网:https://github.com/alibaba/Sentinel/wiki/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8

2 在项目中引入依赖

<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> <version>1.8.0</version> </dependency>

3 在配置文件中配置nacos作为持久化工具

spring.cloud.sentinel.datasource 配置多数据源。Map类型
ds1 自定义名称,随意的。
nacos 使用的持久化工具。支持:file、zk、apollo、nacos
server-addr: ip及端口
data-id : 新建分布式配置文件的data id
group-id: 分组名
data-type: 配置文件类型。
rule-type: 持久化工具支持的类型。nacos取值为flow。其他取值:degrade、authority、system、param-flow、gw-flow、gw-api-flow。

spring:
cloud:
sentinel:
transport:
port: 8719
dashboard: 192.168.8.128:8858
datasource:
ds1:
nacos:
server-addr: 192.168.8.128:8848
data-id: zidingyimingcheng group-id: DEFAULT_GROUP
data-type: json
rule-type: flow