命令行工具可以比你的Hadoop集群快235x倍

介绍

当我在浏览网页关注一些我定期访问网站的更新时,我发现Tom Hayden的一篇很酷的文章,使用Amazon Elastic Map Reduce(EMR)和mrjob,以计算从millionbase archive下载的象棋游戏的输赢率,慢慢地从中发现乐趣。由于数据量仅约为1.75GB,含200万左右的国际象棋游戏,我不确定他为何使用Hadoop,但我能理解他的目标,从mrjob和EMR中学习并获得乐趣。既然问题基本上只是看每个文件的resultl lines和汇总不同的结果,似乎非常适合shell命令的流处理。我试着用相同的数据量处理,我的笔记本电脑得到结果只需12秒左右(处理速度约为270MB /秒),而Hadoop处理了约26分钟(处理速度约1.14MB /秒)。

在报告用7 c1. machine在集群中处理数据所需要的时间为26分钟,汤姆写到:“这可能比在我的机器上按顺序运行快,但如果我做了一些聪明的本地多线程应用程序可能更好。”

这是绝对正确的,但即使串行处理可以击败26分钟。虽然汤姆只是为了娱乐在做项目,人们往往使用Hadoop和其他所谓的大数据(TM)工具来做实世界的处理和分析工作,其实这些工作可以用更简单的工具和不同的技术做得更快。

其中尤其未充分利用是使用标准的shell工具和命令进行数据处理的方法。这种方法的好处是大量的,因为通过shell命令创建一个数据管道意味着所有的处理步骤可以并行完成。这基本上就像在本地计算机上拥有你自己的风暴集群。甚至喷口,螺栓,和水槽的概念转移至壳管和它们之间的命令。你可以很容易地用基本的命令构造相比许多现代大数据(TM)工具有表现更出色的流处理管道。

另外一点是批处理与流分析方法的比较。汤姆在开头提到在装载10000个游戏,并在本地做了分析后,他的内存有些紧缺。这是因为所有的游戏数据被加载到RAM用于分析。但是这个问题可以很容易地通过流媒体分析解决,因为它基本不占内存。我们创建的流处理管道会比Hadoop的实施快235倍以上,并基本不使用内存。

了解数据

在管道中的第一步是从PGN文件中获取数据的。因为我不知道这是什么样的格式,我搜索了维基百科。

[Event "F/S Return Match"]
[Site "Belgrade, Serbia Yugoslavia|JUG"]
[Date "1992.11.04"]
[Round "29"]
[White "Fischer, Robert J."]
[Black "Spassky, Boris V."]
[Result "1/2-1/2"]
(moves from the game follow...)

我们只关心比赛的结果,其中只有3个实际结果。在1-0的情况下是指白色赢了,0-1的情况下是指黑色赢,1 / 2-1 / 2的情况说明比赛是一场平局。还有a- 的情况说明比赛正在进行或无法得分,但我们因为我们的目的忽略它。

采集样本数据

要做的第一件事是获取很多游戏数据。这实际比我想象的更加困难,但在网上看了会儿之后,我在从rozim发现GitHub上的一个git repository有大量的游戏。我用这个编译一组3.46GB的数据,约汤姆测试的两倍。下一步是把所有的数据放到我们的管道。

建立一个处理管道

如果你照着操作并计时你的处理,别忘了清除你的操作系统的页面缓存,否则你的处理时间是无效的。

shell命令对于数据处理管道很好,因为你免费获得并行。为了证明这一点,在你的终端尝试一个简单的例子。

sleep 3 | echo "Hello world."

它可能看起来是上面的会睡3秒钟,然后打印出“Hello World”的,但实际上这两个步骤都在同一时间完成。这一基本事实就是shell命令能够为一种能在单个计算机上运行的简单的非IO结合的处理系统极大的加速的原因。

在开始分析管道之前,先来看一下它到底有多快的参考值,我们可以简单地转储数据到/ dev / null。

在这种情况下,大约需要13秒经过3.46GB,约272MB /秒。这显示了在该系统上数据处理的上限,由于IO约束处理。

现在,我们可以开始分析管道,第一步是使用cat来生成数据流。

cat *.pgn

由于只有result lines在文件中是有趣的,我们可以简单地扫一遍所有的数据文件,并挑选出含有“Result”中有grep的。

cat *.pgn | grep "Result"

这将使我们只能从文件得到Result lines。如果我们愿意,我们可以简单地使用sort和uniq命令,以获得的文件中的所有独特项目的列表以及它们的计数。

cat *.pgn | grep "Result" | sort | uniq -c

这是一个非常简单明了的分析管道,并且使我们在大约70秒得到结果。相比较Hadoop集群,假设线性缩放这些,需要约52分钟处理。

