hadoop中的streaming和pipes

Streaming

 

应用程序在提交 streaming  job 的命令样例,需要指定 JAR 包以及相应的参数值。

$HADOOP_HOME/bin/hadoop  jar $HADOOP_HOME/hadoop-streaming.jar /

    -input myInputDirs /

    -output myOutputDir /

    -mapper myPythonScript.py /

    -reducer /bin/wc /

    -file myPythonScript.py /

    -file myDictionary.txt

客户端运行该命令后,会启动一个进程,该进程的 main 函数为 StreamJob 类。 而由 StreamJob 类完成 job 的提交工作。

所以在 StreamJob 提交 job 之前,需要构造 map,reduce class 类,以及 map,reduce k,v class name 等。

jar 包上,有 streaming map,reduce class ,如 PipeMapRed PipeMapper PipeReducer 。它们分别实现了接口 Mapper Reducer

过程跟普通的 job 是一样的,只不过 streaming job 在我们用其他语言写的 m,r 程序之上用 streaming 自带的 PipeMapper PipeReducer 类包装了一层。

这二个类起了中间的数据传递作用。

PipeMapper PipeReducer 二个类就有 configure,m/r,close 三个函数的。

configure 函数时创建相应语言的进程,进程的 main 函数为应用指定的程序,

同时创建 PipeMapper PipeReducer 类与该 streaming 进程的标准输入输出流。

// Start the process

      ProcessBuilder builder = new ProcessBuilder(argvSplit);

      builder.environment().putAll(childEnv.toMap());

      sim = builder.start();

      clientOut_ = new DataOutputStream( new BufferedOutputStream(

                                              sim .getOutputStream(),

                                              BUFFER_SIZE ));

      clientIn_ = new DataInputStream( new BufferedInputStream (

                                              sim .getInputStream(),

                                              BUFFER_SIZE ));

      clientErr_ = new DataInputStream( new BufferedInputStream( sim .getErrorStream()));

errThread_ = new MRErrorThread();

errThread_ .start();

 

然后 map,reduce() 函数接口去调用上面创建好的输出流,就会把 K,V 输送到 streaming 相应的 map,reduce 程序。

  @Override

  public void writeKey(Object key) throws IOException {

    writeUTF8(key);

    clientOut .write( inputSeparator );

  }

  @Override

  public void writeValue(Object value) throws IOException {

    writeUTF8(value);

    clientOut .write( '/n' );

  }

而对 streaming 程序的 K,V 如何输送到 m,r 接口的呢。

可以看到,在 Map,reduce 接口函数的最开始有这么一个语句。

if ( outerrThreadsThrowable != null ) {

      mapRedFinished();

      throw new IOException ( "MROutput/MRErrThread failed:"

                             + StringUtils.stringifyException (

                                                              outerrThreadsThrowable ));

    }

如果线程对象为空,则需要去会创建一个线程,用来监听 streaming 进程的输出数据。

同是把输入输出流包装成 k,v 对的形式。

  void startOutputThreads(OutputCollector output, Reporter reporter)

    throws IOException {

    inWriter_ = createInputWriter();

    outReader_ = createOutputReader ();

    outThread_ = new MROutputThread ( outReader_ , output, reporter);

    outThread_ .start();

    errThread_ .setReporter(reporter);

  }

守护线程从 streaming 的输出流中得到 K,V 后,最后调用 collect 类把 K,V 对传送给 map reduce 接口。

public void run() {

      try {

        // 3/4 Tool to Hadoop

        while ( outReader .readKeyValue()) {

          Object key = outReader .getCurrentKey();

          Object value = outReader .getCurrentValue();

           outCollector .collect(key, value);

          numRecWritten_ ++;

          long now = System.currentTimeMillis ();

          if (now- lastStdoutReport > reporterOutDelay_ ) {

            lastStdoutReport = now;

            String hline = "Records R/W=" + numRecRead_ + "/" + numRecWritten_ ;

            if (! processProvidedStatus_ ) {

              reporter .setStatus(hline);

            } else {

              reporter .progress();

            }

            logprintln(hline);

            logflush();

          }

        }

      }

大体的上的流程就是以上源码所述的,关键就是 K,V 对的输入输出,二个进程之间的交互过程。

 

Pipes

Streaming 是利用进程之间的标准输入输出流来进行通信,而 pipes 是利用 socket 来通信。

由于 hadoop 是用 java 开发的,所以需要做的就是将其他语言跟 java 进程通信,即跨语言的通信。主要的问题是数据类型的转化问题,因为最低层都是走字节数组的方式。

pipes 包里面实现了 c/c++ java 之间的通信。

同样有提交 job main 函数类 Submitter, 以及管道的 m/r 接口实现类, PipesMapRunner PipesReducer

通信协议包装在 DownwardProtocol 接口。而接口的具体实现类在 Application 类中的 BinaryProtocol 类。这些通信协议与 java C 共同组成。

C++ 的实现在 HadoopPipes.cc 文件中。

process = runClient (cmd, env);

    clientSocket = serverSocket .accept();

    handler = new OutputHandler<K2, V2>(output, reporter, recordReader);

    K2 outputKey = (K2)

      ReflectionUtils.newInstance (outputKeyClass, conf);

    V2 outputValue = (V2)

      ReflectionUtils.newInstance (outputValueClass, conf);

    downlink = new BinaryProtocol <K1, V1, K2, V2>( clientSocket , handler ,

                                  outputKey, outputValue, conf);

    downlink .start();

    downlink .setJobConf(conf);

同样先创建起 pipes 的进程,然后启动网络端口,让 pipes 进程来连接 MR 进程,然后创建输入输出类, OutputHandler BinaryProtocol ,所以具体的通信就在这二个类中。

总结:先启动一个其他语言的进程,然后与之通信,将 K,V 对输入输出到该进程,所以方式有很多种。这里有标准输入输出和网络通信。

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值