我用Java编写了一个简单的Map/Reduce程序,用于两个文本文件的关系连接操作。这个算法在很多地方都有描述,在Reduce任务中执行join。
我想调整它以获得更好的性能。第一件事是尝试不同数量的Reduce任务。目前我只在一台4核的计算机上运行,但实际上是在分布式文件系统中。
我遇到了一个奇怪的现象,如果我运行4个或32个reduce任务,那么wall(时间开始到时间完成)甚至比我只运行1个reduce任务的时间更长:
1 reducer: 22.4 seconds
4 reducer: 23.3 seconds
32 reducer: 26.1 seconds
从这个趋势来看,我真的无法解释。第一印象是瓶颈可能在I/O上,因为我在一台机器上运行,高I/O操作并不是真正并行的。然而,通过查看CPU统计,i/o等待时间非常小(在我的测试数据中输入数据只有几个兆字节),因此它看起来不是一个很好的解释。值得一提的是,我在运行map/reduce程序时监视了不同内核的CPU使用情况,我发现大多数时候CPU使用情况仅限于一个内核,并且看起来并不像并行的。
我还怀疑运行更多reducer的好处会被map/reduce额外的开销所抵消。
你觉得这个怎么样?
[Update]我发现语句(也通过一些计时观察证明),在单个JVM中,map和reduce任务只以串行方式运行,而不是多线程。这就解释了为什么更多的reducer任务会占用更多的时间。
我看到Hadoop使用multithreaddmapper类支持多线程映射器,我尝试了一下,不幸的是结果再次变得更糟。
但是我不知道为什么有一个叫做multithreaddmapper的类,但是为什么有另一个像multithreadddreducer ?
应该根据可用的reduce任务槽来配置reducer的数量。4/32减速器的应用时间更长,因为:1)机器为4芯,所以理想的减速器数量应该在2个左右。2)输入数据非常小,因此初始化reduce任务所花费的时间大于并行处理时间。
为了在相同的硬件上进行更好的基准测试,请将reducer设置为1、2和最多3。另外,使用一些更大的数据集(至少几个块,即512 MB到1 GB)。
对于这个问题,我想我找到了答案。当我以单机模式运行时,Hadoop根本没有尝试在多线程中运行mapper和reducer。这很好地解释了我在计时上的发现。
另一方面,我看到文章和帖子说,在Pseduo模式下运行将启用并发运行(或者更准确地说是多进程)。我试过了,但是有一些问题。然而,我认为这是一个新的问题,所以这个问题可以说已经得到了解答。