dubbo解析-服务降级原理、Mock功能实现
本文基于dubbo 2.7.5版本代码
当远程服务不可用、网络异常或者远程服务执行异常,dubbo提供了Mock功能,可以实现服务降级。远程服务执行异常是远程服务执行过程中出现错误,向客户端返回Exception异常。
dubbo实现该功能是在类MockClusterInvoker中完成,MockClusterInvoker实现了Invoker接口。
在现有dubbo的SPI机制下,客户端发起任何远程调用,都必须通过MockClusterInvoker。先介绍一下MockClusterInvoker是如何被创建的。
在介绍集群容错的时候,提到过类MockClusterWrapper,该类是包装类。在SPI机制下加载Cluster接口对象的时候,MockClusterWrapper会将Cluster对象封装起来返回调用方,所有对Cluster对象的调用都必须通过MockClusterWrapper。
MockClusterWrapper是在上图蓝色方块中通过SPI创建的。MockClusterWrapper根据对cluster的设置,封装了Cluster对象。MockClusterWrapper的join方法如下:
public <T> Invoker<T> join(Directory<T> directory) throws RpcException { return new MockClusterInvoker<T>(directory,this.cluster.join(directory)); }
代码非常简单。this.cluster.join方法返回一个Cluster Invoker对象,默认是FailoverClusterInvoker。MockClusterWrapper使用MockClusterInvoker对Cluster Invoker对象做了一层封装。之后将MockClusterInvoker对象使用JDK代理再做一次封装,这个JDK代理对象就是客户端调用远程服务时使用的对象了。因此每次客户端访问远程服务时,首先调用MockClusterInvoker的invoke方法。
下面介绍MockClusterInvoker的invoke方法。
invoke方法中首先查看mock参数配置。mock参数在@Reference或者@Service中配置。mock参数可以配置的值以及其作用如下:
- mock=false或者空,不使用服务降级功能,调用封装的Cluster Invoker对象,默认值是false;
- mock=以"force"开头,那么直接使用mock服务;
- mock=其他,那么首先访问远程服务,如果网络不通、访问远程服务失败或者远程服务抛出异常后,再使用mock服务。
因为mock参数非常重要,是客户端能正常访问服务的最后一道防线,为了避免在客户端访问远程服务时才暴露问题,所以mock参数在客户端启动的时候,ReferenceConfig的init方法会调用checkMock方法检查mock参数。checkMock方法的检查流程是:
- normalizeMock方法会对mock参数正则化,正则化的规则是(1)去除多余的不可见字符(2)如果mock=“return ”,则将mock修改为“return null”(3)如果mock以“fail:”或者"force:"开头,则将“fail:”或者"force:"去掉,mock等于“fail:”或者"force:"后面的内容(4)替换return或者throw后面的非法字符(5)如果mock为fail、force、true、default,则将mock统一修改为default。normalizeMock不会对原始mock参数值修改,正则化只是为了后续的检查提供方便。
- 正则化后的mock如果以return开头,则对return后面的内容分析,分析规则比较简单,使用if/else根据可能的值分别判断,比如校验return后面的内容是否是JSON格式,如果是,则调用JSON.parseObject方法解析。
- 正则化后的mock如果以throw开头,那么throw后面跟的必须是Throwable的子类,且必须有一个以字符串为入参的构造方法,否则抛出异常,启动失败。
- 如果上述都不满足,则检查classpath下是否有以接口+Mock为名字的类,而且必须有一个无参构造方法。这里的接口指的是访问远程服务的接口,另外该类必须实现了远程服务的接口。比如客户端要访问远程服务WebsiteProcessor下的一个方法,那么此时classpath下必须要有一个类名为WebsiteProcessorMock,且必须有一个无参构造方法,WebsiteProcessorMock实现了WebsiteProcessor接口。
当配置mock不为false或者空时,使用mock服务都是调用doMockInvoke方法。
doMockInvoke方法头:
private Result doMockInvoke(Invocation invocation, RpcException e)
当配置mock=以"force"开头,入参e是null,否则是异常对象,比如服务超时,e是超时异常对象。
doMockInvoke方法的执行流程是:
- 调用selectMockInvoker方法选择mock的invoker列表;
- 如果上一步的invoker列表是空的,那么创建MockInvoker对象,否则获取列表中的第一个invoker;
- 调用上一步的invoker对象或者MockInvoker对象的invoke方法。invoke方法的返回值作为服务返回值返回客户端。
selectMockInvoker主要调用Directory接口的list方法选择invoker列表,invoker可以简单的认为是远程服务提供者。该方法的流程是:
上图的multiGroup属性表示是否匹配多个组的服务,当配置了group参数且group参数的是“*”或者配置了多个组(组名之间使用","分隔)时,multiGroup为true。
在过滤invoke列表的时候,需要遍历Route对象,默认Route对象有四个。Route对象是在创建RouterChain对象的时候通过SPI加载的。与mock相关的Route对象是MockInvokersSelector。MockInvokersSelector当没有设置invocation.need.mock时,MockInvokersSelector过滤掉mock协议的服务,将非mock协议的服务提供者列表返回,如果设置invocation.need.mock=false,则不对invoker列表做任何过滤,如果设置invocation.need.mock=true,则将mock协议的服务提供者列表返回。关于Route对象后面的文章在做详细介绍。
因为在遍历Route对象前已经设置invocation.need.mock=true,所以MockInvokersSelector只会将mock协议的服务提供者列表返回。mock协议服务提供者用对象MockInvoker表示。
selectMockInvoker方法执行完毕后,接下来就是对MockInvoker对象的invoke方法调用了。
MockInvoker实现了Invoker接口,invoke方法的执行逻辑如下:
上述流程中,在处理以return开头的mock值时,会根据return后面的内容,对返回值做类型上的转换,比如return false,那么返回值value是布尔类型的false,如果return后面是JSON格式,调用JSON.parseObject将其转为对象,返回值value即为该对象,最后还会根据要访问的远程方法返回类型,将返回值value转换为该类型的对象。
- dubbo解析-详解服务目录的原理以及代码实现
- 服务治理中间件 Dubbo 原理解析(Dubbo内核实现)读书笔记
- 3. Dubbo原理解析-Dubbo内核实现之动态编译
- Dubbo原理解析-注册中心之基于dubbo协议的简单注册中心实现
- Dubbo原理解析-注册中心之基于dubbo协议的简单注册中心实现
- Dubbo源码解析 —— 逻辑层设计之服务降级
- 分布式服务框架dubbo原理解析
- 跟着小程学微服务-Mock自动化系统的原理及实现
- Dubbo原理解析-注册中心之基于dubbo协议的简单注册中心实现
- 服务治理中间件 Dubbo 原理解析(代理)读书笔记
- 12. Dubbo原理解析-注册中心之基于dubbo协议的简单注册中心实现
- Java类加载原理解析及怎样自定义Java类实现特殊的功能
- 15. Dubbo原理解析-集群&容错之目录服务Directory
- 19. Dubbo原理解析-通信层之暴露服务
- 1. Dubbo原理解析-Dubbo内核实现之SPI简单介绍
- 8. Dubbo原理解析-服务发布
- 服务降级及dubbo中的实现示例
- Dubbo原理解析-Dubbo内核实现之基于SPI思想Dubbo内核实现
- 微服务架构的核心要点和实现原理解析
- 20. Dubbo原理解析-通信层之引用服务