👈👈👈 欢迎点赞收藏关注哟
首先分享之前的所有文章 >>>> 😜😜😜
文章合集 : 🎁 juejin.cn/post/694164...
Github : 👉 github.com/black-ant
CASE 备份 : 👉 gitee.com/antblack/ca...
一. 前言
之前也写过一篇 Sentinel 集成 , 那一篇不是很复杂,也只是针对本地拦截的一些基础原理,这些肯定是不够的。
这一篇就基于生产用法来看一下整个 Sentinel 的流程。并且来了解一下生产级的 Sentinel 有哪些关注点。
Sentinel 官方文档里面就很完善了,我尽量挑里面没有的说说 :
sentinelguard.io/zh-cn/docs/...
二. 宏观概念
2.1 基于应用
Sentinel 常见有2种形式 , 基于单机的手动配置模式和基于 Dashboard 的可视化配置模式 :
单机模式
依赖 :com.alibaba.csp:sentinel-core
java
public void test() throws InterruptedException {
// S1 : 初始化 Rule 规则
initFlowRules();
while (true) {
Entry entry = null;
try {
// S2 : 标注需要处理的 Resource 类型,和配置中的一一对应
entry = entry("HelloWorld");
System.out.println("OK.业务成功执行");
} catch (BlockException e1) {
System.out.println("ERROR.业务被阻塞!");
Thread.sleep(300);
} finally {
if (entry != null) {
entry.exit();
}
}
}
}
private static void initFlowRules() {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
// 定义 Rule 规则,这里基于 QPS ,每秒可以请求三次
rule.setResource("HelloWorld");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setCount(3);
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
- 在这套使用中我们可以进行扩展思考 :
- 单机模式关注面是当前 Pod 节点,
也就是说它没有上报的功能
- 单机场景下只需要在 initFlowRules 环节中通过 FlowRuleManager.loadRules 就可以开启限流
- 这类方式规则不能持久化,或者说现阶段好的持久化方式都需要定制
- 不具备图形界面,没有可观测性,不能实时调节
- 只需要引入一个小小的包就能实现自定义的拦截,相对其实很轻量级了
- 单机模式关注面是当前 Pod 节点,
单机-升级版
- 依赖 (在上述基础上): com.alibaba.csp:sentinel-annotation-aspectj
java
@Bean
public SentinelResourceAspect sentinelResourceAspect() {
return new SentinelResourceAspect();
}
@SentinelResource(value="annotationSource")
public void test(){
System.out.println("OK.业务成功执行");
}
- 整体用法和上述一样,最大的区别在于基于注解实现
- 核心功能还是基于 AOP 原理,只不过是在 AOP 里面帮忙操作了 Entry
集群-外部DataSource
因为默认情况下 Sentinel 都是内存保存的配置,基于初始化的配置进行的流程。
所以一般情况下,会自定义数据源,并且设置动态的处理。
这一块本期不深入,后续文章再细说。
Dashbaord 集群版
上面的一切问题都在于单机场景,没办法链接到集群,这里面就涉及到一个问题 :
- 集群之间机器与机器的情况需要上报 -> 汇总 -> 分析 -> 下发
- 那么就需要一个服务器来进行数据汇总
- 需要具体的上报策略,因为每一个请求来了都上报肯定是不现实的,会影响到接口的性能
java
// S1 : 首先基于官方文档创建好 Dashboard
https://sentinelguard.io/zh-cn/docs/dashboard.html
// S2 : 集成方式
- 依赖包 : com.alibaba.csp # sentinel-transport-simple-http
- 配置项 :
- -Dcsp.sentinel.dashboard.server=127.0.0.1:8080
好了 , 基础原理的使用到这里就结束了 , 下面开始概念性的学习 。
2.2 基于概念
基本概念也是文档里面直接就有的,不深入就做一些总结
- 资源 : sentinel 中被保护的对象,可以是方法,接口,url 等等
- Entry : Entry 标识一个资源的入口,通过 Entry 对资源进行保护
- 规则 : 对资源的访问策略,包括流量,熔断,热点等
- 流量控制规则 : 基于不同的模式对流量进行控制,可以直接拒绝 / 等待
- 熔断降级规则 : 当达到异常比例的时候触发熔断
- 系统保护规则 : 基于 CPU ,负载 ,整体 QPS ,线程数多个指标进行自适应的流控
- 访问控制规则 : 资源的黑白名单控制 (Sentinel 做这个感觉定位上有的不符合)
- 热点规则 : 对热点数据 (集成访问的,访问频繁的)进行针对性的流控
控制台 Dashboard 的作用是什么 ?
@ sentinelguard.io/zh-cn/docs/...
总结一下 , 控制台除了能实时监控,其他一大重要功能在于规则管理和推送,也就是说完全可以把 Dashboard 看成 Sentinel 的 Server 端。
Dashboard 本体默认是不支持数据持久化的,应用重启后配置就失效了,所以一般情况下我们会持久化 Sentinel 配置 ,具体见下文
持久化的配置。
Sentinel 简单原理讲述
Sentinel 当触发资源入口后进入处理流程,其核心流程是在一个 Slot 链中进行的 ,Slot 链是 Sentinel 中的功能插槽,各自负责的功能不同。
包括用于存储的几个 : NodeSelectorSlot (存储是搜集资源路径),ClusterBuilderSlot (存储资源的统计信息以及调用者信息) 指标,StatisticSlot (用于记录 Runtime).
另外就是实际进行控制的 Slot 包括 : FlowSlot (用于流量控制),AuthoritySlot (用于黑白名单控制),DegradeSlot (熔断降级) 以及 SystemSlot (系统指标控制)。
当通过 DefaultProcessorSlotChain 链表触发执行这些 Slot 后,Slot 会调用到其各自的 Check 用于校验是否符合当前配置的策略 。
以 FlowSlot 为例 :
- S1 : 首先通过 SphU # entry 触发资源入口处理
- S2 : 通过一系列处理来到 DefaultProcessorSlotChain # entry 从而处理链表
- S3 : 进入到 FlowSlot 来进行流量控制,由 Slot 中调用 Check
- S4 : 进入 FlowRuleChecker 判断当前的流量情况是否满足规则
- S5 : 满足则通过当前校验,不满足抛出 FlowException 被外部捕获进行处理
- 官方文档 @ sentinelguard.io/zh-cn/docs/...
- 之前的源码记录 @ juejin.cn/post/699368...
其他基础原理
每个功能点都能讲一下,但是这篇文章篇幅就会太长了,推荐直接看文档。
不想看的可以关注我,后续应该会推出基于生产的使用和原理讲解。
三. 生产级有哪些使用技巧
3.1 关于限流的方式
Sentinel 的限流主要是针对于入站流量限流,也就是说优先保护应用的稳定。
入站防护的方案很简单,添加注解或者定义资源入口就行。
但是很多场景下我们需要考虑出站流量,我们通常不能保证下游系统是否能承载足够的并发,这样的情况下就需要对出站流量进行控制,分为几个层级 :
- 优先基于业务处理 : 例如通过MQ来消费的场景,最简单的就是
减少 MQ 的消费线程
,其次就是减少业务的处理线程。 通常不建议使用 Thread.sleep 的方案,那样其实资源并没有节省出来。 - 合理区分渠道 : 不同的渠道接收的能力不一样,可以通过区分线程池处理 , 也不用在意精准的数值,
如果特殊的场景可以考虑上动态线程池
。 - 能动态限流是最好的了 : 我们没有实现这种限流,但是这种限流属于比较理想 ,但是能实现则作用很大。能基于 Response 时间等参数实现限流最好。
3.2 关于持久化定制和配置
单纯的使用功能有时候并不能满足我们的需求,在一些场景里面我们就需要进行定制化操作了 :
@ sentinelguard.io/zh-cn/docs/...
扩展主要在 Dashboard 中进行,主要包括 : 规则 ,数据源
定义自定义的 Sentinel 规则链 :
- S1 : 创建一个 Slot 对象 , 继承 AbstractLinkedProcessorSlot
- S2 : 创建一个 ChainBuilder 对象 , 继承CustomSlotChainBuilder
- S3 : SPI 注入 Builder 对象 (META-INF)
JAVA
// S1 :
public class TestAnalyseSlot extends AbstractLinkedProcessorSlot<DefaultNode> {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode param, int count, boolean prioritized, Object... args) throws Throwable {
logger.info("成功进入分析代码");
logger.info("Current entry resource: {}", context.getCurEntry().getResourceWrapper().getName());
fireEntry(context, resourceWrapper, param, count, prioritized, args);
}
@Override
public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
}
}
// S2 :
public class CustomSlotChainBuilder implements SlotChainBuilder {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public ProcessorSlotChain build() {
logger.info("添加自定义限流链路");
ProcessorSlotChain chain = new DefaultSlotChainBuilder().build();
chain.addLast(new TestAnalyseSlot());
return chain;
}
}
// S3 : 在 Resource 下面创建
- 文件路径 :META-INF/services/com.alibaba.csp.sentinel.slotchain.SlotChainBuilder
# 自定义 Slot
com.alibaba.csp.sentinel.demo.spring.webmvc.customer.CustomSlotChainBuilder
自定义 Resource :
@ sentinelguard.io/zh-cn/docs/...
大多数都已经有具体的实现方式了,包括 Nacos 和 File ,Zookeeper 等等。
另外要注意的是,这些配置信息是直接从 Client 到 DataSource ,而不是先到 dashboard 再到 DataSource。
所以 dashboard 只做了数据的汇总和配置的展示,并没有直接存储配置。
这一块比较多,放在这一篇不合适,下一篇单独讲!!
3.3 关于 Sentinel 的整合
Sentinel 在很多场景下都会配置其他的组件使用,例如 SpringGateway 等
配合 SpringGateway :Spring 网关是可以直接集成 Sentinel 的,分为2步
- S1 :引入 Sentinel Cloud + Sentinel Gateway 依赖
- S2 : 对网关进行配置,添加 Sentinel 拦截
xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
</dependency>
spring:
application:
name: gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1 # nacos注册地址
config:
server-addr: 127.0.0.1 # 远程配置地址
sentinel:
transport:
dashboard: localhost:8080 # sentinel注册地址
# 直接建立心跳
eager: true
scg:
# 限流后的响应配置
fallback:
content-type: application/json
# 模式 response、redirect
mode: response
# 响应状态码
response-status: 429
# 响应信息
response-body: 限流文案
具体的可以参考这篇文档 : blog.csdn.net/qq_43437874...
支持组件列表
对于一些特殊的组件,Sentinel 专门提供了 adapter 用于快速集成 :
- 用于集成 gprc : sentinel-grpc-adapter
- 用于集成 Dubbo : sentinel-dubbo-adapter
具体的看 sentinelguard.io/zh-cn/docs/...
3.4 关于 Sentinel 的性能问题
有的时候我们也要考虑 Sentinel 的性能问题, 比较3种常见场景的即可 :
循环数 | 普通操作 | 流控操作 | 上报类型 |
---|---|---|---|
300000 | 800 | 900 | 1200 |
3000000 | 7521 | 9062 | 10658 |
耗时主要是本地运行,没上监控,就本地打印时间取一个平均值,虽然不能说完全正确,但是大致也能看出时间曲线 :
正常流程 < 本地流控 < 上报流控。 所以当流控上报的时候确实是会产生一些资源的消耗的。
但是 !! 注意了 ,这里差异明显是由于我执行代码只是一句打印,所以差异会很明显。在300万操作情况下 ,也只是多耗时2秒左右,如果算上一些复杂的流控操作,我想这个耗时也是可以接受的。
另外由于执行的 dashboard 是在本机,所以这里没有把网络消耗考虑在内,这个才是大头。
至于资源占用上,一般都可以不考虑。在整个应用尺度上考虑这些小的占用意义不大。
总结
Sentinel 是我读的几个开源里面文档和源码都很清晰的,分包明确。所以读在这一块源码难度不高,可以尝试下。
Sentinel 还有2大重要的概念没在这一篇说,因为篇幅有限,但是会放在后续的计划中 :
- Sentinel 自定义数据源的处理
- Sentinel 上报和集群同步的流程
欢迎关注,这个月会全部捋清楚。