Sentinel
# 1 Sentinel 是什么?
Sentinel 是面向分布式服务架构的流量控制组件,主要以 流量
为切入点,从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定性。
Sentinel具有以下特征:
- 丰富的应用场景 : Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、实时熔断下游不可用应用等。
- 完备的实时监控 : Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
- 广泛的开源生态 : Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
- 完善的 SPI 扩展点 : Sentinel 提供简单易用、完善的 SPI 扩展点。您可以通过实现扩展点,快速的定制逻辑。
# 1.1 基本概念
资源
资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用 的其它应用提供的服务,甚至可以是一段代码。 只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL, 甚至服务名称作为资源名来标示资源。
规则
围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。
# 1.2 工作主流程
在 Sentinel 里面,所有的资源都对应一个资源名称(resourceName),每次资源调用都会创建一个 Entry 对象。Entry 可以通过对主流框架的适配自动创建,也可以通过注解的方式或调用 SphU API 显式创建。Entry 创建的时候,同时也会创建一 系列功能插槽(slot chain),这些插槽有不同的职责,例如:
NodeSelectorSlot
负责收集资源的路径,并将这些资源的调用路径,以树状结构存储起来,用于根据调用路径来限流降级;ClusterBuilderSlot
则用于存储资源的统计信息以及调用者信息,例如该资源的 RT, QPS, thread count 等等,这 些信息将用作为多维度限流,降级的依据;StatisticSlot
则用于记录、统计不同纬度的 runtime 指标监控信息;FlowSlot
则用于根据预设的限流规则以及前面 slot 统计的状态,来进行流量控制;AuthoritySlot
则根据配置的黑白名单和调用来源信息,来做黑白名单控制;DegradeSlot
则通过统计信息以及预设的规则,来做熔断降级;SystemSlot
则通过系统的状态,例如 load1 等,来控制总的入口流量;
# 1.3 Sentinel对比Hystrix
# 2 Sentinel 快速开始
@SentinelResource注解实现
@SentinelResource注解用来标识资源是否被限流、降级。
- blockHandler : 定义当资源内部发生了BlockException应该进入的方法(捕获的是Sentinel定义的异常)。
- fallback : 定义的是资源内部发生了Throwable应该进入的方法。
- exceptionsTolgnore : 配置fallback可以忽略的异常。
# 2.1 引入依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel‐annotation‐aspectj</artifactId>
<version>1.8.0</version>
</dependency>
2
3
4
5
# 2.2 配置切面支持
@Configuration
public class SentinelAspectConfiguration {
@Bean
public SentinelResourceAspect sentinelResourceAspect() {
return new SentinelResourceAspect();
}
}
2
3
4
5
6
7
# 2.3 添加@SentinelResource
@RequestMapping(value = "/findOrderByUserId/{id}")
@SentinelResource(value = "findOrderByUserId",
fallback = "fallback",fallbackClass = ExceptionUtil.class,
blockHandler = "handleException",blockHandlerClass = ExceptionUtil.class
)
public R findOrderByUserId(@PathVariable("id") Integer id) {
//ribbon实现
String url = "http://mall-order/order/findOrderByUserId/"+id;
R result = restTemplate.getForObject(url,R.class);
if(id==4){
throw new IllegalArgumentException("非法参数异常");
}
return result;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 2.4 添加降级限流方法
public class ExceptionUtil {
public static R fallback(Integer id,Throwable e){
return R.error(-2,"===被异常降级啦===");
}
public static R handleException(Integer id, BlockException e){
return R.error(-2,"===被限流啦===");
}
}
2
3
4
5
6
7
8
9
10
# 2.5 客户端引包与控制台通信
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>1.8.0</version>
</dependency>
2
3
4
5
# 2.6 控制台启动
#启动控制台命令
java -jar sentinel-dashboard-1.8.0.jar
2
用户可以通过如下参数进行配置:
-Dsentinel.dashboard.auth.username=sentinel 用于指定控制台的登录用户名为 sentinel;
-Dsentinel.dashboard.auth.password=123456 用于指定控制台的登录密码为 123456;如果省略这两个参数,默认用户和密码均为 sentinel;
-Dserver.servlet.session.timeout=7200 用于指定 Spring Boot 服务端 session 的过期时间,如 7200 表示 7200 秒;60m 表示 60 分钟,默认为 30 分钟;
访问http://localhost:8080/#/login ,默认用户名密码: sentinel/sentinel
提示
Sentinel 会在客户端首次调用的时候进行初始化,开始向控制台发送心跳包,所以要确保客户端有访问量。
# 2.7 SpringCloud整合Sentinel
# 2.7.1 引入依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2
3
4
5
6
7
8
9
# 2.7.2 配置Sentinel控制台地址
server:
port: 8800
spring:
application:
name: mall-user-sentinel-demo
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
sentinel:
transport:
# 添加sentinel的控制台地址
dashboard: 127.0.0.1:8080
# 指定应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用的HttpServer
# port: 8719
#暴露actuator端点
management:
endpoints:
web:
exposure:
include: '*'
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 2.7.3 在Sentinel控制台中设置流控规则
资源名:接口API
针对来源:默认是default,当多个微服务都调用这个资源时,可以配置微服务名对指定的微服务设置阈值
阈值类型:分为QPS和线程数
假设阈值为10
- QPS类型:每秒访问接口的次数 > 10 就进行限流
- 线程数:为接收请求该资源分配的线程数 > 10 就进行限流
# 2.7.4 配置降级规则
提示
除流量控制外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。我们需要对不稳定的 弱依赖服务调用
进行熔断降级(熔断必然伴随着降级),暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩。 熔断降级作为保护自身的手段,通常在客户端(调用端)进行配置
。
熔断策略:慢调用比例、异常比例、异常数。
经过熔断时长后 熔断器会进入探测恢复状态(HALFOPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。
# 2.8 OpenFeign整合Sentinel
Sentinel 适配了 Feign 组件。如果想使用,除了引入 spring-cloud-starter-alibaba-sentinel 的依赖外还需要 2 个步骤:
配置文件打开 Sentinel 对 Feign 的支持:feign.sentinel.enabled=true
feign:
sentinel:
enabled: true
2
3
加入 spring-cloud-starter-openfeign 依赖使 Sentinel starter 中的自动化配置类生效
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2
3
4
在Feign的声明式接口上添加fallback属性
@FeignClient(value = "mall-order",path = "/order",fallback = FallbackOrderFeignServiceFactory.class)
public interface OrderFeignService {
@RequestMapping("/findOrderByUserId/{userId}")
public R findOrderByUserId(@PathVariable("userId") Integer userId);
}
2
3
4
5
6
7
@Component
public class FallbackOrderFeignServiceFactory implements FallbackFactory<OrderFeignService> {
@Override
public OrderFeignService create(Throwable throwable) {
return new OrderFeignService() {
@Override
public R findOrderByUserId(Integer userId) {
if (throwble instanceof FlowException) {
return R.error(100, "接口限流了");
}
return R.error(-1,"=======服务降级了========");
}
};
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
UserController
@Autowired
OrderFeignService orderFeignService;
@RequestMapping(value = "/findOrderByUserId/{id}")
public R findOrderByUserId(@PathVariable("id") Integer id) {
//feign调用
R result = orderFeignService.findOrderByUserId(id);
return result;
}
2
3
4
5
6
7
8
9