美文网首页
【dubbo源码】18. 服务消费方:集群容错之本地伪装mock

【dubbo源码】18. 服务消费方:集群容错之本地伪装mock

作者: 天还下着毛毛雨 | 来源:发表于2021-07-21 15:10 被阅读0次

本地伪装使用方式

如何在 Dubbo 中利用本地伪装实现服务降级

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

配置
<dubbo:reference interface="com.foo.BarService" mock="true" />
<dubbo:reference interface="com.foo.BarService" mock="com.foo.BarServiceMock" />
return
  • empty: 代表空,基本类型的默认值,或者集合类的- 空值
  • null: null
  • true: true
  • false: false
  • JSON 格式: 反序列化 JSON 所得到的对象
throw

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

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

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

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

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

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

Dubbo调用流程

image

源码分析

Cluster接口对invoker对象的包装

在@Referce会用jdk创建代理实例,然后InvokeHanlder的invoke方法会调用成员变量bean的方法,bean由ReferenceConfig根据配置再次生成代理,最后注入到属性上。

创建的时候会一个可执行的invoker对象

ReferenceConfig.createProxy
image
RegistryProtocol.refer
image
根据directory经过Cluster修饰返回修饰过后Invoker对象
image

Cluster成员变量

image

肯定是SPI工厂通过ioc注入进来的

image

注入进来的肯定是动态生成的类,里面获取的实例肯定是包装类

image

包装类持有Cluster接口上@Spi默认指定的类

image image

最后才是服务列表Directory实例,返回

image

对invoker对象进行代理

获取到Cluster实例包装过后的invoker之后,需要调用代理工厂,生成代理

image

通过javassist技术动态生成,对需要调用的目标类的包装wrapper对象类,然后new 出一个抽象类AbstractProxyInvoker的的实例,重写的的invoker里会由wrapper对象调用invoker的具体方法。

image

远程服务代理实例发起tcp请求之前的调用流程

image

在调用原始invoker之前会先调用Cluster接口实例的invoker方法,附加集群容错的逻辑。

MockClusterInvoker

返回MockClusterInvoker实例,持有默认Cluster实例的FailoverClusterInvoker的引用和RegistryDirectory的引用

FailoverClusterInvoker  :当前处理完,由下一个ClusterInvoker实例进行对原始invoker进行修饰
RegistryDirectory       :包含服务列表
image

MockClusterInvoker.invoke()

先是从url中获取mock的配置,如果没有配置,直接不做任何其他逻辑,调下一个Cluster实例修饰的invoker的invoke方法。

image

1. force 强制降级

如果你的mock配置以force开头,比如

@Reference(mock = "force:return fake")
private UserService userService;

则会走强制降级的判断,就不会调用后端服务,直接返回你配置的返回值

image
  1. 创建MockInvoker对象

    先根据invocation里的method去本地服务列表里 拿protocol为mock的invokers,

    image image image

    从RegistryDirectory的methodInvokerMap根据methodName拿invokers

    image

    拿到之后会进行路由,这里起作用的路由类是MockInvokersSelector,会过滤掉所有协议不是mock的invoker,最后返回的inv okers是null

    image image image

    拿不到protocol为mock的invoker,就会new出 MockInvoker实例,最后调用MockInvoker.invoke方法

    image
  2. MockInvoker.invoke返回降级结果

    1. 如果配置的是force : return xxxx

      就会解析出return 后面的值,然后判断出类型,创造出对应类型和值的实例,包装到RpcResult中,返回

      image

      这里解析出来的是个字符串,直接返回

      image
    2. force:throw com.xx.XXException

      这种表示不发起远程调用,直接强制抛出异常
      根据throw后面的全限定性异常类名,new 出Throwable实例,throw new RpcException()

      image
    3. force:true / force:default / force:com.lb.mocrk.XXXServiceXX

      这是表示强制调本地的某个类的方法,来进行伪装

      这个类要和 远程实例类实现同一个接口,这样才能与远程实例类有同样的方法,走对应方法的降级方法

      image

      getInvoker(mock)根据的你的mock配置获取mock实现类实例

      先是获取到服务接口名

      image

      如果你配置的mock属性的值是true / defalut ,就默认为接口名+ 'Mock' 作为mock的实现类

      image image

      如果配置的是 一个全限定性类名,就直接用这个,最后是校验最终得到的mock类是否是服务接口的子类,校验通过 ,mockClass.newInstance()实例化返回

      image

      得到mock类实例后,用代理包装成invoker对象

      image

      最终就直接调mock实例的降级方法,不会发起远程调用

2. fail 异常降级

如果你的mock配置以fail开头,比如

@Reference(mock = "fail:return fake")
private UserService userService;

和强制降级不同,会先发起远程调用,如果捕获到异常,再走和强制降级一样的降级逻辑

image

相关文章

网友评论

      本文标题:【dubbo源码】18. 服务消费方:集群容错之本地伪装mock

      本文链接:https://www.haomeiwen.com/subject/eqyjmltx.html