Dubbo-RPC调用流程(图)
RPC 起源
RPC 这个概念术语在上世纪 80 年代由 Bruce Jay Nelson 提出。这里我们追溯下当初开发 RPC 的原动机是什么?在 Nelson 的论文 "Implementing Remote Procedure Calls" 中他提到了几点:
- 简单:RPC 概念的语义十分清晰和简单,这样建立分布式计算就更容易。
- 高效:过程调用看起来十分简单而且高效。
- 通用:在单机计算中过程往往是不同算法部分间最重要的通信机制。
通俗一点说,就是一般程序员对于本地的过程调用很熟悉,那么我们把 RPC 作成和本地调用完全类似,那么就更容易被接受,使用起来毫无障碍。Nelson 的论文发表于 30 年前,其观点今天看来确实高瞻远瞩,今天我们使用的 RPC 框架基本就是按这个目标来实现的。
Nelson 的论文中指出实现 RPC 的程序包括 5 个部分:
- User
- User-stub
- RPCRuntime
- Server-stub
- Server
pack:包装
RPC 工作原理
RPC的设计由Client,Client stub,Network ,Server stub,Server构成。 其中Client就是用来调用服务的,Cient stub是用来把调用的方法和参数序列化的(因为要在网络中传输,必须要把对象转变成字节),Network用来传输这些信息到Server stub, Server stub用来把这些信息反序列化的,Server就是服务的提供者,最终调用的就是Server提供的方法。
- Client像调用本地服务似的调用远程服务;
- Client stub接收到调用后,将方法、参数序列化
- 客户端通过sockets将消息发送到服务端
- Server stub 收到消息后进行解码(将消息对象反序列化)
- Server stub 根据解码结果调用本地的服务
- 本地服务执行(对于服务端来说是本地执行)并将结果返回给Server stub
- Server stub将返回结果打包成消息(将结果消息对象序列化)
- 服务端通过sockets将消息发送到客户端
- Client stub接收到结果消息,并进行解码(将结果消息反序列化)
- 客户端得到最终结果。
Dubbo中的RPC调用流程图
Dubbo官网
一、客户端执行流程
执行main(String[])
首先服务消费者通过代理对象 Proxy 发起远程调用,即demoService是一个代理bean,执行proxy0.sayHello(String) ,在sayHello方法中当执行到handler.invoke(this, methods[0], args)时
1.调用InvocationHandler
执行InvokerInvocationHandler.invoke(Object, Method, Object[])
2.调用invoker
执行MockClusterInvoker<T>.invoke(Invocation)
执行服务降级FailoverClusterInvoker<T>(AbstractClusterInvoker<T>).invoke(Invocation)
执行MockClusterInvoker<T>.invoke(Invocation)
执行服务降级FailoverClusterInvoker<T>(AbstractClusterInvoker<T>).invoke(Invocation)
执行RegistryDirectory$InvokerDelegate<T>(InvokerWrapper<T>).invoke(Invocation)
3.过滤器链处理
ConsumerContextFilter.invoke(Invoker<?>, Invocation)FutureFilter.invoke(Invoker<?>, Invocation)MonitorFilter.invoke(Invoker<?>, Invocation)
4.调用invoker
ListenerInvokerWrapper<T>.invoke(Invocation)DubboInvoker<T>(AbstractInvoker<T>).invoke(Invocation)
5.调用ExchangeClient
ReferenceCountExchangeClient.request(Object, int)HeaderExchangeClient.request(Object, int)
6.执行ExchangeChannel
HeaderExchangeChannel.request(Object, int),执行channel.send方法向服务端发起请求
二、服务提供者执行流程
1.当服务端接收到来自客户端的请求后,开始执行ChannelEventRunnable中的run() 方法
2.执行ChannelHandler
DecodeHandler.received(Channel, Object)HeaderExchangeHandler.received(Channel, Object)HeaderExchangeHandler.handleRequest(ExchangeChannel, Request)
3.执行Protocol
DubboProtocol$1.reply(ExchangeChannel, Object)
4.过滤器链处理
EchoFilter.invoke(Invoker<?>, Invocation)ClassLoaderFilter.invoke(Invoker<?>, Invocation)GenericFilter.invoke(Invoker<?>, Invocation)ContextFilter.invoke(Invoker<?>, Invocation)TraceFilter.invoke(Invoker<?>, Invocation)TimeoutFilter.invoke(Invoker<?>, Invocation)MonitorFilter.invoke(Invoker<?>, Invocation)ExceptionFilter.invoke(Invoker<?>, Invocation)
5.执行Invoker调用
RegistryProtocol$InvokerDelegete<T>(InvokerWrapper<T>).invoke(Invocation)DelegateProviderMetaDataInvoker<T>.invoke(Invocation)
6.代理类调用
JavassistProxyFactory$1(AbstractProxyInvoker<T>).invoke(Invocation)
7.Wrapper调用方法
Wrapper1.invokeMethod(Object, String, Class[], Object[])
8.执行Impl的调用
DemoServiceImpl.sayHello(String)
说明:
服务消费者执行如下代码时
DemoService demoService = (DemoService) context.getBean("demoService");
String hello = demoService.sayHello("world");
获得demoService代理类,执行hello方法直接调用其代理类的sayHello方法
public java.lang.String sayHello(java.lang.String arg0){ Object[] args = new Object[1]; args[0] = ($w)$1; Object ret = handler.invoke(this, methods[0], args); return (java.lang.String)ret; }
handler是一个InvokerInvocationHandler类型,InvocationHandler是其接口