03 为什么选择 Sentinel,Sentinel 与 Hystrix 的对比

为什么选择 Sentinel?

选择 Sentinel 与 Hystrix 通常第一步都是通过对比两者优缺点,Sentinel 与 Hystrix 的对比结果是作为我们选择 Sentinel 还是 Hystrix 的直观参考,不过使用 Sentinel 能做什么,是否满足实际需求才是我们最终决定是否使用 Sentinel 的最关键因素,否则尽管一个框架再好,不适合也不会选择。

以下 Sentinel 与 Hystrix 的对比,表格来自 Sentinel Github 官方文档。 Sentinel Hystrix 隔离策略 信号量隔离 线程池隔离/信号量隔离 熔断降级策略 基于响应时间或失败比率 基于失败比率 实时指标实现 滑动窗口 滑动窗口(基于 RxJava) 规则配置 支持多种数据源 支持多种数据源 扩展性 多个 SPI 扩展点 插件的形式 基于注解的支持 支持 支持 限流 基于 QPS,支持基于调用关系的限流 有限的支持 流量整形 支持慢启动、匀速器模式 不支持 系统负载保护 支持 不支持 控制台 开箱即用,可配置规则、查看秒级监控、机器发现等 不完善 常见框架的适配 Servlet、Spring Cloud、Dubbo、gRPC 等 Servlet、Spring Cloud Netflix

Sentinel 于 2018 年 7 月份开源,截至本文写作之日已有 13k 的 Star,而 Hystrix 已经停止开发。Hystrix 不再维护可能也是 Sentinel 能快速进入大家眼球的原因之一。Hystrix 虽然不再维护,但依然开源,且 Hystrix 已经很稳定,不会因为不维护就不可用,只是不会再有更新。相比 Hystrix,Sentinel 更易于上手,Sentinel 是国内开源的项目,官方有提供中文文档,因此对只会中文的开发者较为友好,并且文档介绍得也很全面。

Hystrix 最核心的一项功能就是资源隔离,支持线程池隔离和信号量隔离。Sentinel 不支持线程池隔离,但使用 Sentinel 也可通过控制并发线程数方式提供信号量隔离。例如,控制服务 A 同时只能有 5 个线程去调用服务 B 的某个接口,或者控制服务 B 同时只能有 5 个线程去处理服务 A 发起调用的某个接口,避免因为一个接口消耗全部线程资源,导致服务奔溃。Hystrix 的线程池隔离可以为每个资源配置单独的线程池用于发送请求,但资源多的情况下会导致线程池增多,线程池增多会导致线程数增多,上下文切换会有非常大的损耗,对低延时的调用影响较大,因此 Hystrix 的线程池隔离也并未体现出多大的优势。

Sentinel 与 Hystrix 都支持基于失败比率的熔断降级,在调用超过指定的数量并且失败比率达到设定的阈值时触发熔断,并在下个时间窗口自动恢复。Sentinel 也支持按失败总数熔断降级,但按失败总数的熔断降级固定时间窗口为 1 分钟,当 1 分钟内调用失败总数达到设定的阈值就会触发熔断。除此之外,Sentinel 还支持基于平均响应时间的熔断降级,平均响应时间越长,说明服务的性能在持续下降,在响应时间持续飙高时自动熔断,可以防止调用慢造成级联阻塞。

Sentinel 和旧版本 Hystrix 的实时指标数据统计实现都是基于滑动窗口,指标数据统计指的是统计每个资源的当前窗口时间内的请求总数、处理成功总数、失败总数、总耗时、平均耗时、最大耗时、最小耗时、被降级总数等。使用滑动窗口可以循环利用一个数组,不需要重新申请内存,也不需要去删除过期的统计数据,降低 GC 的压力。Hystrix 1.5 版本对实时指标统计的实现进行了重构,将指标统计数据结构抽象成响应式流(reactive stream)的形式,方便消费者去利用指标信息,同时底层改造成基于 RxJava 的事件驱动模式,在服务调用成功、失败或超时时发布事件,通过一系列的变换和聚合最终得到实时的指标统计数据流,可以被熔断器或 Dashboard 消费 [1]。Sentinel 官方表示,未来将支持响应式流。

Sentinel 提供数据源接口可实现动态加载规则配置,结合 loadRules API 可灵活的运行时修改规则配置,并且随时修改随时生效。动态修改不仅支持修改某资源的规则配置,也支持添加新的资源规则配置或者移除资源规则配置。Sentinel 支持给同一个资源同时添加多种规则配置,当对同一个资源配置多种规则时,哪个规则先达到阈值就会触发哪个规则的降级。Hystrix 的资源模型设计上采用了命令模式,在创建 Command 时就需要指定隔离策略是线程池隔离还是信号量隔离,一但指定了隔离策略,运行期间便不能修改隔离策略,而在 Sentinel 中资源定义和规则配置是分离的,因此在配置的灵活性上 Sentinel 更具有优势。