为了进一步降低速度,我们可以从管道中拿出sort | uniq的步骤,并将它们用AWK代替,AWK是一个基于事件的数据处理的奇妙的工具/语言。

cat *.pgn | grep "Result" | awk '{ split($0, a, "-"); res = substr(a[1], length(a[1]), 1); if (res == 1) white++; if (res == 0) black++; if (res == 2) draw++;} END { print white+black+draw, white, black, draw }'

这将需要记录每个结果,用连字符分割它,并立即将字符放到左侧,即一个0表示黑色赢一次,一个1表示白色赢一次,一个2表示平局。注意$0是一个内置的变量,它表示整个记录。

这将运行时间约减少到65秒,因为我们正在处理两倍的数据,这是大约47倍的加速。

因此,单在这一点上,我们用一个天真的本地解决方案已经有大约47的加速。此外,内存使用情况是零,因为唯一的存储数据是实际计数,而且递增的3整数几乎不占内存空间。然而在运行中htop显示,grep是目前单个CPU核心充分使用遭遇的瓶颈。

并行化瓶颈

未使用的核心这个问题可以是用出色的xargs命令解决,这将使我们能够并行化的grep。由于xargs预期以某种特定的方式输入,使用find与-print0参数会更安全和容易,以确保每个被传递给xargs的文件名是空值终止。相应-0的显示xargs预期空值终止输入。此外,-n表示给每个过程投入多少,-P表示并行运行的进程数。同样重要的是,这样的并行流水线不保证传递顺序,如果你习惯用分布式处理系统,这就不是一个问题。该grep的-F表示我们只是在匹配固定字符串并没有做任何花哨的正则表达式,并能提供一个小的加速,这是我在测试中没有注意到的。

find . -type f -name '*.pgn' -print0 | xargs -0 -n1 -P4 grep -F "Result" | gawk '{ split($0, a, "-"); res = substr(a[1], length(a[1]), 1); if (res == 1) white++; if (res == 0) black++; if (res == 2) draw++;} END { print NR, white, black, draw }'

这个结果运行约38秒,这是一个额外的40%左右的降低在管道中并行grep工序的处理时间。这会让我们比Hadoop快约77倍。

虽然我们已经通过在我们的管道上并行grep步骤显着改善性能,我们实际上可以完全用AWK过滤输入记录(在此情况中是lines),并且只在那些包含字符串“Result”操作来删除整个步骤。

find . -type f -name '*.pgn' -print0 | xargs -0 -n1 -P4 awk '/Result/ { split($0, a, "-"); res = substr(a[1], length(a[1]), 1); if (res == 1) white++; if (res == 0) black++; if (res == 2) draw++;} END { print white+black+draw, white, black, draw }'

你可能认为这是正确的解决方案,但是这将输出每个文件的个别结果,当我们想将它们聚集在一起时。由此产生的正确应用在概念上MapReduce的应用非常相似。

time find . -type f -name '*.pgn' -print0 | xargs -0 -n4 -P4 awk '/Result/ { split($0, a, "-"); res = substr(a[1], length(a[1]), 1); if (res == 1) white++; if (res == 0) black++; if (res == 2) draw++ } END { print white+black+draw, white, black, draw }' | awk '{games += $1; white += $2; black += $3; draw += $4; } END { print games, white, black, draw }'

通过将第二个AWK的步骤加在最后,我们获得了需要的汇总的游戏信息。

这进一步显著地提高了速度,达到约18秒的运行时间,即约Hadoop的174倍。

不过,我们仍可以用mawk让它更快一点,这往往完全取代gawk,可以提供更好的表现。

find . -type f -name '*.pgn' -print0 | xargs -0 -n4 -P4 mawk '/Result/ { split($0, a, "-"); res = substr(a[1], length(a[1]), 1); if (res == 1) white++; if (res == 0) black++; if (res == 2) draw++ } END { print white+black+draw, white, black, draw }' | mawk '{games += $1; white += $2; black += $3; draw += $4; } END { print games, white, black, draw }'



这个find | xargs mawk | mawk管道将我们的运行时间下降到约12秒,即约270MB /秒,比Hadoop快235倍。

结论

希望这说明了一些使用和滥用工具的要点,如Hadoop用于数据处理的任务能在一台机器上用简单的shell命令和工具更好地实现。如果你有一个庞大的数据量,或确实需要分布式处理,然后像Hadoop的工具可能是必需的,但更多的往往是这些天我看到一些使用Hadoop的场景,如果使用关系数据库或其他解决方案能好得多,不管是在性能,实施成本还是后续维护方面。

翻译自: Adam Drake http://aadrake.com/command-line-tools-can-be-235x-faster-than-your-hadoop-cluster.html

Comment

*

沪ICP备14014813号

沪公网安备 31010802001379号