Sentinel Dubbo 适配器看限流与熔断(实战思考篇)

作积极的人,越努力越幸运!
Sentinel Dubbo 适配器看限流与熔断(实战思考篇)
本文是源码分析 Sentinel 系列的第十三篇,已经很是详细的介绍了 Sentinel 的架构体系、滑动窗口、调用链上下文、限流、熔断的实现原理,相信各位读者朋友们对Sentinel有一个较为体系化的认知了,这个时候是该开始如何在生产环境进行运用了。java

本文将以 Dubbo 服务调用为案例剖析场景,尝试对官方提供的 Dubbo 适配器作一个研究学习并对此作出本身的评价,抛出个人观点,期待与你们共同探讨,交流。redis

一个 Dubbo RPC 的简易调用过程以下图所示:
Sentinel Dubbo 适配器看限流与熔断(实战思考篇)算法

消费者会维护一个服务提供者列表,而后再发一块儿一个服务调用的时候会首先根据负载均衡算法从中选择一个服务提供者,而后发起 RPC 调用,在请求真实发送以前会依次经过客户端设置的过滤器链(Filter),而后通过网络传输到到达服务提供者,并执行完服务提供者端的 Filter,最后进入到业务逻辑执行并返回结果。网络

Sentinel 与 Dubbo 的整合就是利用了 Dubbo 的 Filter 机制,为 Dubbo 提供对应的 过滤器,无缝实现限流、熔断等功能,作到业务无感知,即业务代码无需使用 Sentinel 相关的 API。
接下来请你们带着在 Dubbo 中如何使用限流、熔断方面来看官方给出的解决方案。架构

思考题:在看接下来的内容以前,建议你们稍做停顿,思考一下,在服务调用模型中,限流、熔断一般在哪一个端作比较合适。负载均衡

一、从消费端来看限流与熔断


Sentinel Dubbo 适配器看限流与熔断(实战思考篇)
从消费端的视角,虽然提供了服务端的负载均衡,但从客户端不论是向192.168.1.3仍是向192.168.1.4发送RPC调用,都会通过同一个 Sentinel Dubbo Filter。这个看似简单明了,但这是咱们接下来思考的最基本最核心的点。
咱们先来看看官方提供的 Dubbo 适配器的核心实现:ide

Sentinel Dubbo 适配器看限流与熔断(实战思考篇)
SentinelDubboConsumerFilter#invoke
消费端这边使用到了两个资源名称,一个是接口级别,例如 com.demo.service.UserService,另一是方法级别,例如 com.demo.servcie.UserServce#findUser(Ljava.lang.String)。
定义了两个资源后,Sentinel 会使用滑动窗口机制,为上述两个资源收集实时的调用信息,为后续的限流、熔断提供数据依据。
限流规则是依附于具体某一个项目的,例如以下图所示:源码分析

Sentinel Dubbo 适配器看限流与熔断(实战思考篇)
限流、熔断都是根据资源级别,若是须要对消费端的调用进行限流的话,就须要为这两个资源配置对应的限流规则,若是不配置则默认经过,表示不限流。学习

1.1 服务调用端(消费方)是否须要配置限流规则

在 dubbo 的服务调用场景中,在消费端设置限流的规则的话,这个调用链是针对整个集群全部服务提供者的,例如当前集群中包含3个服务提供者,每一个服务提供者用于1000tps的服务能力,那消费端的限流,应该配置的限流TPS应该为3000tps,若是设置为1000tps,则没法完整的利用服务端的能力,基于这样的状况,一般消费端无需配置限流规则。架构设计

那是否是说消费端就不必配置限流规则呢?其实也不是,有以下这个场景,例如调用第三方外部的计费类服务接口,对方一般为特定的帐户等级设置对应的TPS上限,若是超过该调用频率就会抛出错误,这种状况仍是须要设置限流规则,确保消费端以不超过要求进行调用,避免业务异常。

1.2 服务调用端(消费方)是否须要配置熔断

