SpringCloudRPC 远程调用核心原理:Feign 远程调用的执行流程
以上 4 步基本上就是 Spring Cloud 中的 Feign 远程调用的执行流程。
然而,默认的基于 FeignInvocationHandler 调用处理器的执行流程在运行机制和调用性能上都满足不了生产环境的要求,大致原因有以下两点:
(1)在远程调用过程中没有异常的熔断监测和恢复机制。
(2)没有用到高性能的 HTTP 连接池技术。
接下来将为大家介绍一种结合 Hystrix 进行 RPC 保护的远程调用处理流程。在该流程中所使用的 InvocationHandler 调用处理器叫作 HystrixInvocationHandler 调用处理器。
这里作为铺垫,首先为大家介绍 HystrixInvocationHandler 调用处理器本身的具体实现。
与 HystrixInvocationHandler 相关的远程调用执行流程
=====================================
HystrixInvocationHandler 调用处理器类位于 feign.hystrix 包中,其字节码文件不是处于 feign 核心包 feign-core-*.jar 中,而是在扩展包 feignhystrix-*.jar 中。这里的*表示的是与 Spring Cloud 版本配套的版本号,当 Spring Cloud 的版本为 Finchley.RELEASE 时,feign-core 和 feign-hystrix 两个 JAR 包的版本号都为 9.5.1。
HystrixInvocationHandler 是具备 RPC 保护能力的调用处理器,它实现了 InvocationHandler 接口,对接口的 invoke(...)抽象方法的实现如下:
package feign.hystrix;
//省略 import
final class HystrixInvocationHandler implements InvocationHandler {
...
//... Map 映射:Key 为 RPC 方法的反射实例,value 为方法处理器
private final Map<Method, MethodHandler> dispatch;
...
public Object invoke(Object proxy, final Method method, final Object[] args) throws Throwable {
//创建一个 HystrixCommand 命令,对同步方法调用器进行封装
HystrixCommand<Object> hystrixCommand =
new HystrixCommand<Object>
( (Setter)this.setterMethodMap.get(method) )
{
protected Object run() throws Exception {
try {
SynchronousMethodHandler handler=HystrixInvocationHandler.this.dispatch.get(method);
return handler.invoke(args);
} catch (Exception var2) {
throw var2;
} catch (Throwable var3) {
throw (Error)var3;
}
}
protected Object getFallback() {
//省略 HystrixCommand 的异常回调
}
};
//根据 method 的返回值类型,或返回 hystrixCommand,或直接执行
if (this.isReturnsHystrixCommand(method)) {
return hystrixCommand;
} else if (this.isReturnsObservable(method)) {
return hystrixCommand.toObservable();
} else if (this.isReturnsSingle(method)) {
return hystrixCommand.toObservable().toSingle();
} else {
//直接执行
return this.isReturnsCompletable(method) ?
hystrixCommand.toObservable().toCompletable() : hystrixCommand.execute();
}
...
}
HystrixInvocationHandler 调用处理器与默认调用处理器 FeignInvocationHandler 有一个共同点:都有一个非常重要的 Map 类型成员 dispatch 映射,保存着 RPC 方法反射实例到 MethodHandler 方法处理器的映射。
在源码中,HystrixInvocationHandler 的 invoke(...)方法会创建 hystrixCommand 命令实例,对从 dispatch 获取的 SynchronousMethodHandler 实例进行封装,然后对 RPC 方法实例 method 进行判断,判断是直接返回 hystrixCommand 命令实例,还是立即执行其 execute()方法。默认情况下,都是立即执行它的 execute()方法。
HystrixCommand 具备熔断、隔离、回退等能力,如果它的 run()方法执行发生异常,就会执行 getFallback()失败回调方法,这一点后面会详细介绍。
回到 uaa-provider 服务中 DemoClient 动态代理实例的 hello()方法的具体执行过程,在执行命令处理器 hystrixCommand 实例的 run()方法时,步骤如下:
(1)根据 RPC 方法 DemoClient.hello()的反射实例在 dispatch 映射对象中找到对应的方法处理器 MethodHandler 实例。
(2)调用 MethodHandler 方法处理器的 invoke(...)方法完成实际的 hello()方法所配置的远程 URL 的 HTTP 请求和结果的处理。
如果 MethodHandler 内的 RPC 调用出现异常,比如远程 server 宕机、网络延迟太大而导致请求超时、远程 server 来不及响应等,hystrixCommand 命令器就会调用失败回调方法 getFallback()返回回退结果。
而 hystrixCommand 的 getFallback()方法最终会调用配置在 RPC 接口 @FeignClient 注解的 fallback 属性上的失败回退类中对应的回退方法,执行业务级别的失败回退处理。
使用 HystrixInvocationHandler 方法处理器进行远程调用,总体流程与使用默认的方法处理器 FeignInvocationHandler 进行远程调用大致是相同的。
以 uaa-provider 模块的 DemoClient 中 hello()方法的远程调用执行过程为例,进行整体流程的展示,具体的时序图如图 3-26 所示。
图 3-26 与 HystrixInvocationHandler 相关的远程调用执行流程
总体来说,使用 HystrixInvocationHandler 处理器的执行流程与使用 FeignInvocationHandler 默认的调用处理器相比大致是相同的。不同的是,HystrixInvocationHandler 增加了 RPC 的保护机制。
Feign 远程调用的完整流程及其特性
==================
Feign 是一个声明式的 RPC 调用组件,它整合了 Ribbon 和 Hystrix,使得服务调用更加简单。Feign 提供了 HTTP 请求的模板,通过编写简单的接口和方法注解就可以定义好 HTTP 请求的参数、格式、地址等信息。
Feign 极大地简化了 RPC 远程调用,大家只需要像调用普通方法一样就可以完成 RPC 远程调用。
Feign 远程调用的核心是通过一系列封装和处理,将以 JAVA 注解方式定义的 RPC 方法最终转换成 HTTP 请求,然后将 HTTP 请求的响应结果解码成 POJO 对象返回给调用者。
Feign 远程调用的完整流程如图 3-27 所示。
图 3-27 Feign 远程调用的完整流程
从图 3-27 可以看到,Feign 通过对 RPC 注解的解析将请求模板化。当实际调用时传入参数,再根据参数应用到请求模板上,进而转化成真正的 Request 请求。通过 Feign 及其动态代理机制,Java 开发人员不用再通过 HTTP 框架封装 HTTP 请求报文的方式完成远程服务的 HTTP 调用。
Spring Cloud Feign 具有如下特性:
(1)可插拔的注解支持,包括 Feign 注解和 Spring MVC 注解。
(2)支持可插拔的 HTTP 编码器和解码器。
(3)支持 Hystrix 和它的 RPC 保护机制。(4)支持 Ribbon 的负载均衡。(5)支持 HTTP 请求和响应的压缩。总体来说,使用 Spri
ng Cloud Feign 组件本身整合了 Ribbon 和 Hystrix,可设计一套稳定可靠的弹性客户端调用方案,避免整个系统出现雪崩效应。
评论