hadoop 0.19.1 rpc代码分析

来源:互联网 发布:淘宝网日本进口钓鱼竿 编辑:程序博客网 时间:2024/05/10 03:08

一、概述

hadoop中mr类图大致如下所示,其中只是简单列出了一些主要的功能模块。
JobConf、JobTracker、TaskTracker、RPC Server等组件。在图中,我用红色框框框出了一些基本的类。此图基本反映了MR的类图结构。

一个简单的job在hadoop上面跑起来,基本可以分为10个步骤。如下图所示:

hadoop都是用rpc框架来机器的连接,由于一些性能的原因及别的我不知道的原因,hadoop自己选择实现一套rpc框架。

二、分析RPC
hadoop是master-slave结构,以心跳为例,心跳主要作用是监控及数据传输。如,taskTasker为了得到一个HeartbeatResponse,大致需要经过以下的流程。

上图是一个序列图,是代码实现的调用序列,我们简化为流程图如下:

我们大致认为一次心跳(包括RPC)需要经过7个步骤。在这个7个步骤中,有大约6个主要的线程在服务。
TaskTracker端的:TaskTreacker,Client.Connection
JobTracker端的:Server.Listener,Server.Reader,Server.Handler,Server.Responder
7个步骤为:
1)、TaskTracker定期发送请求。TaskTracker持有一个代理对象InterTrackerProtocol.此对象经过动态代理处理,实际上是调用RPC.Invoker类。此类再调用 client.call()。此方法中,会实例化一个Client.Connection对象,并启动此对象。发送远程请求后,TaskTracker会阻塞在Call上面,等待Client.Connection线程被唤醒后调用call.notify()。
    Call call = new Call(param);
    Connection connection = getConnection(addr, ticket, call);
    connection.sendParam(call);                 // send the parameter
    synchronized (call) {
      while (!call. done) {
        try {
          call.wait();                           // wait for the result
        } catch (InterruptedException ignored) {}
      }
注意Client.Connection线程一直阻塞在DataInputStream.readInt()等待JobTracker的响应。

图:Client.Connection线程
2)、Server.Listener会监听到请求并建立连接,再调用Reader来做读取网络数据。与Server.Reader的协同主要是通过adding变量、Server.Reader.wait()、readSelector;完成后阻塞在selector.select();
     while ( adding) {
                this.wait(1000);
              }  

图:Server.Listener线程
3)、Server.Reader主要是读取数据,做一些分析,再生成Server.call放进BlockingQueue<Call> callQueue队列中。完成后会阻塞在readSelector.select();

图:Server.Reader线程
4)、Server.Handler阻塞在队列上面,当callQueue队列中存在数据的时候就会被唤醒。执行任务主要是 调用 Server的子类(RPC.Server)实现的Call()函数。此函数会根据TaskTreacker传入的函数来反射调用JobTracker的实现(这里是InterTrackerProtocol接口的实现heartbeat(x,x,x)),完成后,再调用Server.Responder的函数。在一些特别的条件下会与Server.Responder线程协调工作。由Server.Responder线程完成数据压入网络的工作。

图:Server.Handler线程

5)、Server.Handler线程会反射调用TaskTreacker.heartbeat(x,x,x)会执行相关的工作,拿到结果HeartbeatResponse。
6)、Server.Responder线程在一些情况下会把响应结果压入网络中。
7)、Client.Connection线程被唤醒,他再调用call.nodify()唤醒TaskTreacker主线程。
此点,在开始Connection发送请求的时候,会把call的id存入在map中,在被唤醒的时候DataInputStream.readInt()直接返回一个call的id。用id到map查找相应的call,再调用call.nodify()唤醒TaskTracker,TaskTracker被唤醒后再根据call.value做相应的事情。如:启动一个任务。


备注:
以上的代码分析是基于0.19.1,高版本的代码可能所有不同。

三、版权信息

作者工作于阿里巴巴 封神

转载请保留来源地址:http://blog.csdn.net/bxyz1203/article/details/7924834

原创粉丝点击