Sentinel Dubbo 适配器看限流与熔断(实战思考篇)
点击上方“中间件兴趣圈”,选择“设为星标”
做积极的人,越努力越幸运!
本文将以 Dubbo 服务调用为案例剖析场景,尝试对官方提供的 Dubbo 适配器做一个研究学习并对此做出自己的评价,抛出我的观点,期待与大家共同探讨,交流。
一个 Dubbo RPC 的简易调用过程如下图所示:
接下来请大家带着在 Dubbo 中如何使用限流、熔断方面来看官方给出的解决方案。
思考题:在看接下来的内容之前,建议大家稍作停顿,思考一下,在服务调用模型中,限流、熔断通常在哪个端做比较合适。
1、从消费端来看限流与熔断
我们先来看看官方提供的 Dubbo 适配器的核心实现:
消费端这边使用到了两个资源名称,一个是接口级别,例如 com.demo.service.UserService,另外一是方法级别,例如 com.demo.servcie.UserServce#findUser(Ljava.lang.String)。限流规则是依附于具体某一个项目的,例如如下图所示:
1.1 服务调用端(消费方)是否需要配置限流规则
在 dubbo 的服务调用场景中,在消费端设置限流的规则的话,这个调用链是针对整个集群所有服务提供者的,例如当前集群中包含3个服务提供者,每个服务提供者用于1000tps的服务能力,那消费端的限流,应该配置的限流TPS应该为3000tps,如果设置为1000tps,则无法完整的利用服务端的能力,基于这样的情况,通常消费端无需配置限流规则。
那是不是说消费端就没必要配置限流规则呢?其实也不是,有如下这个场景,例如调用第三方外部的计费类服务接口,对方通常为特定的账户等级设置对应的TPS上限,如果超过该调用频率就会抛出错误,这种情况还是需要设置限流规则,确保消费端以不超过要求进行调用,避免业务异常。
1.2 服务调用端(消费方)是否需要配置熔断
引入熔断的目的是避免服务端单节点响应慢而导致这个服务不稳定,例如示例中有3个服务提供者,如果192.168.1.3的服务提供者由于触发了BUG导致响应时间大大增加,导致发往该服务提供者的请求大概率超时,在这样的情况下希望在接下来某段时间内消费方发往这这个服务提供者的请求快速熔断降级,返回错误,由客户端重试其他服务提供者。其实现效果如下:
我们以 Sentinel 基于异常比例熔断策略来进行阐述,如果资源的调用异常比例超过一定值是会触发降级熔断,抛出 DegradeException 异常。
由于总共只有三个服务提供者,其中发往192.168.1.3的请求大概率会由于超时失败,则异常比例会超过设置的熔断降级规则,会触发降级,造成的效果是整个服务调用都会发送熔断降级,即调用192.168.1.4,5两个请求都不会被熔断,造成整个服务调用不可用,与期望不一致。即还是会出现一个节点的不稳定而导致整个服务不稳定的情况。
其造成的根本原因是因为其资源的定义并没有包含服务提供者的信息,改进的初步方案:
在过滤器中再定义一个资源,加上服务提供的IP与端口号,例如 SphU.entry("com.d.s.UserService@ip:port"),对单个服务提供者进行单独收集调用信息,并且需要提供一可配置的项,用来标记该类型的资源在做熔断判断可使用某一个资源的配置,例如配置为 com.d.s.UserService,表示用这个配置规则来判断熔断。
在熔断规则判断的时候,该资源使用被引用资源的熔断规则进行判断。
最后来解答一下,熔断规则通常只需要配置在调用方即可。
2、从服务端来看限流与熔断
由于服务端看限流与熔断就比较简单,因为服务端与客户端存在一个非常大的区别是客户端存在负载均衡机制,一个消费端对于同一资源来说,会调用多个服务提供者,而服务提供者对于一个资源来就是其自身,故限流规则,熔断规则都是针对个体,其复杂度降低。
为了知识体系的完备性,我们来看一下 Sentinel Dubbo 在服务端的适配器的实现。
这里有二个关键点:
使用了 ContextUtil 的 entry 方法,定义本次调用的上下文环境名称为:resourceName,默认为接口名与方法名、参数列表,例如 com.d.s.UserServce#findUser(Ljava.lang.String),源头为消费端的应用名称。
定义两个资源,这里与消费端相同,就不做重复解读。
关于这个 ContextUtil 的 entry 方法非常关键,因为 Sentinel 中数据节点的统计是以 ContextName 为维度的。
例如想对一个应用所有的操作 redis 操作统一设置为一个资源名,redisOpsResource,即想控制该应用整体的 redis 操作 tps,其场景如下:
3、总结
本文结合 Sentinel 官方对于 Dubbo 提供的适配器并加以理解,提出了如下观点,欢迎大家留言探讨,相互交流,共同进步。
限流规则根据不同的使用场景可以在客户端、服务端配置。
熔断规则通常在服务调用方配置即可。
Sentinel 目前的熔断还实现的比较简单,无法解决集群中因为某一个节点的访问慢而触发熔断,并使服务稳定的能力。
Sentienl 的实时统计是以调用上下文(Context Name),即 ContextUtil.entry 方法定义的上下文为维度的,这点非常关键,不然容易踩坑。
欢迎加入我的知识星球,一起交流源码,探讨架构,揭秘亿级订单的架构设计与实践经验,打造高质量的技术交流圈,为广大星友提供高质量问答服务,长按如下二维码加入。