本地伪装

学习如何使用本地伪装在 Dubbo3 中实现服务降级

功能描述

Dubbo3 中存在一种机制可以实现轻量级的服务降级,即本地伪装1

使用场景

本地伪装通常用于服务降级。例如,对于一个验证服务,当所有服务提供者都挂掉时,如果服务消费者此时发起远程调用,则调用会失败并抛出 RpcException 异常。

为了避免直接抛出异常的这种情况,客户端可以使用本地伪装提供 Mock 数据并返回授权失败。

使用方法

启用 Mock 配置

在 Spring XML 配置文件中以以下方式配置

<dubbo:reference interface="com.foo.BarService" mock="true" />

或者

<dubbo:reference interface="com.foo.BarService" mock="com.foo.BarServiceMock" />

在项目中提供 Mock 实现2

package com.foo;
public class BarServiceMock implements BarService {
    public String sayHello(String name) {
        // You can fake fault-tolerant data, this method is only executed when RpcException occurs
        return "fault tolerance data";
    }
}

使用 return 关键字模拟返回值

使用 return 返回一个由字符串表示的对象作为 Mock 的返回值。合法的字符串可以是

  • empty: 代表空,返回基本类型的默认值,集合类的空值,自定义实体类的空对象3
  • null: 返回 null
  • true: 返回 true
  • false: 返回 false
  • JSON 字符串: 返回 JSON 字符串反序列化后得到的对象

例如,如果服务的消费者经常需要使用 try-catch 来捕获异常,例如

public class DemoService {

    public Offer findOffer(String offerId) {
        Offer offer = null;
        try {
            offer = offerService. findOffer(offerId);
        } catch (RpcException e) {
            logger. error(e);
        }

        return offer;
    }
}

那么考虑改为 Mock 实现,并在 Mock 实现中 return null。如果只是想简单地忽略异常,在 2.0.11 及以上版本中可以使用

<dubbo:reference interface="com.foo.BarService" mock="return null" />

使用 throw 关键字 Mock 抛出异常

使用 throw 返回一个 Exception 对象作为 Mock 的返回值。

调用失败时抛出默认的 RPCException


<dubbo:reference interface="com.foo.BarService" mock="throw"/>

调用发生错误时,抛出指定的 Exception4


<dubbo:reference interface="com.foo.BarService" mock="throw com.foo.MockException"/>

使用 force 和 fail 关键字配置 Mock 的行为

force: 表示强制使用 Mock 行为,在这种情况下不会进行远程调用。

fail: 与默认行为一致,只有当远程调用发生错误时才会使用 Mock 行为。也就是说,在配置时实际上可以不使用 fail 关键字,而直接使用 throwreturn

force:fail: 都支持与 throwreturn 结合使用。

强制返回指定的值


<dubbo:reference interface="com.foo.BarService" mock="force:return fake"/>

强制抛出指定的异常


<dubbo:reference interface="com.foo.BarService" mock="force:throw com.foo.MockException"/>

调用失败时返回指定的值


<dubbo:reference interface="com.foo.BarService" mock="fail:return fake"/>

<!-- Equivalent to the following writing -->
<dubbo:reference interface="com.foo.BarService" mock="return fake"/>

调用失败时抛出异常


<dubbo:reference interface="com.foo.BarService" mock="fail:throw com.foo.MockException"/>

<!-- Equivalent to the following writing -->
<dubbo:reference interface="com.foo.BarService" mock="throw com.foo.MockException"/>

在方法级别配置 Mock

Mock 可以指定在方法级别,假设 com.foo.BarService 上有几个方法,我们可以分别为 sayHello() 方法指定 Mock 行为。

具体的配置如下。在这个例子中,无论何时调用 sayHello(),它都会强制返回“fake”


<dubbo:reference id="demoService" check="false" interface="com.foo.BarService">
    <dubbo:parameter key="sayHello.mock" value="force:return fake"/>
</dubbo:reference>

注意事项


  1. Mock 是 Stub 的一个子集,它方便服务提供者在客户端实现容错逻辑。因为通常需要在 RpcException(例如网络故障、超时等)发生时执行容错,而业务异常(例如登录用户名和密码错误)则不需要容错。如果使用 Stub,则可能需要捕获并依赖 RpcException 类,但使用 Mock 则不需要依赖 RpcException,因为它的约定是在 RpcException 发生时才执行。 ↩︎

  2. 在接口旁边,放置一个实现 BarService 接口并具有无参数构造函数的 Mock 实现。同时,如果在配置文件中没有显式指定 Mock 类,那么需要确保 Mock 类的全限定类名是 原始全限定类名+Mock 的形式,例如 com.foo.BarServiceMock,否则 Mock 会失败。 ↩︎

  3. 如果返回值是实体类,则会返回一个带有默认值的空对象,而不是 null。 ↩︎

  4. 自定义异常必须具有以 String 作为输入参数的构造函数,它将用于接收异常信息。 ↩︎


上次修改时间:2023 年 1 月 2 日:Enhance en docs (#1798) (95a9f4f6c1c)