Dubbo服务降级

21 篇文章 0 订阅
12 篇文章 0 订阅

Dubbo服务降级

1. 为什么需要服务降级

RPC 是解决分布式系统通信问题的一大利器,而分布式系统的一大特点就是高并发,所以说 RPC 也会面临高并发的场景。在这样的情况下,我们提供服务的每个服务节点就都可能由于访问量过大而引起一系列的问题,比如业务处理耗时过长、CPU 飘高、频繁 Full GC 以及服务进程直接宕机等等。但是在生产环境中,我们要保证服务的稳定性和高可用性,这时我们就需要业务进行自我保护,从而保证在高访问量、高并发的场景下,应用系统依然稳定,服务依然高可用。

2. 服务端的自我保护

先说个结论,服务端自我保护的方式就是限流,包括服务端的限流和客户端的限流。

也就是说,如果某个服务节点的负载压力高,那么就让该服务节点不再接收太多的服务请求就好。等接收和处理的请求数量下来后,这个节点的负载压力自然就下来了。

简单来说,就是让刚启动的服务提供方应用不承担全部的流量,而是让它被调用的次数随着时间的移动慢慢增加,最终让流量缓和地增加到跟已经运行一段时间后的水平一样。

如下:

在这里插入图片描述

Dubbo限流的方式
Dubbo 中的并发控制

样例 1

限制 com.foo.BarService 的每个方法,服务器端并发执行(或占用线程池线程数)不能超过 10 个:

<dubbo:service interface="com.foo.BarService" executes="10" />

样例 2

限制 com.foo.BarService 的 sayHello 方法,服务器端并发执行(或占用线程池线程数)不能超过 10 个:

<dubbo:service interface="com.foo.BarService">
    <dubbo:method name="sayHello" executes="10" />
</dubbo:service>

样例 3

限制 com.foo.BarService 的每个方法,每客户端并发执行(或占用连接的请求数)不能超过 10 个:

<dubbo:service interface="com.foo.BarService" actives="10" />
连接控制

样例1 服务端连接控制

限制服务器端接受的连接不能超过 10 个:

<dubbo:provider protocol="dubbo" accepts="10" />

样例2 客户端连接控制

限制客户端服务使用连接不能超过 10 个 2:

<dubbo:reference interface="com.foo.BarService" connections="10" />
Dubbo限流源码分析

通过以上的分析,我们知道在Dubbo可以通过多种的方式进行服务端的限流。实际上,上面的每一种限流的逻辑都是
一个个Filter,所有的Filter会连接成一个过滤器链,每次请求都会经过整个链路中的每一个Filter。后面会出一篇文章详细介绍Dubbo Filter了,这里就不再展开了。

3. 调用端的自我保护

熔断

以上分析了服务端的自我保护,那么调用端是否也需要进行自我保护呢?答案是肯定的。

举个例子。

有服务A, 服务B, 服务C 三个服务方。它们之间存在如下的调用链关系:

服务A -> 服务B -> 服务C。

也就是服务A 依赖于服务B,服务B依赖于服务C。当一个服务 A 来调用服务 B 时,服务 B 的业务逻辑调用服务 C,而这时服务 C 响应超时了,由于服务 B 依赖服务 C,C 超时直接导致 B 的业务逻辑一直等待,而这个时候服务 A 在频繁地调用服务 B,服务 B 就可能会因为堆积大量的请求而导致服务宕机。

如下图所示:

在这里插入图片描述

所以说,在一个服务作为调用端调用另外一个服务时,为了防止被调用的服务出现问题而影响到作为调用端的这个服务,这个服务也需要进行自我保护。而最有效的自我保护方式就是熔断。

在这里插入图片描述

关于熔断,可以看下面的这篇文章:

熔断

但是Dubbo中主要是通过Dubbo Mock来实现的,不能说是真正的熔断。

Dubbo Mock配置
  1. 服务消费者注册url的mock属性

可以通过服务降级功能临时屏蔽某个出错的非关键服务,并定义降级后的返回策略。

向注册中心写入动态配置覆盖规则:

RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();
Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181"));
registry.register(URL.valueOf("override://0.0.0.0/com.foo.BarService?category=configurators&dynamic=false&application=foo&mock=force:return+null"));

其中:

  • mock=force:return+null 表示消费方对该服务的方法调用都直接返回 null 值,不发起远程调用。用来屏蔽不重要服务不可用时对调用方的影响。

  • 还可以改为 mock=fail:return+null 表示消费方对该服务的方法调用在失败后,再返回 null 值,不抛异常。用来容忍不重要服务不稳定时对调用方的影响。

  1. @DubboReference注解或者dubbo:reference标签的mock属性

这个标签的作用主要是用于本地伪装。比如某验权服务,当服务提供方全部挂掉后,客户端不抛出异常,而是通过 Mock 数据返回授权失败。

例子:
mock=“return null”,即当服务提供者出现异常(宕机或者业务异常),则返回null给服务消费者。

public class HelloController{
    
    @DubboReference(check = false,lazy = true,retries = 1,mock = "return null")
    private DubboServiceOne dubboServiceOne;
    
    //.....
}
MockClusterInvoker源码分析

com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker ,实现 Invoker 接口,MockClusterWrapper 对应的 Invoker 实现类。

  1. 构造方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rcj4NxkQ-1673527805154)(https://tva1.sinaimg.cn/large/008i3skNgy1gqs6y28rt4j31p60nodkd.jpg)]

  1. invoke

在这里插入图片描述
在这里插入图片描述

从上面的源码分析可知:

  • 在 MockClusterInvoker#invoke 方法里面,如果是业务异常是不会做 mock 做处理的。而其他关于 RPC 的异常,是会做 mock 处理的,例如我们这里拿来测试的服务提供者超时异常和服务提供者不存在;

  • 在 doMockInvoke 方法中,首先会调用 selectMockInvoker 方法会尝试获取 MockInvoker,而默认情况下,都是没有的,所以最后会使用 Dubbo 提供的 MockInvoker。

4. 总结

通过以上的分析,我们可以知道,服务端主要是通过限流来进行自我保护。而调用端主要是通过熔断来进行自我保护。

5. 鸣谢

RPC核心实战与原理

Dubbo服务熔断与降级的深入讲解&代码实战

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱coding的同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值