Sentinel是去年7月由阿里中间件团队开源的,面向分布式服务架构的轻量级高可用流量控制组件。
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
(引自官方文档)
之前大家熟知的容错组件Hystrix,在去年宣布停止开发,因此许多的开发人员在选型时将目光投向了Sentienl。这里将它们做一下对比:
Sentinel | Hystrix | |
---|---|---|
隔离策略 | 信号量隔离 | 线程池隔离/信号量隔离 |
熔断降级策略 | 基于响应时间或失败比率 | 基于失败比率 |
实时指标实现 | 滑动窗口 | 滑动窗口(基于 RxJava) |
规则配置 | 支持多种数据源 | 支持多种数据源 |
扩展性 | 多个扩展点 | 插件的形式 |
基于注解的支持 | 支持 | 支持 |
限流 | 基于 QPS,支持基于调用关系的限流 | 有限的支持 |
流量整形 | 支持慢启动、匀速器模式 | 不支持 |
系统负载保护 | 支持 | 不支持 |
控制台 | 开箱即用,可配置规则、查看秒级监控、机器发现等 | 不完善 |
常见框架的适配 | Servlet、Spring Cloud、Dubbo、gRPC 等 | Servlet、Spring Cloud Netflix |
在Sentinel中,Resource-资源 是最重要的一个概念,可以是代码块、方法、接口等任何需要保护的东西。在编码的时候,只需要考虑这个代码是否需要保护,如果需要保护,就将之定义为一个资源,然后定义规则就可以了,剩下的通通交给Sentinel来处理了。
Sentinel的工作流程就是围绕着一个个插槽所组成的插槽链来展开的。每个插槽都有自己的功能,通过一定的编排顺序,来达到最终的限流降级的目的。默认的各个插槽之间的顺序是固定的,因为有的插槽需要依赖其他的插槽计算出来的结果才能进行工作。
Context 代表调用链路上下文,贯穿一次调用链路中的所有 Entry
。Context 维护着当前调用链的元数据:入口节点、本次调用链路节点、调用来源等信息,通过 ThreadLocal 传递。
Entry是Sentinel中用来表示请求是否通过限流的一个凭证。每次执行 SphU.entry()
或 SphO.entry()
都会返回一个 Entry
给调用者。资源调用结束时需要 entry.exit()
。
Entry
包含了资源名、curNode(当前统计节点)、originNode(来源统计节点)等信息。
Sentinel中保存统计数据的对象:
StatisticNode
:最为基础的统计节点,包含秒级和分钟级两个滑动窗口结构。DefaultNode
:链路节点,用于统计调用链路上某个资源的数据,维持树状结构。ClusterNode
:簇节点,用于统计每个资源全局的数据(不区分调用链路),以及存放该资源的按来源区分的调用数据。EntranceNode
:入口节点,特殊的链路节点,对应某个 Context 入口的所有调用数据。<dependency>
<groupId>com.alibaba.cspgroupId>
<artifactId>sentinel-coreartifactId>
<version>1.7.1version>
dependency>
注意: 从 Sentinel 1.5.0 开始仅支持 JDK 1.7 或者以上版本。Sentinel 1.5.0 之前的版本最低支持 JDK 1.6。
Sentinel 在使用上提供了两种形式,一种是异常捕获形式,一种是布尔形式。也就是当限流被触发时,是抛出异常来还是返回一个 false:
Entry entry = null;
try {
entry = SphU.entry("myResource");
// 被保护的业务逻辑
} catch (BlockException e1) {
// 资源访问阻止,被限流或被降级
// 进行相应的处理操作
} finally {
if (entry != null) {
entry.exit();
}
}
if (SphO.entry("myResource")) {
try {
// 被保护的业务逻辑
} finally {
SphO.exit();
}
} else {
// 资源访问阻止,被限流或被降级
// 进行相应的处理操作
}
以上这两种方式都是通过硬编码的形式定义资源然后进行资源埋点的,对业务代码的侵入太大,sentinel从0.1.1版本开始加入了注解的支持,可以通过@SentinelResource
注解来定义资源。通过注解除了可以定义资源外,还可配置 blockHandler
和 fallback
方法来进行限流之后的处理。
@SentinelResource(value = "myResource")
public void test() {
System.out.println("Hello World!");
}
使用 Sentinel 需要我们提供限流规则
private void initRules() {
// 配置规则
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setResource("myResource"); // 限流规则的作用对象
// 配置规则:QPS不得超出10
rule.setCount(10);
rule.setGrade(RuleConstant.FLOW_GRADE_QPS); // 设置限流阈值类型为QPS模式
rule.setLimitApp("default"); // 针对的调用来源,default代表不区分来源
rules.add(rule);
// 加载规则
FlowRuleManager.loadRules(rules);
}
详细使用示例参见:sentinel-demo-basic
在上面的示例中,我们通过硬编码来对资源进行规则配置,而在实际项目中,规则应该需要支持动态配置,Sentinel官方提供了多种DataSource(规则源)用于动态配置规则,比如Nacos、Apollo、Zookeeper等。
DataSource
扩展常见的实现方式有:
<dependency>
<groupId>com.alibaba.cspgroupId>
<artifactId>sentinel-datasource-nacosartifactId>
<version>1.7.1version>
dependency>
创建 NacosDataSource
并将其注册至对应的 RuleManager 上即可。比如:
// remoteAddress 代表 Nacos 服务端的地址
// groupId 和 dataId 对应 Nacos 中相应配置
ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new NacosDataSource<>(remoteAddress, groupId, dataId,
source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {}));
FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
在Nacos控制界面相应groupId和dataId下的配置内容中,使用json格式填写配置内容:
[
{
"resource": "/myResource",
"limitApp": "default",
"grade": 1,
"count": 5,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
Nacos搭建及使用相关参见: Nacos整合SpringCloud实现配置管理和服务发现
详细示例参见: sentinel-demo-nacos-datasource
Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理、监控(单机和集群),规则管理和推送的功能。
从release页下载最新dashboard jar包:https://github.com/alibaba/Sentinel/releases
使用命令启动:
# 指定控制台端口为8080
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
<dependency>
<groupId>com.alibaba.cspgroupId>
<artifactId>sentinel-transport-simple-httpartifactId>
<version>1.7.1version>
dependency>
启动时加入 JVM 参数 -Dcsp.sentinel.dashboard.server=consoleIp:port
指定控制台地址和端口。
根据指定的控制台端口,访问http://localhost:8080/,即可打开管理页面,查看机器列表和监控信息: