浅析dubbo原理和实现 转

出处: 浅析dubbo原理和实现

一、Duboo基本概念解释

Dubbo是一种分布式服务框架。 Webservice也是一种服务框架,但是webservice并不是分布式的服务框架,他需要结合F5实现负载均衡。因此,dubbo除了可以提供服务之外,还可以实现软负载均衡。它还提供了两个功能Monitor 监控中心和调用中心。这两个是可选的,需要单独配置。

Dubbo的计数架构图如下:

我们解释以下这个架构图:

  Consumer服务消费者,Provider服务提供者。Container服务容器。消费当然是invoke提供者了,invoke这条实线按照图上的说明当然同步的意思了,多说一句,在实际调用过程中,Provider的位置对于Consumer来说是透明的,上一次调用服务的位置(IP地址)和下一次调用服务的位置,是不确定的。这个地方就是实现了软负载。

  Monitor这是一个监控,图中虚线表明Consumer 和Provider通过异步的方式发送消息至Monitor,Consumer和Provider会将信息存放在本地磁盘,平均1min会发送一次信息。Monitor在整个架构中是可选的(图中的虚线并不是可选的意思),Monitor功能需要单独配置,不配置或者配置以后,Monitor挂掉并不会影响服务的调用

二 分析源代码,基本原理如下:

扫描二维码关注公众号,回复: 9651120 查看本文章

  1:client一个线程调用远程接口,生成一个唯一的ID(比如一段随机字符串,UUID等),Dubbo是使用AtomicLong从0开始累计数字的
  2:将打包的方法调用信息(如调用的接口名称,方法名称,参数值列表等),和处理结果的回调对象callback,全部封装在一起,组成一个对象object
  3:向专门存放调用信息的全局ConcurrentHashMap里面put(ID, object)
  4:将ID和打包的方法调用信息封装成一对象connRequest,使用IoSession.write(connRequest)异步发送出去
  5:当前线程再使用callback的get()方法试图获取远程返回的结果,在get()内部,则使用synchronized获取回调对象callback的锁, 再先检测是否已经获取到结果,如果没有,然后调用callback的wait()方法,释放callback上的锁,让当前线程处于等待状态。
  6:服务端接收到请求并处理后,将结果(此结果中包含了前面的ID,即回传)发送给客户端,客户端socket连接上专门监听消息的线程收到消息,分析结果,取到ID,再从前面的ConcurrentHashMap里面get(ID),从而找到callback,将方法调用结果设置到callback对象里。
  7:监听线程接着使用synchronized获取回调对象callback的锁(因为前面调用过wait(),那个线程已释放callback的锁了),再notifyAll(),唤醒前面处于等待状态的线程继续执行(callback的get()方法继续执行就能拿到调用结果了),至此,整个过程结束。

 当前线程怎么让它“暂停”,等结果回来后,再向后执行?
    答:先生成一个对象obj,在一个全局map里put(ID,obj)存放起来,再用synchronized获取obj锁,再调用obj.wait()让当前线程处于等待状态,然后另一消息监听线程等到服 务端结果来了后,再map.get(ID)找到obj,再用synchronized获取obj锁,再调用obj.notifyAll()唤醒前面处于等待状态的线程。

 正如前面所说,Socket通信是一个全双工的方式,如果有多个线程同时进行远程方法调用,这时建立在client server之间的socket连接上会有很多双方发送的消息传递,前后顺序也可能是乱七八糟的,server处理完结果后,将结果消息发送给client,client收到很多消息,怎么知道哪个消息结果是原先哪个线程调用的?
    答:使用一个ID,让其唯一,然后传递给服务端,再服务端又回传回来,这样就知道结果是原先哪个线程的了。

 

三、远程调用细节

服务提供者暴露一个服务的详细过程:

 

上图是服务提供者暴露服务的主过程: 
  首先ServiceConfig类拿到对外提供服务的实际类ref,然后将ProxyFactory类的getInvoker方法使用ref生成一个AbstractProxyInvoker实例,到这一步就完成具体服务到invoker的转化。接下来就是Invoker转换到Exporter的过程。 
  Dubbo处理服务暴露的关键就在Invoker转换到Exporter的过程,下面我们以Dubbo和rmi这两种典型协议的实现来进行说明 

1. Dubbo的实现: 

  Dubbo协议的Invoker转为Exporter发生在DubboProtocol类的export方法,它主要是打开socket侦听服务,并接收客户端发来的各种请求,通讯细节由dubbo自己实现。 

2. Rmi的实现: 

  RMI协议的Invoker转为Exporter发生在RmiProtocol类的export方法,他通过Spring或Dubbo或JDK来实现服务,通讯细节由JDK底层来实现。

服务消费者消费一个服务的详细过程:

上图是服务消费的主过程: 
  首先ReferenceConfig类的init方法调用Protocol的refer方法生成Invoker实例。接下来把Invoker转为客户端需要的接口。

附:发布服务配置文件: 

  •  使用dubbo发布服务 
<!-- 提供方应用信息,用于计算依赖关系 -->
<dubbo:application name="some-manager" />
<dubbo:registry protocol="zookeeper"
address="192.168.25.154:2181,192.168.25.154:2182,192.168.25.154:2183" />
<!-- 用dubbo协议在20880端口暴 露服务 -->
<dubbo:protocol name="dubbo" port="20880" />
<!-- 声明需要暴露的服务接口 -->
<dubbo:service interface="com.xx.service.ItemService" ref="itemServiceImpl"  timeout=“3000”/>//设置服务超时时间:服务调用超时时间默认1秒
  • (消费)调用服务:
<!-- 引用dubbo服务 -->
<dubbo:application name="some-manager-web"/>
   <dubbo:registry protocol="zookeeper" address="192.168.25.154:2181,192.168.25.154:2182,192.168.25.154:2183"/>
<dubbo:reference interface="com.xx.service.ItemService" id="itemService" />

接口要么是采用服务方的接口API依赖,要么是复制相同的引用接口API到消费端,以便调用。

  • 添加dubbo的依赖 加入dubbo相关的jar包。服务层、表现层都添加。
<!-- dubbo相关 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>dubbo</artifactId>
<!-- 排除依赖 -->
<exclusions>
    <exclusion>
        <groupId>org.springframework</groupId>
       <artifactId>spring</artifactId>
   </exclusion>
    <exclusion>
         <groupId>org.jboss.netty</groupId>
         <artifactId>netty</artifactId>
      </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.apache.zookeeper</groupId>
     <artifactId>zookeeper</artifactId>
</dependency>
<dependency>
     <groupId>com.github.sgroschupf</groupId>
      <artifactId>zkclient</artifactId>
</dependency>

猜你喜欢

转载自www.cnblogs.com/myseries/p/12439171.html