(一)、sentinel介绍
1、sentinel是什么?
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式服务架构的流量控制组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定性。 源码地址:https://github.com/alibaba/Sentinel 官方文档:https://github.com/alibaba/Sentinel/wiki
2、Sentinel具有以下特征:
丰富的应用场景: Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、实时熔断下游不可用应用等。 完备的实时监控: Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。 广泛的开源生态: Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。 完善的 SPI 扩展点: Sentinel 提供简单易用、完善的 SPI 扩展点。您可以通过实现扩展点,快速的定制逻辑。例如定制规则管理、适配数据源等。 阿里云提供了 企业级的 Sentinel 服务,应用高可用服务 AHAS
Sentinel和Hystrix对比
3、sentinel能解决什么问题
【大流量请求】:在秒杀和大促开始前,如果准备不充分,瞬间大量请求会造成服务提供者的不可用。 【硬件故障】:可能为硬件损坏造成的服务器主机宕机, 网络硬件故障造成的服务提供者的不可访问。 【缓存击穿】:一般发生在缓存应用重启, 缓存失效时高并发,所有缓存被清空时,以及短时间内大量缓存失效时。大量的缓存不命中, 使请求直击后端,造成服务提供者超负荷运行,引起服务不可用。
在服务提供者不可用的时候,会出现大量重试的情况:用户重试、代码逻辑重试,这些重试最终导致:进一步加大请求流量。所以归根结底导致雪崩效应的最根本原因是:大量请求线程同步等待造成的资源耗尽。当服务调用者使用同步调用时, 会产生大量的等待线程占用系统资源。一旦线程资源被耗尽,服务调用者提供的服务也将处于不可用状态, 于是服务雪崩效应产生了。
服务雪崩效应:因服务提供者的不可用导致服务调用者的不可用,并将不可用逐渐放大的过程,就叫服务雪崩效应
4、重要概念
资源 资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。在接下来的文档中,我们都会用资源来描述代码块。 只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。
规则 围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。
工作主流程 在 Sentinel 里面,所有的资源都对应一个资源名称(resourceName),每次资源调用都会创建一个 Entry 对象。Entry 可以通过对主流框架的适配自动创建,也可以通过注解的方式或调用 SphU API 显式创建。Entry 创建的时候,同时也会创建一系列功能插槽(slot chain),这些插槽有不同的职责,例如: NodeSelectorSlot 负责收集资源的路径,并将这些资源的调用路径,以树状结构存储起来,用于根据调用路径来限流降级; ClusterBuilderSlot 则用于存储资源的统计信息以及调用者信息,例如该资源的 RT, QPS, thread count 等等,这些信息将用作为多维度限流,降级的依据; StatisticSlot 则用于记录、统计不同纬度的 runtime 指标监控信息; FlowSlot 则用于根据预设的限流规则以及前面 slot 统计的状态,来进行流量控制; AuthoritySlot 则根据配置的黑白名单和调用来源信息,来做黑白名单控制; DegradeSlot 则通过统计信息以及预设的规则,来做熔断降级; SystemSlot 则通过系统的状态,例如 load1 等,来控制总的入口流量;
详细的介绍请参考sentinel官方文档:sentinel中文文档
(二)、sentinel的使用
一、定义资源和规则
1、引入依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>${sentinel.versioin}</version>
</dependency>
2、定义规则 规则的种类:Sentinel 支持以下几种规则:流量控制规则、熔断降级规则、系统保护规则、来源访问控制规则 和 热点参数规则。 以流控规则为例,在资源保护前先定义好流控规则,所以使用到 @PostConstruct注解,在该bean对象实例化之前将定义的流控规则加载完成。
@PostConstruct
public static void initFlowRules() {
List<FlowRule> flowRules = new ArrayList<>();
FlowRule flowRule = new FlowRule();
flowRule.setResource(RESOURCE_NAME);
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
flowRule.setCount(1);
flowRules.add(flowRule);
FlowRuleManager.loadRules(flowRules);
}
3、编写资源保护的代码
@RestController
@Slf4j
public class HelloController {
private static final String RESOURCE_NAME = "hello";
@RequestMapping(value = "/hello")
public String hello() {
Entry entry = null;
try {
entry = SphU.entry(RESOURCE_NAME);
String str = "hello world";
log.info("====="+str);
return str;
} catch (BlockException ex) {
log.info("block!");
} catch (Exception ex) {
Tracer.traceEntry(ex, entry);
} finally {
if (entry != null) {
entry.exit();
}
}
return null;
}
@PostConstruct
public static void initFlowRules() {
List<FlowRule> flowRules = new ArrayList<>();
FlowRule flowRule = new FlowRule();
flowRule.setResource(RESOURCE_NAME);
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
flowRule.setCount(1);
flowRules.add(flowRule);
FlowRuleManager.loadRules(flowRules);
}
}
资源保护的核心代码块:
try (Entry entry = SphU.entry("resourceName")) {
} catch (BlockException ex) {
}
测试效果: 其他规则定义和资源保护的详细介绍可以参考官方文档:如何使用
以上方式定义资源的缺点很明显
- 业务侵入性很强,定义资源保护需要在controller中写入非业务代码.
- 规则配置不灵活,若需要添加新的保护规则,还需要手动添加
二、@SentinelResource注解+Sentinel dashboard控制台
Sentinel 支持通过 @SentinelResource 注解定义资源并配置 blockHandler 和 fallback 函数来进行限流之后的处理。 同时支持通过Sentinel控制台定义规则,可以简化开发。
@SentinelResource 注解用来标识资源是否被限流、降级。
1、使用该注解需要引入依赖:
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
<version>1.8.0</version>
</dependency>
如果是spring项目需要配置切面支持(springboot项目会自动配置,不用关注)
@Configuration
public class SentinelAspectConfiguration {
@Bean
public SentinelResourceAspect sentinelResourceAspect() {
return new SentinelResourceAspect();
}
}
2、使用@SentinelResource定义资源
@SentinelResource(value = "findOrderByUserId",
blockHandler = "handleException",
fallback = "fallback"
)
@RequestMapping(value = "/user/findOrderByUserId/{id}")
public User findOrderByUserId(@PathVariable("id") Integer id) {
throw new RuntimeException("getUserById command failed");
}
public User handleException(@PathVariable("id") Integer id, BlockException ex) {
return new User("admin");
}
public User fallback(@PathVariable("id") Integer id, Throwable e) {
return new User("admin1");
}
使用@SentinelResource需要注意: 配置了@SentinelResource注解的方法都视作资源,可以配置在@RequestMapping("/user/findOrderByUserId/{id}")修饰的接口层,也可以配置在service层,如果配置在了接口上,则sentinel会产生两套资源链路,一个是@RequestMapping中的value属性的"/user/findOrderByUserId/{id}"链路,一个是@SentinelResource(“findOrderByUserId”)配置的"findOrderByUserId"链路 (1)如果这两个链路都配置了规则的话,默认会先执行接口产生的链路; (2)如果没有为接口配置规则,就会执行@SentinelResource的资源链路。
3、编写ExceptionUtil,注意如果指定了fallback函数或者blockHandler的class类,该类中的方法必须是static方法
public class ExceptionUtil {
public static R handleException(Integer id, BlockException e){
log.error("===被限流啦===");
return new User("admin");
}
public static fallback(Integer id,Throwable e){
log.error("===被异常降级啦===");
return new User("admin1");
}
}
4、客户端接入Sentinel dashboard控制台
- 客户端需要引入 Transport 模块来与 Sentinel 控制台进行通信。
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>1.8.0</version>
</dependency>
启动时加入 JVM 参数 -Dcsp.sentinel.dashboard.server=consoleIp:port 指定控制台地址和端口。若启动多个应用,则需要通过 -Dcsp.sentinel.api.port=xxxx 指定客户端监控 API 的端口(默认是 8719)。 除了修改 JVM 参数,也可以通过配置文件取得同样的效果。更详细的信息可以参考 启动配置项。
- 启动 Sentinel 控制台
您可以从 release 页面 下载最新版本的控制台 jar 包。 下载控制台 jar 包并在本地启动:可以参见 此处文档
java -jar sentinel-dashboard-1.8.0.jar
用户可以通过如下参数进行配置: -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 会在客户端首次调用的时候进行初始化,开始向控制台发送心跳包,所以要确保客户端有访问量;
三、Spring Cloud Alibaba整合Sentinel
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.添加yml配置,为微服务设置sentinel控制台地址 添加Sentinel后,需要暴露/actuator/sentinel端点,而Springboot默认是没有暴露该端点的,所以需要设置,测试http://localhost:8800/actuator/sentinel
server:
port: 8800
spring:
application:
name: sentinel-demo
cloud:
sentinel:
transport:
dashboard: 127.0.0.1:8080
management:
endpoints:
web:
exposure:
include: '*'
3.在sentinel控制台中设置流控规则 资源名: 接口的API 针对来源: 默认是default,当多个微服务都调用这个资源时,可以配置微服务名来对指定的微服务设置阈值 阈值类型: 分为QPS和线程数 假设阈值为10 QPS类型: 只得是每秒访问接口的次数>10就进行限流 线程数: 为接受请求该资源分配的线程数>10就进行限流 测试: 因为QPS是1,所以1秒内多次访问会出现如下情形: 微服务和Sentinel Dashboard通信原理 Sentinel控制台与微服务端之间,实现了一套服务发现机制,集成了Sentinel的微服务都会将元数据传递给Sentinel控制台,架构图如下所示:
|