Sentinel 支持系统自适应限流,Hystrix 所不支持的。当系统负载较高的时候,如果仍持续让请求进入,可能会导致系统崩溃,无法响应。在集群环境下,负载均衡把本应这台机器承载的流量转发到其它的机器上去,如果这个时候其它的机器也处在一个边缘状态的时候,这个增加的流量就会导致这台机器崩溃,最后导致整个集群不可用。针对这个情况,Sentinel 提供了对应的保护机制,让系统的入口流量和系统的负载达到一个平衡,保证系统在能力范围之内处理最多的请求 [2]。

在 QPS 过高的情况下,直接拒绝超出限制的请求是最常见的实现方式,但有些场景我们可能并不想直接拒绝请求,而是让请求排队等待处理,例如某一秒突增请求过多,但下一秒可能又没有请求或者请求很少的情况。Sentinel 的流量控制支持多种模式,例如直接拒绝模式、慢启动预热模式、匀速器模式。而慢启动预热模式和匀速器模式也是 Hystrix 所不支持的。

Sentinel 在框架的设计上使用了责任链模式和 SPI 机制提供扩展功能。使用 SPI 机制为 Sentinel 提供了更好的扩展性,例如,使用 SPI 支持自定义调用链构建器,使用自定义调用链构建器可实现按需选配降级功能(ProcessorSlot),并且还可以自己添加自定义降级功能(ProcessorSlot)。简单说,我们可以实现自定义降级功能,或者根据需要选择 Sentinel 提供的降级功能,移除不需要的,尽量降低 Sentinel 对服务的性能影响。

Sentinel 还支持集群限流。除了轮询负载均衡算法外,其它的算法都会导致流量到集群的每个节点都不一样,有的多有的少,假设服务 B 部署两个节点,对每个节点配置限流阈值为 200 QPS,我们希望集群的整体限量阈值是 400 QPS,但实际情况可能 400 个请求有 300 个请求分配到节点 1,只有 100 个请求分配到节点 2,导致总量没有到的情况下节点 1 就开始限流,因此单机维度限流会无法精确地限制总体流量。

集群流控可以精确地控制整个集群的调用总量,结合单机限流兜底,可以更好地发挥流量控制的效果。但实现集群限量需要一个 Server 专门统计集群的总调用量,其它的实例都要与 Server 通信来判断是否可以调用,也意味着每个请求都要增加一次额外的与 Server 通信的消耗,不过在使用单一长连接且 Server 处理“判断是否能通过”的耗时非常低,这个消耗对性能的影响还是可以接受的。

另外,黑白名单限流和热点参数限流也是 Sentinel 的一大特色。

黑白名单限流,可根据请求来源判断来源是否在黑名单中,如果在黑名单中则拒绝请求,否则放行,结合 Sentinel 的灵活动态配置,黑白名单可用于高峰期间对某些服务限流。

热点参数限流,统计调用 SphU.entry 传入参数中的热点参数,根据配置的限流阈值对包含热点参数的资源调用进行限流。热点参数限流仅对包含热点参数的资源调用生效,Sentinel 利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法进行参数级别的流控,并且支持匀速流控效果。例如,想对某个热卖的商品限流,可将商品的 ID 为参数,统计一段时间内访问量最多的商品并进行限制。

Sentinel 提供的多种限流功能基本满足我们的所有需求,并且提供切入点让使用者可扩展 Sentinel 的功能,加上灵活的规则配置,以及 Sentinel 在性能上所作出的努力,都是 Sentinel 被广泛使用的原因。Sentinel 有阿里巴巴做信用背书,也在不断的优化、不断更新,相信 Sentinel 能做得更好。

参考文献

参考资料

https://learn.lianglianglee.com/%e4%b8%93%e6%a0%8f/%e6%b7%b1%e5%85%a5%e7%90%86%e8%a7%a3%20Sentinel%ef%bc%88%e5%ae%8c%ef%bc%89/03%20%e4%b8%ba%e4%bb%80%e4%b9%88%e9%80%89%e6%8b%a9%20Sentinel%ef%bc%8cSentinel%20%e4%b8%8e%20Hystrix%20%e7%9a%84%e5%af%b9%e6%af%94.md