微服务实战 02 Sentinel 入门
这一节接着上一文了解一下 Sentinel 的使用
注意: SphU.entry(xxx) 需要与 entry.exit() 方法成对出现,匹配调用,否则会导致调用链记录异常,抛出 ErrorEntryFreeException 异常。 1.5.0 版本开始可以利用 try-with-resources 特性
// 1.5.0 版本开始可以利用 try-with-resources 特性
// 资源名可使用任意有业务语义的字符串,比如方法名、接口名或其它可唯一标识的字符串。
try (Entry entry = SphU.entry("resourceName")) {
// 被保护的业务逻辑
// do something here...
} catch (BlockException ex) {
// 资源访问阻止,被限流或被降级
// 在此处进行相应的处理操作
}
// 资源名可使用任意有业务语义的字符串
if (SphO.entry("自定义资源名")) {
// 务必保证finally会被执行
try {
/**
* 被保护的业务逻辑
*/
} finally {
SphO.exit();
}
} else {
// 资源访问阻止,被限流或被降级
// 进行相应的处理操作
}
// 原本的业务方法.
@SentinelResource(blockHandler = "blockHandlerForGetUser")
public User getUserById(String id) {
throw new RuntimeException("getUserById command failed");
}
// blockHandler 函数,原方法调用被限流/降级/系统保护的时候调用
public User blockHandlerForGetUser(String id, BlockException ex) {
return new User("admin");
}
SphU.asyncEntry(xxx) 不会影响当前(调用线程)的 Context,因此以下两个 entry 在调用链上是平级关系(处于同一层),而不是嵌套关系:
try {
AsyncEntry entry = SphU.asyncEntry(resourceName);
// 异步调用. // 异步回调
doAsync(userId, result -> {
try {
// 在此处处理异步调用的结果.
} finally {
// 在回调结束后 exit.
entry.exit();
}
});
} catch (BlockException ex) {
// Request blocked.
// Handle the exception (e.g. retry or fallback).
}
若在异步回调中需要嵌套其它的资源调用(无论是 entry 还是 asyncEntry),只需要借助 Sentinel 提供的上下文切换功能,在对应的地方通过 ContextUtil.runOnContext(context, f) 进行 Context 变换,将对应资源调用处的 Context 切换为生成的异步 Context,即可维持正确的调用链路关系。
public void handleResult(String result) {
Entry entry = null;
try {
entry = SphU.entry("handleResultForAsync");
// Handle your result here.
} catch (BlockException ex) {
// Blocked for the result handler.
} finally {
if (entry != null) {
entry.exit();
}
}
}
public void someAsync() {
try {
AsyncEntry entry = SphU.asyncEntry(resourceName);
// Asynchronous invocation.
doAsync(userId, result -> {
// 在异步回调中进行上下文变换,通过 AsyncEntry 的 getAsyncContext 方法获取异步 Context
ContextUtil.runOnContext(entry.getAsyncContext(), () -> {
try {
// 此处嵌套正常的资源调用.
handleResult(result);
} finally {
entry.exit();
}
});
});
} catch (BlockException ex) {
// Request blocked.
// Handle the exception (e.g. retry or fallback).
}
}
在控制台可以看到这样多的配置型项
以上的配置对应编程式的 FlowRule 类
可以采用硬编码定义流量控制规则
List<FlowRule> rules = new ArrayList<>();
FlowRule rule1 = new FlowRule();
rule1.setResource(resource); //设置资源
// Set max qps to 20
rule1.setCount(20); // 设置最大 QPS
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS); //限流阈值类型,QPS 或线程数模式
rule1.setLimitApp("default"); // 代表不区分调用来源
rules.add(rule1);
FlowRuleManager.loadRules(rules); // 加载规则
}
重要属性说明
Field | 说明 | 默认值 |
---|---|---|
resource | 资源名:限流规则的作用对象 | |
count | 限流阈值 | |
grade | 限流阈值类型,QPS 或线程数模式 | QPS 模式 |
limitApp | 流控针对的调用来源 | default,代表不区分调用来源 |
strategy | 调用关系限流策略:直接、链路、关联 | 根据资源本身(直接) |
controlBehavior | 流控效果(直接拒绝 / 排队等待 / 慢启动模式),不支持按调用关系限流 | 直接拒绝 |
调用关系爆破含调用房和被调用方,一个方法有可能会调用其他方法,形成一个调用链。所谓的调用关系流量策略,解释根据不同维度来触发流量控制
关联 和 链路 的区别
关联: 统计于当前资源相关的另一个资源,触发阈值时,对当前资源限流 也就是 当关联的资源达到阀值,就限流自己。
链路:统计从指定链路访问到本资源的请求,触发阈值时,对指定资源限流 也就是 当入口的资源达到阀值,就限流整个链路
熔断降级规则 对应DegradeRule类
重要属性说明
Field | 说明 | 默认值 |
---|---|---|
resource | 资源名,即规则的作用对象 | |
count | 慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值 | [0.0,1.0] |
grade | 熔断策略,支持慢调用比例/异常比例/异常数策略 | 慢调用比例 |
timeWindow | 熔断时长,单位为 s | |
minRequestAmount | 熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断 | 5 |
statIntervalMs | 统计时长(单位为 ms),如 60*1000 代表分钟级 | 1000 ms |
slowRatioThreshold | 慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入) |
Sentinel 提供了三种 熔断策略
熔断 和 限流最终结果都是让资源降级限制访问 , 熔断是以资源为判断条件,防止因资源发生异常导致调用者请求堆积或者异常,限流以调用者为条件,防止资源被过度调用导致资源的崩溃情况
Sentinel 系统自适应限流从整体维度对应用入口流量进行控制,结合应用的 Load、CPU 使用率、总体平均 RT、入口 QPS 和并发线程数等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
对应 SystemRule 类
Field | 说明 | 默认值 |
---|---|---|
highestSystemLoad | load1 触发值,用于触发自适应控制阶段 | -1 (不生效) |
avgRt | 所有入口流量的平均响应时间 | -1 (不生效) |
maxThread | 入口流量的最大并发数 | -1 (不生效) |
qps | 所有入口资源的 QPS | -1 (不生效) |
highestCpuUsage | 当前系统的 CPU 使用率(0.0-1.0) | -1 (不生效) |
很多时候,我们需要根据调用方来限制资源是否通过,这时候可以使用 Sentinel 的访问控制(黑白名单)的功能。黑白名单根据资源的请求来源(origin)限制资源是否通过,若配置白名单则只有请求来源位于白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。
授权规则,即黑白名单规则(AuthorityRule)非常简单,主要有以下配置项:
热点限流在以下场景使用较多
Sentinel核心分为三个部分