Dubbo高可用之服务降级

服务降级是指,当服务器压力剧增的情况下,需要根据当前业务情况及流量对一些非关键服务有策略的临时降低服务级别,以释放服务器资源, 保证核心任务的正常运行。如淘宝双十一,在0点-2点期间淘宝用户不能修改收货地址,不能查看历史订单,就是典型的服务降级。

降级方式

能够实现服务降级方式很多,总结起来有以下4种情况:

1)部分服务暂停

例如个人中心,完整功能包括修改基本信息、修改密码、查看购买的课程列表等,将其中的修改基本信息临时暂停,其它功能可以正常使用,就属于部分服务暂停。

2)全部服务暂停

这种一般在宕机的情况下使用,比如以前很多Web应用在更新升级的短暂瞬间,访问应用会跳转到一个预先设定好的静态页面。这种服务降级,一般配置在路由网关上,比如Nginx服务器。

3)随机拒绝服务

服务器会按照预先设定好的比例, 随机挑选用户,对其拒绝服务。作为用户,可能会看到一些温馨提示,例如“服务器繁忙,请稍后重试”之类,重试也有可能就可获得服务。

4)部分服务延迟

服务正常使用,只是结果会延迟。比如当用户提交某些请求时,系统会提示该操作已成功,并提示会在若干时间后可以查看到正确的执行结果。对于一些耗时较长或实时性不敏感的服务,适合规划使用此类降级。这类服务大多会使用消息队列的方式处理。

Dubbo框架提供的服务降级支持,主要围绕在服务消费者端进行,实现对部分或者全部服务暂停,是否全部暂停,取决于运维需求。

Dubbo的服务降级实现机制

Dubbo的服务降级采用的是mock机制(模拟机制),即在服务消费方本地创建一个服务的实现类,用于在需要服务降级时,包括服务调用超时等,临时代替真实的远程服务实现类执行并返回结果,官方称为本地伪装。

Dubbo提供了两种服务降级的方式,一种是使用Dubbo内置的mock实现,一种是自定义本地伪装类即Mock类。

Dubbo中配置服务降级的属性为dubbo:reference标签或dubbo:method标签上的mock属性;支持接口级别和方法级别的配置;对于方法级别的设置,除了可以使用dubbo:method标签外,还可以使用dubbo:parameter标签配置。

通过mock属性设置为return、throw、force或fail关键字开头的字符串来启用Dubbo内置的mock实现;如果mock设置为true或具体的Mock类型,表示使用自定义的Mock类进行服务降级处理。

内置Mock实现服务降级

1)return

使用return来返回一个用字符串表示的对象,作为远程方法调用的返回值。

  1. empty: 代表空,表示返回基本类型的默认值,或者集合类的空值,或字符串的"",或者实体类属性的默认值(即new Xxxx())
  2. null:返回null值,如果匹配不到其它处理方式或使用方式,这是配置mock属性后默认的返回值
  3. true:返回布尔值true
  4. false:返回布尔值false
  5. JSON 格式: 反序列化JSON所得到的对象
  6. 除了以上5种,将原样返回return之后的内容(字符串或基本类型)

接口级别降级:接口的所有方法调用降级,全部返回null

<dubbo:reference id="orderService" interface="com.harvey.samples.client.OrderService" protocol="dubbo" group="one"
                     mock="return null"/>

方法级别降级:如果只是想对部分接口降级

<!-- 对getOrderInfo方法进行降级,其它方法正常调用 -->
<dubbo:reference id="orderService" interface="com.harvey.samples.client.OrderService" protocol="dubbo" group="one">
    <dubbo:method name="getOrderInfo" mock="return null"/>
    <!-- 也可以使用dubbo:parameter标签进行配置 -->
    <dubbo:parameter key="getOrderInfo.mock" value="return null"/>
</dubbo:reference>

注意,Mock是在调用发生RpcException异常之后才起作用的,如果不是Mock异常,将不会用到Mock。对于方法级别的降级,仍然需要服务注册到注册中心,否则调用时会发生服务提供者不存在的异常,此时Mock实际还未介入,最终可能导致调用或程序中断。

2)throw

使用throw来返回一个Exception对象,作为远程方法调用的返回值。

当调用出错时,抛出一个默认的RPCException

<dubbo:reference id="orderService" interface="com.harvey.samples.client.OrderService" protocol="dubbo" group="one" mock="throw"/>

也可以抛出一个自定义的异常,比如

<dubbo:reference id="orderService" interface="com.harvey.samples.client.OrderService" protocol="dubbo" group="one"
                     mock="throw com.harvey.samples.core.OrderException"/>

OrderException.java

/**
 * 自定义异常,重新类的方法
 */
public class OrderException extends RuntimeException {

    public OrderException() {
        super();
    }

    public OrderException(String message) {
        super(message);
    }

    public OrderException(String message, Throwable cause) {
        super(message, cause);
    }

    public OrderException(Throwable cause) {
        super(cause);
    }
}

3)force和fail

在 2.6.6 以上的版本,可以开始在Spring XML置文件中使用 fail: 和 force:。fail: 与上面的介绍的2种方式行为一致,即只有当远程调用发生错误时才使用Mock行为。force: 代表强制使用Mock行为,在这种情况下不会走远程调用。force: 和 fail: 都支持与throw或者return组合使用。

强制接口所有方法返回指定值(假设接口的所有方法返回值都是Sring类型)

<dubbo:reference id="orderService" interface="com.harvey.samples.client.OrderService" protocol="dubbo" group="one"
                     mock="force:return stringresult"/>

强制抛出自定义的异常

<dubbo:reference id="orderService" interface="com.harvey.samples.client.OrderService" protocol="dubbo" group="one" 
                     mock="force:throw com.harvey.samples.core.OrderException"/>

自定义Mock类实现服务降级

在消费服务端本地创建一个实现了服务接口的Mock类,当远程服务不可用时或临时需要停用时,Dubbo框架将会调用mock属性指定的Mock类对应的方法并返回预设值给到用户。

自定义Mock类实现服务降级的步骤如下:

1)首先,将mock属性设置为true

<dubbo:reference id="orderService" interface="com.harvey.samples.client.OrderService" protocol="dubbo" group="one"
                     mock="true"/>

或设置为自定义的Mock类完整名

<dubbo:reference id="orderService" interface="com.harvey.samples.client.OrderService" protocol="dubbo" group="one"
                     mock="com.harvey.samples.core.OrderServiceMock"/>

接着,定义Mock类,实现需要降级的方法,返回预设的值。Mock类的命名规则遵循为服务接口名+Mock后缀,实现服务接口,并有一个无参构造函数。

如果属性mock设置为true的方式,则需要将Mock实现类放在和接口相同的包下。

public class OrderServiceMock implements OrderService {

    //必须有一个无参构造函数
    public OrderServiceMock(){

    }

    @Override
    public Order getOrderInfo(long orderId) throws InterruptedException {
        Order order = new Order();
        order.setOrderId(-1L);
        order.setOrderName("调用失败");
        return order;
    }

    @Override
    public List<Order> listAll() {
        // 返回一个空的列表
        return new ArrayList<>();
    }
}

Dubbo的服务降级采用的是mock机制,可以直接使用其内置的mock实现,也可以自定义本地的Mock类来实现。Dubbo的服务降级的介入节点主要在服务消费者端,对应配置属性为mock,支持接口级别和方法级别两种粒度的服务降级配置。

 

posted @ 2022-03-29 10:31  残城碎梦  阅读(708)  评论(1编辑  收藏  举报