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

dubbo rpc重试 dubbo的rpc调用_Server

pack:包装

 

 

RPC 工作原理

RPC的设计由Client,Client stub,Network ,Server stub,Server构成。 其中Client就是用来调用服务的,Cient stub是用来把调用的方法和参数序列化的(因为要在网络中传输,必须要把对象转变成字节),Network用来传输这些信息到Server stub, Server stub用来把这些信息反序列化的,Server就是服务的提供者,最终调用的就是Server提供的方法。

dubbo rpc重试 dubbo的rpc调用_服务端_02

  1. Client像调用本地服务似的调用远程服务;
  2. Client stub接收到调用后,将方法、参数序列化
  3. 客户端通过sockets将消息发送到服务端
  4. Server stub 收到消息后进行解码(将消息对象反序列化)
  5. Server stub 根据解码结果调用本地的服务
  6. 本地服务执行(对于服务端来说是本地执行)并将结果返回给Server stub
  7. Server stub将返回结果打包成消息(将结果消息对象序列化)
  8. 服务端通过sockets将消息发送到客户端
  9. Client stub接收到结果消息,并进行解码(将结果消息反序列化)
  10. 客户端得到最终结果。

 

 

 

Dubbo中的RPC调用流程图

dubbo rpc重试 dubbo的rpc调用_Server_03

 

Dubbo官网

dubbo rpc重试 dubbo的rpc调用_服务端_04

 

 

 

一、客户端执行流程

执行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)

执行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是其接口

dubbo rpc重试 dubbo的rpc调用_服务端_05