zoukankan      html  css  js  c++  java
  • Dubbo使用及底层通信原理

     Dubbo采用的是一种非常简单的模型,要么是提供方提供服务,要么是消费方消费服务,所以基于这一点可以抽象出服务提供方(Provider)和服务消费方(Consumer)两个角色。dubbo除了可以提供服务之外,还可以实现软负载均衡。它还提供了两个功能Monitor 监控中心和调用中心。这两个是可选的,需要单独配置。

    常用场景:

    Dubbo采用单一长连接和NIO异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况

    Dubbo原理

       

    1. 节点角色说明

    Provider:暴露服务的服务提供方

    Consumer:调用远程服务的服务消费方

    Registry:服务注册与发现的注册中心(Provider将服务暴露给它,Consumer在这里查找所需服务)

    Monitor:统计服务的调用次数和调用事件的监控中心

    Cotainer:服务运行容器,常见的容器有Spring容器。

    2. 原理

    整个发布-订阅的过程可以简单的理解为生产者-消费者模型+注册中心+监控中心:

    • 启动容器,加载,运行服务提供者。
    • 服务提供者在启动时,在注册中心发布注册自己提供的服务。
    • 服务消费者在启动时,在注册中心订阅自己所需的服务。

    如果考虑失败或变更的情况,就需要考虑下面的过程。

    • 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
    • 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
    • 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

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

    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()方法继续执行就能拿到调用结果了),至此,整个过程结束。

    思考

    了解了前面的原理部分,思考几个问题考察一下自己是否真的懂了.

    1. 当前线程怎么让它“暂停”,等结果回来后,再向后执行?

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

    【后面这句是废话】回想之前做项目时,需在前台调用某一服务(该服务要求在后一服务前发生),当时还不懂dubbo,以为调用服务及其相应的行为都是同步的,没有使用嵌套,结果导致代码逻辑未达到预期设想。

    2. Socket通信是一个全双工的方式,如果有多个线程同时进行远程方法调用,这时建立在client server之间的socket连接上会有很多双方发送的消息传递,前后顺序也可能是乱七八糟的,server处理完结果后,将结果消息发送给client,client收到很多消息,怎么知道哪个消息结果是原先哪个线程调用的?

    答:使用一个ID,让其唯一,然后传递给服务端,再服务端又回传回来,这样就知道结果是原先哪个线程的了。

    参考文章列表:

    https://blog.csdn.net/en_joker/article/details/89946034

    https://segmentfault.com/a/1190000019896723

  • 相关阅读:
    2. Add Two Numbers
    1. Two Sum
    22. Generate Parentheses (backTracking)
    21. Merge Two Sorted Lists
    20. Valid Parentheses (Stack)
    19. Remove Nth Node From End of List
    18. 4Sum (通用算法 nSum)
    17. Letter Combinations of a Phone Number (backtracking)
    LeetCode SQL: Combine Two Tables
    LeetCode SQL:Employees Earning More Than Their Managers
  • 原文地址:https://www.cnblogs.com/pass-ion/p/14077294.html
Copyright © 2011-2022 走看看