1

调试 Hadoop map-reduce 作业很痛苦。我可以打印到标准输出,但这些日志显示在运行 MR 作业的所有不同机器上。我可以去 jobtracker,找到我的工作,然后单击每个单独的 mapper 以获取其任务日志,但是当您有 20 多个 mapper/reducer 时,这非常麻烦。

我在想我可能必须编写一个脚本来遍历作业跟踪器,以找出每个映射器/减速器在哪台机器上运行,然后 scp 将日志返回到一个可以将它们集中在一起的中心位置。在我浪费时间做这件事之前,是否有人知道一种更好的方法来为作业的映射器和减速器获取一个合并的标准输出日志?

4

3 回答 3

1

我这样做是通过以下方式:

对于一般调试(即测试作业是否有效),我在本地机器上以独立模式运行 hadoop,并使用少量数据样本。这样,hadoop 就可以像任何其他 java 应用程序一样工作,并在控制台中显示映射器或减速器的标准输出。

对于特定的错误(即作业在我的本地机器上运行良好,但在生产中死亡),我只需调整代码以作为作业的输出,我通常会在调试时发送到标准输出。这样,您可以检查作业的结果以获取调试见解。这不漂亮,但效果很好。

另一种选择是在 jobtracker 中检查节点的日志。他们有所有的标准输出和标准错误。但是,由于多种原因,我发现这比上述解决方案要复杂得多(一段时间后删除日志,要查找几个节点等)

于 2013-08-30T04:30:18.937 回答
1

所以我最终只是创建了一个 Python 脚本来执行此操作。这并不可怕。这是脚本,以防其他人想使用它。显然它需要更多的错误检查,而不是硬编码的网址等,但你明白了。注意,你需要下载Beautiful Soup

#!/usr/bin/python
import sys
from bs4 import BeautifulSoup as BS
from urllib2 import urlopen
import re

TRACKER_BASE_URL = 'http://my.tracker.com:50030/'
trackerURLformat = TRACKER_BASE_URL + 'jobtasks.jsp?jobid=%s&type=%s&pagenum=1' # use map or reduce for the type

def findLogs(url):
    finalLog = ""

    print "Looking for Job: " + url
    html = urlopen(url).read()
    trackerSoup = BS(html)
    taskURLs = [h.get('href') for h in trackerSoup.find_all(href=re.compile('taskdetails'))]

    # Now that we know where all the tasks are, go find their logs
    logURLs = []
    for taskURL in taskURLs:
        taskHTML = urlopen(TRACKER_BASE_URL + taskURL).read()
        taskSoup = BS(taskHTML)
        allLogURL = taskSoup.find(href=re.compile('all=true')).get('href')
        logURLs.append(allLogURL)

    # Now fetch the stdout log from each
    for logURL in logURLs:
        logHTML = urlopen(logURL).read()
        logSoup = BS(logHTML)
        stdoutText = logSoup.body.pre.text.lstrip()
        finalLog += stdoutText

    return finalLog


def main(argv):
    with open(argv[1] + "-map-stdout.log", "w") as f:
        f.write(findLogs(trackerURLformat % (argv[1], "map")))
        print "Wrote mapers stdouts to " + f.name

    with open(argv[1] + "-reduce-stdout.log", "w") as f:
        f.write(findLogs(trackerURLformat % (argv[1], "reduce")))
        print "Wrote reducer stdouts to " + f.name

if __name__ == "__main__":
    main(sys.argv)
于 2013-08-30T13:08:37.913 回答
0

我的经验是,当您确切知道是什么 map/reduce 尝试导致了要通过日志检查的问题时,您不需要单击 20 多个 map/reduce 输出链接。这就是为什么我在抛出异常或增加计数器时总是使用 Context.setStatus("Warn message here") 以引起怀疑。

更多关于 setStatus:http://hadoop.apache.org/docs/r1.1.1/api/org/apache/hadoop/mapreduce/TaskInputOutputContext.html#setStatus(java.lang.String)

https://www.inkling.com/read/hadoop-definitive-guide-tom-white-3rd/chapter-5/running-on-a-cluster(调试作业部分)

于 2014-07-14T22:40:11.333 回答