zoukankan      html  css  js  c++  java
  • 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的四种连接方式。

  • 相关阅读:
    [模仿]Google Doodles 的春分和秋分
    [模仿]canvas视频拼图
    SQL--from w3c school
    txt文件导入mysql
    公益图书馆-基本环境搭建及代码规范
    IP地址
    Android基础_1
    Android_输入输出流
    设计模式(2):观察者模式-2 (委托、事件)
    小张日记 一 正式场合说话要正式
  • 原文地址:https://www.cnblogs.com/lovejune/p/12446123.html
Copyright © 2011-2022 走看看