Sentinel
分布式系统的流量防卫兵
Sentinel 基本概念
资源
资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。在接下来的文档中,我们都会用资源来描述代码块。
只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。
规则
围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。
Sentinel 功能和设计理念
流量控制
熔断降级
系统负载保护
快速入门
1.引入 jar 包
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.8.1</version>
</dependency>
2.定义资源、添加规则
public static void main(String[] args) {
// 配置规则.
initFlowRules();
while (true) {
try (Entry entry = SphU.entry("resourceName")) {
// 被保护的逻辑
System.out.println("hello world");
} catch (BlockException ex) {
// 处理被流控的逻辑
System.out.println("blocked!");
}
}
private static void initFlowRules(){
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setResource("resourceName");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// Set limit QPS to 20.
rule.setCount(20);
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
}
3.检查效果
Demo 运行之后,我们可以在日志 ~/logs/csp/${appName}-metrics.log.xxx 里看到下面的输出:
|--timestamp-|------date time----|--resource-|p |block|s |e|rt
1529998904000|2018-06-26 15:41:44|hello world|20|0 |20|0|0
1529998905000|2018-06-26 15:41:45|hello world|20|5579 |20|0|728
1529998906000|2018-06-26 15:41:46|hello world|20|15698|20|0|0
1529998907000|2018-06-26 15:41:47|hello world|20|19262|20|0|0
1529998908000|2018-06-26 15:41:48|hello world|20|19502|20|0|0
1529998909000|2018-06-26 15:41:49|hello world|20|18386|20|0|0
其中 p 代表通过的请求, block 代表被阻止的请求, s 代表成功执行完成的请求个数, e 代表用户自定义的异常, rt 代表平均响应时长。
4.启动 Sentinel 控制台
4-1.下载 Sentinel 控制台项目
4-2.引入 Transport 模块
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>1.8.1</version>
</dependency>
4-3.启动时加入 JVM 参数 -Dcsp.sentinel.dashboard.server=consoleIp:port 指定控制台地址和端口
4-4.确保应用端有访问量
完成以上步骤后即可在 Sentinel 控制台上看到对应的应用
启动配置项
用户可以通过 -Dcsp.sentinel.config.file 参数配置 properties 文件的路径,支持 classpath 路径配置(如 classpath:sentinel.properties)。默认 Sentinel 会尝试从 classpath:sentinel.properties 文件读取配置,读取编码默认为 UTF-8。
若应用为 Spring Boot 或 Spring Cloud 应用,您可以使用 Spring Cloud Alibaba,通过 Spring 配置文件来指定配置。
流量控制
限流的直接表现是在执行 Entry nodeA = SphU.entry(资源名字)
的时候抛出 FlowException
异常。FlowException
是 BlockException
的子类,您可以捕捉 BlockException
来自定义被限流之后的处理逻辑。
同一个资源可以对应多条限流规则。FlowSlot
会对该资源的所有限流规则依次遍历,直到有规则触发限流或者所有规则遍历完毕。
一条限流规则主要由下面几个因素组成,我们可以组合这些元素来实现不同的限流效果:
resource
:资源名,即限流规则的作用对象count
: 限流阈值grade
: 限流阈值类型,QPS 或线程数strategy
: 根据调用关系选择策略
并发线程数流量控制
Sentinel线程数限流不负责创建和管理线程池,而是简单统计当前请求上下文的线程个数,如果超出阈值,新的请求会被立即拒绝。
QPS流量控制
- 直接拒绝(RuleConstant.CONTROL_BEHAVIOR_DEFAULT)方式
- 冷启动(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式
- 匀速器(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)方式(适合用于 MQ 的消费者)
基于调用关系的流量控制
- 根据调用方限流
- 根据调用链路入口限流:链路限流
- 具有关系的资源流量控制:关联流量控制
熔断降级
除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。一个服务常常会调用别的模块,可能是另外的一个远程服务、数据库,或者第三方 API 等。例如,支付的时候,可能需要远程调用银联提供的 API;查询某个商品的价格,可能需要进行数据库查询。然而,这个被依赖服务的稳定性是不能保证的。如果依赖的服务出现了不稳定的情况,请求的响应时间变长,那么调用服务的方法的响应时间也会变长,线程会产生堆积,最终可能耗尽业务自身的线程池,服务本身也变得不可用。
熔断策略
- 慢调用比例 (SLOW_REQUEST_RATIO)
- 异常比例 (ERROR_RATIO)
- 异常数 (ERROR_COUNT)
注意异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常(BlockException)不生效。为了统计异常比例或异常数,需要通过 Tracer.trace(ex) 记录业务异常。
Entry entry = null;
try {
entry = SphU.entry(key, EntryType.IN, key);
// Write your biz code here.
// <<BIZ CODE>>
} catch (Throwable t) {
if (!BlockException.isBlockException(t)) {
Tracer.trace(t);
}
} finally {
if (entry != null) {
entry.exit();
}
}
开源整合模块,如 Sentinel Dubbo Adapter, Sentinel Web Servlet Filter 或 @SentinelResource 注解会自动统计业务异常,无需手动调用。
熔断器事件监听
Sentinel 支持注册自定义的事件监听器监听熔断器状态变换事件(state change event)。示例:
EventObserverRegistry.getInstance().addStateChangeObserver("logging",
(prevState, newState, rule, snapshotValue) -> {
if (newState == State.OPEN) {
// 变换至 OPEN state 时会携带触发时的值
System.err.println(String.format("%s -> OPEN at %d, snapshotValue=%.2f", prevState.name(),
TimeUtil.currentTimeMillis(), snapshotValue));
} else {
System.err.println(String.format("%s -> %s at %d", prevState.name(), newState.name(),
TimeUtil.currentTimeMillis()));
}
});
系统自适应保护
Sentinel 系统自适应保护从整体维度对应用入口流量进行控制,结合应用的 Load、总体平均 RT、入口 QPS 和线程数等几个维度的监控指标,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
- Load(仅对 Linux/Unix-like 机器生效):当系统 load1 超过阈值,且系统当前的并发线程数超过系统容量时才会触发系统保护。系统容量由系统的
maxQps * minRt
计算得出。设定参考值一般是CPU cores * 2.5
。 - CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0)。
- RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
- 线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
- 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。
集群流量控制
网管流量控制
热点参数限流
来源访问控制
注解埋点支持
Sentinel 提供了 @SentinelResource 注解用于定义资源,并提供了 AspectJ 的扩展用于自动定义资源、处理 BlockException 等
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
<version>x.y.z</version>
</dependency>
@SentinelResource 注解
- 注意:注解方式埋点不支持 private 方法。
配置
AspectJ
若您的应用直接使用了 AspectJ,那么您需要在 aop.xml
文件中引入对应的 Aspect:
<aspects>
<aspect name="com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect"/>
</aspects>
Spring AOP
若您的应用使用了 Spring AOP,您需要通过配置的方式将 SentinelResourceAspect
注册为一个 Spring Bean:
@Configuration
publicclassSentinelAspectConfiguration {
@Beanpublic SentinelResourceAspectsentinelResourceAspect() {
returnnew SentinelResourceAspect();
}
}
动态规则扩展
Sentinel 的理念是开发者只需要关注资源的定义,当资源定义成功后可以动态增加各种流控降级规则。Sentinel 提供两种方式修改规则:
- 通过 API 直接修改 (
loadRules
) - 通过
DataSource
适配不同数据源修改
DataSource 扩展
上述 loadRules() 方法只接受内存态的规则对象,但更多时候规则存储在文件、数据库或者配置中心当中。DataSource 接口给我们提供了对接任意配置源的能力。相比直接通过 API 修改规则,实现 DataSource 接口是更加可靠的做法。
DataSource
扩展常见的实现方式有:
- 拉模式:客户端主动向某个规则管理中心定期轮询拉取规则,这个规则中心可以是 RDBMS、文件,甚至是 VCS 等。这样做的方式是简单,缺点是无法及时获取变更;
- 推模式:规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 Nacos、Zookeeper 等配置中心。这种方式有更好的实时性和一致性保证。
日志
拦截详情日志(block 日志)
无论触发了限流、熔断降级还是系统保护,它们的秒级拦截详情日志都在 ${user_home}/logs/csp/sentinel-block.log
里。如果没有发生拦截,则该日志不会出现。日志格式如下:
2014-06-20 16:35:10|1|sayHello(java.lang.String,long),FlowException,default,origin|61,0
2014-06-20 16:35:11|1|sayHello(java.lang.String,long),FlowException,default,origin|1,0
秒级监控日志
所有的资源都会产生秒级日志,它在 ${user_home}/logs/csp/${app_name}-${pid}-metrics.log
里。格式如下:
1532415661000|2018-07-24 15:01:01|sayHello(java.lang.String)|12|3|4|2|295
业务日志
其它的日志在 ${user_home}/logs/csp/sentinel-record.log.xxx 里。该日志包含规则的推送、接收、处理等记录,排查问题的时候会非常有帮助。
实时监控
Sentinel 提供对所有资源的实时监控。如果需要实时监控,客户端需引入以下依赖(以 Maven 为例):
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>x.y.z</version>
</dependency>
引入上述依赖后,客户端便会主动连接 Sentinel 控制台。通过 Sentinel 控制台 即可查看客户端的实时监控。
启动配置项
配置方式
Sentinel 提供如下的配置方式:
- JVM -D 参数方式
- properties 文件方式(1.7.0 版本开始支持)
用户可以通过 -Dcsp.sentinel.config.file 参数配置 properties 文件的路径,支持 classpath 路径配置(如 classpath:sentinel.properties)。默认 Sentinel 会尝试从 classpath:sentinel.properties 文件读取配置,读取编码默认为 UTF-8。
若您的应用为 Spring Boot 或 Spring Cloud 应用,您可以使用 Spring Cloud Alibaba,通过 Spring 配置文件来指定配置。