作业链
在生成环境中,作业链对于理解和拥有一个操作计划非常重要。许多人发现有些问题无法通过单个MapReduce作业解决。另外,在整个链条中,有些作业可以并行执行,有些则需要将它们的输出发送至其他作业,等等。一旦你开始理解如何通过一系列的MapReduce作业去解决问题,你就能够应对一类全新的挑战。
作业链是众多比较难处理的过程的一种,因为它并不是大多数MapReduce框架中包含的特性。像Hadoop这样的系统被设计成能够很好地处理单个MapReduce作业,但在处理多级作业时则需要加入许多手工编码。在操作上还需要考虑作业的各个阶段如何处理任务失败以及清理中间结果输出。
使用MapReduce的一个特别常见的误区是,用MapReduce去处理非常小的作业,而实际上这种作业是不需要分发的。如果你认为将两个作业链接在一起是正确的选择,那么需要考虑第一个作业由多少输出。如果作业的输出数据非常多,那么务必使用第二个MapReduce作业。不过,许多时候作业的输出都很小而且可以在一个节点上非常高效处理。有两种方式可以完成这个工作,一是在作业完成后通过驱动程序中的文件系统API加载数据,一是嵌入某种形式的bash脚本封装器。
6.1.1 关于驱动程序
最简单的执行作业链的方法或许是有一个主驱动程序能够启动多个作业专用的驱动程序。在hadoop中,MapReduce作业的驱动程序就是非常普通的Java代码,没有什么特殊的地方,也不是源于某种特殊的额类或任何东西。
在生成环境中,应该对临时目录进行清理,使它们存在的事件不会超过作业完成时。如果在这里缺乏原则,那么这些临时数据将会以惊人的速度填满集群。同时,要注意你实际创建了多少临时数据,因为这些数据需要存储在文件系统中。
这种方法可以很容易地扩展到创建多于两个作业的作业链。只要确保记录了所有的临时路径并选择性地清理掉作业运行时不会再使用到的数据。
你也可以使用Job.submit()方法代替Job.waitForCompletion()并行地启动多个作业。调用submit方法后会立即返回至当前线程,而作业将在后台运行。
另一个需要注意的是作业是否成功。仅仅知道作业完成了是不够的,还要检查作业是否成功。
6.1.3 关于shell脚本
作业链中的每个作业都是单独启动,你可以在shell脚本内用命令方式执行。
该方法的有点是,不需要重新编译代码就能改变作业的流程,因为主程序是脚本语言而不是Java。另一个优点是,shell脚本可以和非Java为核心的服务、系统、工具进行交互。缺点是,可能更难实现作业并行执行这种较为复杂的作业流程。