1. 引入Sentinel依赖,在pom.xml中引入
代码语言:javascript复制<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.6.0</version>
</dependency>
2. 定义资源
资源 是Sentinel中的核心概念之一。在java中的资源一般是接口方法。例如,把需要控制流量的代码用 Sentinel API SphU.entry("HelloWorld") 和 entry.exit() 包围起来即可。在下面的例子中,我们将 System.out.println("hello world"); 作为资源(被保护的逻辑),用 API 包装起来。参考代码如下:
代码语言:javascript复制public static void main(String[] args) {
// 配置规则.
initFlowRules();
while (true) {
// 1.5.0 版本开始可以直接利用 try-with-resources 特性
try (Entry entry = SphU.entry("HelloWorld")) {
// 被保护的逻辑
System.out.println("hello world");
} catch (BlockException ex) {
// 处理被流控的逻辑
System.out.println("blocked!");
}
}
}
也可以使用Sentinel提供的注解来定义资源,它是配合着aop或者aspectJ来使用的:
代码语言:javascript复制@SentinelResource("HelloWorld")
public void helloWorld() {
// 资源中的逻辑
System.out.println("hello world");
}
也可以使用SphU.asyncEntry(xxx)异步调用资源。 上面的方式都可以定义资源。
3. 定义规则
规则主要有流控规则、降级规则、系统规则、权限规则、热点参数规则等:
代码语言:javascript复制FlowRuleManager.loadRules(List<FlowRule> rules); // 修改流控规则
DegradeRuleManager.loadRules(List<DegradeRule> rules); // 修改降级规则
SystemRuleManager.loadRules(List<SystemRule> rules); // 修改系统规则
AuthorityRuleManager.loadRules(List<AuthorityRule> rules); // 修改授权规则
1. 流控规则
通过流控规则来指定允许该资源通过的请求次数,例如下面的代码定义了资源 HelloWorld 每秒最多只能通过 20 个请求。
代码语言:javascript复制private static void initFlowRules(){
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setResource("HelloWorld");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// Set limit QPS to 20.
rule.setCount(20);
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
详情参考:流量控制 1
2. 熔断降级规则
熔断降级规则包含下面几个重要的属性: resource 资源名,即限流规则的作用对象 count 阈值 grade 降级模式,根据 RT 降级还是根据异常比例降级 RT timeWindow 降级的时间,单位为 s 同一个资源可以同时有多个降级规则。 理解上面规则的定义之后,我们可以通过调用 DegradeRuleManager.loadRules() 方法来用硬编码的方式定义流量控制规则。
代码语言:javascript复制private void initDegradeRule() {
List<DegradeRule> rules = new ArrayList<>();
DegradeRule rule = new DegradeRule();
rule.setResource(KEY);
// set threshold RT, 10 ms
rule.setCount(10);
rule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
rule.setTimeWindow(10);
rules.add(rule);
DegradeRuleManager.loadRules(rules);
}
我们通常用以下几种方式来衡量资源是否处于稳定的状态:
- 平均响应时间 (DEGRADE_GRADE_RT):当资源的平均响应时间超过阈值(DegradeRule 中的 count,以 ms 为单位)之后,资源进入准降级状态。如果接下来 1s 内持续进入 5 个请求(即 QPS >= 5),它们的 RT 都持续超过这个阈值,那么在接下的时间窗口(DegradeRule 中的 timeWindow,以 s 为单位)之内,对这个方法的调用都会自动地熔断(抛出 DegradeException)。注意 Sentinel 默认统计的 RT 上限是 4900 ms,超出此阈值的都会算作 4900 ms,若需要变更此上限可以通过启动配置项 -Dcsp.sentinel.statistic.max.rt=xxx 来配置。
- 异常比例 (DEGRADE_GRADE_EXCEPTION_RATIO):当资源的每秒异常总数占通过量的比值超过阈值(DegradeRule 中的 count)之后,资源进入降级状态,即在接下的时间窗口(DegradeRule 中的 timeWindow,以 s 为单位)之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
- 异常数 (DEGRADE_GRADE_EXCEPTION_COUNT):当资源近 1 分钟的异常数目超过阈值之后会进行熔断。注意由于统计时间窗口是分钟级别的,若 timeWindow 小于 60s,则结束熔断状态后仍可能再进入熔断状态。 详情参考:熔断降级 2
3. 系统保护规则 (SystemRule)
参数说明:
- highestSystemLoad 最大的 load1,参考值 -1 (不生效)
- avgRt 所有入口流量的平均响应时间 -1 (不生效)
- maxThread 入口流量的最大并发数 -1 (不生效)
- qps 所有入口资源的 QPS -1 (不生效)
硬编码的方式定义流量控制规则如下:
代码语言:javascript复制private void initSystemRule() {
List<SystemRule> rules = new ArrayList<>();
SystemRule rule = new SystemRule();
rule.setHighestSystemLoad(10);
rules.add(rule);
SystemRuleManager.loadRules(rules);
}
系统保护规则是从应用级别的入口流量进行控制,从单台机器的总体 Load、RT、入口 QPS 和线程数四个维度监控应用数据,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(EntryType.IN),比如 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量。
系统规则支持四种阈值类型:
- Load(仅对 Linux/Unix-like 机器生效):当系统 load1 超过阈值,且系统当前的并发线程数超过系统容量时才会触发系统保护。系统容量由系统的 maxQps * minRt 计算得出。设定参考值一般是 CPU cores * 2.5。
- RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
- 线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
- 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。
详情参考:系统自适应保护 3
4. 访问控制规则 (AuthorityRule)
很多时候,我们需要根据调用方来限制资源是否通过,这时候可以使用 Sentinel 的访问控制(黑白名单)的功能。黑白名单根据资源的请求来源(origin)限制资源是否通过,若配置白名单则只有请求来源位于白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。
调用方信息通过 ContextUtil.enter(resourceName, origin) 方法中的 origin 参数传入。
授权规则,即黑白名单规则(AuthorityRule)非常简单,主要有以下配置项:
- resource:资源名,即限流规则的作用对象
- limitApp:对应的黑名单/白名单,不同 origin 用 , 分隔,如 appA,appB
- strategy:限制模式,AUTHORITY_WHITE 为白名单模式,AUTHORITY_BLACK 为黑名单模式,默认为白名单模式 比如我们希望控制对资源 test 的访问设置白名单,只有来源为 appA 和 appB 的请求才可通过,则可以配置如下白名单规则:
AuthorityRule rule = new AuthorityRule();
rule.setResource("test");
rule.setStrategy(RuleConstant.AUTHORITY_WHITE);
rule.setLimitApp("appA,appB");
AuthorityRuleManager.loadRules(Collections.singletonList(rule));
详细信息参考:黑白名单控制 4
5. 热点规则 (ParamFlowRule)
何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:
- 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
- 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制 热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。 使用该规则需要引入依赖:
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-parameter-flow-control</artifactId>
<version>x.y.z</version>
</dependency>
热点参数规则(ParamFlowRule)类似于流量控制规则(FlowRule):
- resource 资源名,必填
- count 限流阈值,必填
- grade 限流模式 QPS 模式
- paramIdx 热点参数的索引,必填,对应 SphU.entry(xxx, args) 中的参数索引位置
- paramFlowItemList 参数例外项,可以针对指定的参数值单独设置限流阈值,不受前面 count 阈值的限制。仅支持基本类型
可以通过 ParamFlowRuleManager 的 loadRules 方法更新热点参数规则,下面是一个示例:
代码语言:javascript复制ParamFlowRule rule = new ParamFlowRule(resourceName)
.setParamIdx(0)
.setCount(5);
// 针对 int 类型的参数 PARAM_B,单独设置限流 QPS 阈值为 10,而不是全局的阈值 5.
ParamFlowItem item = new ParamFlowItem().setObject(String.valueOf(PARAM_B))
.setClassType(int.class.getName())
.setCount(10);
rule.setParamFlowItemList(Collections.singletonList(item));
ParamFlowRuleManager.loadRules(Collections.singletonList(rule));
详情参考:热点参数限流 5
4. 控制台工具
- 下载控制台 jar 包并在本地启动:可以参见 此处文档 6
- 客户端接入需要在pom中引入如下依赖:
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>1.6.0</version>
</dependency>
- 启动时加入 JVM 参数 -Dcsp.sentinel.dashboard.server=consoleIp:port 指定控制台地址和端口。更多的参数参见启动参数文档 7
- 确保应用端有访问量
在控制台上可以看到资源的实时流控数据,可以进行规则配置推送等。 控制台详情可参考:控制台启动及配置 8
5. 规则管理及推送
Sentinel 控制台同时提供简单的规则管理以及推送的功能。规则推送分为 3 种模式,包括 "原始模式"、"Pull 模式" 和"Push 模式"。
- 原始模式即在控制台直接页面上配置,仅在内存生效,重启后规则会丢失。
- pull模式数据源一般为本地文件、RDBMS等,一般是可写入的。使用时需要在客户端注册数据源:将对应的读数据源注册至对应的 RuleManager,将写数据源注册至 transport 的 WritableDataSourceRegistry 中。以本地文件数据源为例:
public class FileDataSourceInit implements InitFunc {
@Override
public void init() throws Exception {
String flowRulePath = "xxx";
ReadableDataSource<String, List<FlowRule>> ds = new FileRefreshableDataSource<>(
flowRulePath, source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {})
);
// 将可读数据源注册至 FlowRuleManager.
FlowRuleManager.register2Property(ds.getProperty());
WritableDataSource<List<FlowRule>> wds = new FileWritableDataSource<>(flowRulePath, this::encodeJson);
// 将可写数据源注册至 transport 模块的 WritableDataSourceRegistry 中.
// 这样收到控制台推送的规则时,Sentinel 会先更新到内存,然后将规则写入到文件中.
WritableDataSourceRegistry.registerFlowDataSource(wds);
}
private <T> String encodeJson(T t) {
return JSON.toJSONString(t);
}
}
会定时轮询文件的变更,读取规则。好处是简单,不引入新的依赖,坏处是无法保证监控数据的一致性。首先 Sentinel 控制台通过 API 将规则推送至客户端并更新到内存中,接着注册的写数据源会将新的规则保存到本地的文件中。使用 pull 模式的数据源时一般不需要对 Sentinel 控制台进行改造。
- 在生产环境推荐使用push模式,对于 push 模式的数据源,如远程配置中心(ZooKeeper, Nacos, Apollo等等),推送的操作不应由 Sentinel 客户端进行,而应该经控制台统一进行管理,直接进行推送,数据源仅负责获取配置中心推送的配置并更新到本地。因此推送规则正确做法应该是 配置中心控制台/Sentinel 控制台 → 配置中心 → Sentinel 数据源 → Sentinel,而不是经 Sentinel 数据源推送至配置中心。可参考:在生产环境上使用 9
6. 其他功能
Sentinel还提供了集群流控、网关流控、实时监控、动态规则、主流框架适配(与servlet、dubbo、springcloud、grpc)和多语言生态等功能,具体详情见官方wiki,官方wiki地址 10
7. 生产环境注意事项
- 启动sentinel core时需要注意的事项参见:启动配置项 11 需要设置project.name与控制台的ip和端口等;
- 规则配置部分,参见:生产环境上使用方法 12
[1]: https://github.com/alibaba/Sentinel/wiki/流量控制
[2]: https://github.com/alibaba/Sentinel/wiki/熔断降级
[3]: https://github.com/alibaba/Sentinel/wiki/系统自适应限流
[4]: https://github.com/alibaba/Sentinel/wiki/黑白名单控制
[5]: https://github.com/alibaba/Sentinel/wiki/热点参数限流
[6]: https://github.com/alibaba/Sentinel/wiki/控制台#2-启动控制台
[7]: https://github.com/alibaba/Sentinel/wiki/控制台#32-配置启动参数
[8]: https://github.com/alibaba/Sentinel/wiki/控制台#2-启动控制台
[9]: https://github.com/alibaba/Sentinel/wiki/在生产环境中使用-Sentinel
[10]: https://github.com/alibaba/Sentinel/wiki
[11]: https://github.com/alibaba/Sentinel/wiki/启动配置项
[12]: https://github.com/alibaba/Sentinel/wiki/在生产环境中使用-Sentinel