RPC之总体架构

Posted lovejune

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RPC之总体架构相关的知识,希望对你有一定的参考价值。

要完成一个高可用、高性能的RPC框架,需要对其架构的设计进行梳理,这里参考xxl-rpc框架,对整个项目进行梳理。

技术图片

 

 以上就是项目的整个构架,分为四个部分;

第一个是服务发布与引入,基于JDK动态代理以及Spring实现;包括invoker和provider。

第二个部分是服务注册,基于zookeeper实现;

第三部分是远程调用,基于并发编程基础知识实现;这里最为复杂,使用了分层的模式。

第四部分是远程通信,基于Netty实现。

 


 


 

服务引入

服务引入的实质就是输入请求,然后得到请求回来的对象。

创建一个处理引入的Bean类,属性是请求时需要的数据,包括:

1.网络传输的组件:Netty等,比如MiNA等

2.序列化方式,HESSIAN等,比如JACKSON

3.调用的方式,一共有四种,同步、异步、回调、单一长连接

4.负载均衡的方式,一共5种,RANDOM、ROUND、LRU、LFU、CONSISTENT_HASH

5.接口名称

6.超时时间,若超时,则请求报错

7.请求地址:ip+prot

8.进入token

9.是否使用回调

10.调用工厂,如果没有,默认实例化工厂。

 

返回的数据当然就是客户端所需要的对象。

这里请求和返回的操作,是该类的getObject方法执行。

分析:getObject方法是一个动态代理的过程,即给定一个接口,将接口实现。因此,使用动态代理来获取代理的对象。

简单来说,当得到了接口的所有信息:接口名,方法名,方法类型以及方法属性值。那么就可以去对服务端发起请求了。

这里需要注意几点,客户端发起请求不一定会将那些属性都配置上,因此,需要考虑各种配置不同的情况,应该做的操作

动态代理的意义是:当我们在客户端调用哪个方法,哪个方法被代理,传入Proxy函数的就是哪个方法,而不是代理整个类。

步骤1:接口名是一定要配置的,否则根本不知道请求什么,   

若类名是一个通用的业务类,则转向得到这一接口中方法的特定请求(比如在通用业务类接口方法中定义了所要调用的业务的类名,方法和参数等),

若类名是一个Object类,则需要抛出异常,这种类不能当做业务类。

步骤2:有可能只配置了接口名,但没有配置请求地址,但不代表一定会出错,这里就是使用注册服务的好处,注册服务可以管理我们的各种请求地址,和请求的类;

若没有请求地址,则看看注册服务中有没有现在请求的类(一般会通过类名和版本号按照一定的规则形成一个key值存在注册服务中),若找到这个key,就能够得到所请求类的请求地址。

但请求地址可能没有,抛异常;可能有一个,就把这个当做请求地址;若有多个,就要调用负载均衡,让它来决定请求哪个。

步骤3:将请求封装起来,这里需要一个请求的封装类, 

需要封装的内容包括:请求的id(通过该id可以在返回响应时获得同步的响应)、请求创建时间、请求的进入token、请求的类名、方法名、方法属性类型、方法属性。

步骤4:可以发送请求了,可以选择四种不同的调用方式,同步、异步、回调、单一长连接

  同步方式

  由于netty的NIO是异步模型,在调用的同时,并不会阻塞获取调用结果;因此需要实现sync-over-async(在异步中同步),其过程如下:

  调用XxlRpcFutureResponse类的get方法

  该类继承了Future类,并实现了其方法,可以使用其get方法来实现同步,即,如果done不为true,一直使线程处于阻塞状态,然后当达到超时时间后,主动唤醒该线程,然后就可以得到响应对象了。

  具体来说,当客户端netty的nio线程组发送的请求后,netty的服务端会异步返回response,然后该响应会被传入一个调用工厂的唤醒调用的方法中,在该方法中,取出XxlRpcFutureResponse类,并将其设置response,然后唤醒线程,此时就可以通过get方法来得到response,这样通过唯一的resquesId就可以同步唯一的得到response对象了。

  为啥说实现了同步,即在发送请求以后,线程阻塞,无法接收到其他所有的响应,只有这个响应收到或抛异常后,才能收到其他的响应。如果是采用异步方式,则会出现请求得到的是同一个响应的情况。

 

  异步方式

   在发送了请求之后,不马上得到返回的结果,而是在需要的时候再取,这时候就需要用异步的方式,所谓异步,就是利用一个InvokerFuture对象,来包装已经得到响应的respnsefuture对象,然后将InvokerFuture放到ThreadLocal里面,等需要的时候,取出来使用。

  

  callback方式

  这种方式也是异步的,而且是需要等待请求返回,因此,会造成异步的请求返回有多个,请求不及时。

  过程是,设置一个ConcurrentMap集合,先将callback和request存入futureresponse中,然后将futureresponse放入ConcurrentMap集合中,这样,当我们发送了请求之后,请求会从handle类中,找到read方法,然后read方法会调用notify函数,将返回的response对象取到,同时,notify函数还会把futureresponse从ConcurrentMap集合中取出来,然后把callback从futureresponse中取出,最后调用callback中的方法。这样就会准确的执行callback函数了。

  

  oneway方式

  暂时不清楚

 

 

以上就是rpc的四种连接方式。

 

以上是关于RPC之总体架构的主要内容,如果未能解决你的问题,请参考以下文章

RPC框架之Thrift架构及源码解读

RPC框架之Thrift架构及源码解读

面向服务架构之RPC原理与实例

事件驱动的微服务-总体设计

网络RPC通信之Apache Thrift

常用RPC框架及如何设计一个RPC框架