在使用Python编写Hadoop Streaming作业的过程中,我们发现需要使用一些比较复杂的第三方库,比如numpy,scipy,scikit-learn,pandas等等。而这些库通过简单的zipimport机制又不能正常在工作节点上执行,主要原因是这些库中,有些是有C共享库依赖的。
为了能够解决这个问题,最笨的办法就是,在所有的工作节点上都部署一套相同的Python解释器,并安装好相应的第三方模块;或者直接在一台服务器上,通过virtualenv工具生成一个虚拟的Python环境,将这个环境同步到其它服务器上。
这样做的话,每增加一台新的工作节点,我们都需要想着在这台新工作节点上,要部署一个Python环境,并且按照要求安装大量的第三方模块(或者直接拷贝virtualenv声称的虚拟环境),并且当需要新加入第三方模块的时候,需要重新同步所有工作节点上Python环境,这个工作量可是不小的!
通过对Hadoop Streaming的研究,其实有一种更好的办法来解决这个问题:那就是在提交Hadoop Streaming任务的时候,将整个的virtualenv生成的虚拟Python环境拷贝到工作节点上,然后在运行相应的Map或者Reduce任务脚本时,指定用这个“实时”同步过来的虚拟Python解释器来执行。
为了将,最新的Python解释器环境传到工作节点上,我们使用的是Hadoop Streaming的-archives选项,用它能够指定一系列用逗号分割的打包文件(支持jar,tar.gz,tgz等等),这些包会同步到工作节点服务器的本地,然后自动解压这些包。这样,我们就可以在后续的执行过程中,使用最新的Python解释器了。当然,如果我们需要增加新的第三方模块,我们只需在一台核心服务器(比如专门用来提交任务的服务器)上的Python虚拟环境中安装相应的第三方模块,然后打一个新的压缩包即可!
举一个例子:
1. 通过virtualenv生成一个Python虚拟环境vp:
virtualenv vp
2. 进入虚拟Python环境vp,并安装需要的第三方模块:
source vp/bin/active
pip install numpy scipy scikit-learn
3. 将安装好第三方模块的Python虚拟环境打成压缩包:
tar cvzf vp.tgz vp
4. 此时,我们就可以用这个第三方包来运行Hadoop Streaming程序了:
hadoop jar /usr/lib/hadoop/hadoop-streaming-2.6.0-amzn-2.jar -archives other.zip,vp.tgz -D mapreduce.job.reduces=1 -D mapreduce.task.timeout=6000000 -input s3://... -output s3://... -mapper "vp.tgz/vp/bin/python xxx.py" -file xxx.py
这样,在提交这个Hadoop Streaming任务之后,首先各个工作节点会得到我们最新的vp.tgz包,继而会解压这个文件到一个叫vp.tgz的目录下,这一点一定要注意,以便在引用的时候准确找到执行文件。
以上。