引入熔断的目的是避免服务端单节点响应慢而致使这个服务不稳定,例如示例中有3个服务提供者,若是192.168.1.3的服务提供者因为触发了BUG致使响应时间大大增长,致使发往该服务提供者的请求大几率超时,在这样的状况下但愿在接下来某段时间内消费方发往这这个服务提供者的请求快速熔断降级,返回错误,由客户端重试其余服务提供者。其实现效果以下:
Sentinel Dubbo 适配器看限流与熔断(实战思考篇)
当前的 Sentinel 默认是否能知足上述的需求呢?
咱们以 Sentinel 基于异常比例熔断策略来进行阐述,若是资源的调用异常比例超过必定值是会触发降级熔断,抛出 DegradeException 异常。

因为总共只有三个服务提供者,其中发往192.168.1.3的请求大几率会因为超时失败,则异常比例会超过设置的熔断降级规则,会触发降级,形成的效果是整个服务调用都会发送熔断降级,即调用192.168.1.4,5两个请求都不会被熔断,形成整个服务调用不可用,与指望不一致。即仍是会出现一个节点的不稳定而致使整个服务不稳定的状况。

其形成的根本缘由是由于其资源的定义并无包含服务提供者的信息,改进的初步方案:

  1. 在过滤器中再定义一个资源,加上服务提供的IP与端口号,例如 SphU.entry("com.d.s.UserService@ip:port"),对单个服务提供者进行单独收集调用信息,而且须要提供一可配置的项,用来标记该类型的资源在作熔断判断可以使用某一个资源的配置,例如配置为 com.d.s.UserService,表示用这个配置规则来判断熔断。
  2. 在熔断规则判断的时候,该资源使用被引用资源的熔断规则进行判断。
    最后来解答一下,熔断规则一般只须要配置在调用方便可。

二、从服务端来看限流与熔断


因为服务端看限流与熔断就比较简单,由于服务端与客户端存在一个很是大的区别是客户端存在负载均衡机制,一个消费端对于同一资源来讲,会调用多个服务提供者,而服务提供者对于一个资源来就是其自身,故限流规则,熔断规则都是针对个体,其复杂度下降。

为了知识体系的完备性,咱们来看一下 Sentinel Dubbo 在服务端的适配器的实现。

Sentinel Dubbo 适配器看限流与熔断(实战思考篇)
SentinelDubboProviderFilter#invoke

这里有二个关键点:

  1. 使用了 ContextUtil 的 entry 方法,定义本次调用的上下文环境名称为:resourceName,默认为接口名与方法名、参数列表,例如 com.d.s.UserServce#findUser(Ljava.lang.String),源头为消费端的应用名称。
  2. 定义两个资源,这里与消费端相同,就不作重复解读。
    关于这个 ContextUtil 的 entry 方法很是关键,由于 Sentinel 中数据节点的统计是以 ContextName 为维度的。

例如想对一个应用全部的操做 redis 操做统一设置为一个资源名,redisOpsResource,即想控制该应用总体的 redis 操做 tps,其场景以下:

Sentinel Dubbo 适配器看限流与熔断(实战思考篇)
例如初衷设计为 opsReisTotal 的整个 tps 为 500,例如从UserService#findser链路的访问 redis tps 为 400,而从 Order#createOrder 链路访问 redis tps 为 400,此时 redis 的总体 tps 已经达到了 800 tps,但你会发现并不会触发限流,由于对资源 RredisOpResource 的调用信息统计是以 context name 为维度的,不一样的 context name 互不影响,从而没法作到全局控制。

三、总结


本文结合 Sentinel 官方对于 Dubbo 提供的适配器并加以理解,提出了以下观点,欢迎你们留言探讨,相互交流,共同进步。

  1. 限流规则根据不一样的使用场景能够在客户端、服务端配置。
  2. 熔断规则一般在服务调用方配置便可。
  3. Sentinel 目前的熔断还实现的比较简单,没法解决集群中由于某一个节点的访问慢而触发熔断,并使服务稳定的能力。
  4. Sentienl 的实时统计是以调用上下文(Context Name),即 ContextUtil.entry 方法定义的上下文为维度的,这点很是关键,否则容易踩坑。

欢迎加入个人知识星球,一块儿交流源码,探讨架构,揭秘亿级订单的架构设计与实践经验,打造高质量的技术交流圈,为广大星友提供高质量问答服务,长按以下二维码加入。
Sentinel Dubbo 适配器看限流与熔断(实战思考篇)

相关文章
相关标签/搜索