《深入理解 Sentinel》笔记
《深入理解 Sentinel》笔记
开篇词:一次服务雪崩问题排查经历
什么是服务雪崩
服务雪崩是指:在微服务项目中指由于突发流量导致某个服务不可用,从而导致上游服务不可用,并产生级联效应,最终导致整个系统不可用。
当一切正常时,整体系统如下所示:
在分布式系统架构下,这些强依赖的子服务稳定与否对系统的影响非常大。但是,依赖的子服务可能有很多不可控问题:如网络连接、资源繁忙、服务宕机等。例如:下图中有一个 QPS 为 50 的依赖服务 I 出现不可用,但是其他依赖服务是可用的。
当流量很大的情况下,某个依赖的阻塞,会导致上游服务请求被阻塞。当这种级联故障愈演愈烈,就可能造成整个线上服务不可用的雪崩效应,如下图。这种情况若持续恶化,如果上游服务本身还被其他服务所依赖,就可能出现多米洛骨牌效应,导致多个服务都无法正常工作。
为什么需要服务降级以及常见的几种降级方式
服务降级是为了保障服务能够稳定运行的一种保护方式,应对流量突增用降级牺牲一些流量换取系统的稳定。常见的服务降级实现方式有:开关降级、限流降级、熔断降级。
限流降级与熔断降级都可以实现在消费端限流或者服务端限流,限流可以根据流量控制策略处理超过阈值的流量。
- 限流即便没有达到系统的瓶颈,只要流量达到设定的阈值,就会触发限流;
- 熔断尽最大的可能去完成所有的请求,容忍一些失败,熔断也能自动恢复。熔断的常见降级策略:
- 在每秒请求异常数超过多少时触发熔断降级
- 在每秒请求异常错误率超过多少时触发熔断降级
- 在每秒请求平均耗时超过多少时触发熔断降级
开关降级适用于促销活动这种可以明确预估到并发会突增的场景。
为什么选择 Sentinel,Sentinel 与 Hystrix 的对比
Sentinel | Hystrix | |
---|---|---|
社区活跃度 | Github 13K star | 官方停止维护 |
隔离策略 | 信号量隔离 | 线程池隔离/信号量隔离 |
熔断降级策略 | 基于响应时间或失败比率 | 基于失败比率 |
实时指标实现 | 滑动窗口 | 滑动窗口(基于 RxJava) |
规则配置 | 支持多种数据源 | 支持多种数据源 |
扩展性 | 多个 SPI 扩展点 | 插件的形式 |
基于注解的支持 | 支持 | 支持 |
限流 | 基于 QPS,支持基于调用关系的限流 | 有限的支持 |
流量整形 | 支持慢启动、匀速器模式 | 不支持 |
系统负载保护 | 支持 | 不支持 |
控制台 | 开箱即用,可配置规则、查看秒级监控、机器发现等 | 不完善 |
常见框架的适配 | Servlet、Spring Cloud、Dubbo、gRPC 等 | Servlet、Spring Cloud Netflix |
Sentinel 基于滑动窗口的实时指标数据统计
- WindowWrap 用于包装 Bucket,随着 Bucket 一起创建。
- WindowWrap 数组实现滑动窗口,Bucket 只负责统计各项指标数据,WindowWrap 用于记录 Bucket 的时间窗口信息。
- 定位 Bucket 实际上是定位 WindowWrap,拿到 WindowWrap 就能拿到 Bucket。
Sentinel 的一些概念与核心类介绍
- 资源:资源是 Sentinel 的关键概念。资源,可以是一个方法、一段代码、由应用提供的接口,或者由应用调用其它应用的接口。
- 规则:围绕资源的实时状态设定的规则,包括流量控制规则、熔断降级规则以及系统保护规则、自定义规则。
- 降级:在流量剧增的情况下,为保证系统能够正常运行,根据资源的实时状态、访问流量以及系统负载有策略的拒绝掉一部分流量。
核心类:
ResourceWrapper
类用于表示资源。
Node
用于持有实时统计的指标数据。它有几个实现类:DefaultNode
、ClusterNode
、EntranceNode
、StatisticNode
。
- StatisticNode 是实现实时指标数据统计 Node。
- DefaultNode 是实现以资源为维度的指标数据统计的 Node。
- ClusterNode 统计每个资源全局的指标数据,以及统计该资源按调用来源区分的指标数据。
- EntranceNode 继承 DefaultNode,用于维护一颗树,从根节点到每个叶子节点都是不同请求的调用链路,所经过的每个节点都对应着调用链路上被 Sentinel 保护的资源,一个请求调用链路上的节点顺序正是资源被访问的顺序。
- Context 代表调用链路上下文,贯穿一次调用链路中的所有 Entry。Context 维持着入口节点(entranceNode)、本次调用链路的 curNode、调用来源(origin)等信息。Context 名称即为调用链路入口名称。Context 通过 ThreadLocal 传递,只在调用链路的入口处创建。
- Entry 维护了当前资源的 DefaultNode,以及调用来源的 StatisticNode。
- ProcessorSlot 直译就是处理器插槽,是 Sentinel 实现限流降级、熔断降级、系统自适应降级等功能的切入点。Sentinel 提供的 ProcessorSlot 可以分为两类,一类是辅助完成资源指标数据统计的切入点,一类是实现降级功能的切入点。实现降级功能的 ProcessorSlot:
- AuthoritySlot:实现黑白名单降级
- SystemSlot:实现系统自适应降级
- FlowSlot:实现限流降级
- DegradeSlot:实现熔断降级
Sentinel 中的责任链模式与 Sentinel 的整体工作流程
Sentinel 的工作流就是使用责任链模式将所有的 ProcessorSlot 按照一定的顺序串成一个单向链表。
实现将 ProcessorSlot 串成一个单向链表的是 ProcessorSlotChain,这个 ProcessorSlotChain 是由 SlotChainBuilder 构造的。
Java SPI 及 SPI 在 Sentinel 中的应用
SPI 全称是 Service Provider Interface,直译就是服务提供者接口,是一种服务发现机制,是 Java 的一个内置标准,允许不同的开发者去实现某个特定的服务。SPI 的本质是将接口实现类的全限定名配置在文件中,由服务加载器读取配置文件,加载实现类,实现在运行时动态替换接口的实现类。
在 sentinel-core 模块的 resources 资源目录下,有一个 META-INF/services 目录,该目录下有两个以接口全名命名的文件,其中 com.alibaba.csp.sentinel.slotchain.SlotChainBuilder 文件用于配置 SlotChainBuilder 接口的实现类。
08 资源指标数据统计的实现全解析(上)
NodeSelectorSlot 负责为资源的首次访问创建 DefaultNode,以及维护 Context.curNode 和调用树。NodeSelectorSlot 被放在 ProcessorSlotChain 链表的第一个位置,这是因为后续的 ProcessorSlot 都需要依赖这个 ProcessorSlot。
09 资源指标数据统计的实现全解析(下)
- 一个调用链路上只会创建一个 Context,在调用链路的入口创建(一个调用链路上第一个被 Sentinel 保护的资源)。
- 一个 Context 名称只创建一个 EntranceNode,也是在调用链路的入口创建,调用 Context#enter 方法时创建。
- 与方法调用的入栈出栈一样,一个线程上调用多少次 SphU#entry 方法就会创建多少个 CtEntry,前一个 CtEntry 作为当前 CtEntry 的父节点,当前 CtEntry 作为前一个 CtEntry 的子节点,构成一个双向链表。Context.curEntry 保存的是当前的 CtEntry,在调用当前的 CtEntry#exit 方法时,由当前 CtEntry 将 Context.curEntry 还原为当前 CtEntry 的父节点 CtEntry。
- 一个调用链路上,如果多次调用 SphU#entry 方法传入的资源名称都相同,那么只会创建一个 DefaultNode,如果资源名称不同,会为每个资源名称创建一个 DefaultNode,当前 DefaultNode 会作为调用链路上的前一个 DefaultNode 的子节点。
- 一个资源有且只有一个 ProcessorSlotChain,一个资源有且只有一个 ClusterNode。
- 一个 ClusterNode 负责统计一个资源的全局指标数据。
- StatisticSlot 负责记录请求是否被放行、请求是否被拒绝、请求是否处理异常、处理请求的耗时等指标数据,在 StatisticSlot 调用 DefaultNode 用于记录某项指标数据的方法时,DefaultNode 也会调用 ClusterNode 的相对应方法,完成两份指标数据的收集。
- DefaultNode 统计当前资源的各项指标数据的维度是同一个 Context(名称相同),而 ClusterNode 统计当前资源各项指标数据的维度是全局。