整套大数据学习资料(视频+笔记)百度网盘无门槛下载:http://www.edu360.cn/news/content?id=3377

5.5.5 作业调试

hadoop 小红牛 7℃ 0评论


最经典的方法通过打印语句来调试程序,这在Hadoop中同样适用。然而,需要考虑复杂的情况:当程序运行在几十台、几百台甚至几千台节点上时,如何找到并检测调试语句分散在这些节点中的输出呢?为了处理这种情况,我们要査找一个特殊情况,我们用一个调试语句记录到一个标准错误中,它将发送一个信息来更,新任务的状态信息以提示我们査看错误日志。我们将看到WebUI简化了这个操作。

我们还要创建一个自定义的计数器来统计整个数据集中不合理的气温记录总数。这就提供了很有价值的信息来处理如下情况,如果这种情况经常发生,我们需要从中进一步了解事件发生的条件以及如何提取气温值,而不是简单地丢掉这些记录。事实上,调试一个作业的时候,应当总想是否能够使用计数器来获得需要找出事件发生来源的相关信息。即使需要使用日志或状态信息,但使用计数器来衡量问题的严重程度仍然也是有帮助的(详情参见8.丨节)。

 

如果调试期间产生的日志数据规模比较大,可以有如下选择。第一是将这些信息写到map的输出流供reduce分析和汇总,而不是写到标准错误流。这种方法通常必须改变程序结构,所以先选用其他技术。第二种方法,•可 以编写一个程序(当然是MapReduce程序)来分析作业产生的日志。 我们把调试加入mapper(版本4),而不是reducer,因为我们希望找到导致这些异常输出的数据源:

public class MaxTemperatureMapper extends Mapper<LongWritable, Text, Text, IntWritable> {

enum Temperature {

OVERJL00

} •

private NcdcRecordParser parser = new NcdcRecordParser();

@ Override

public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {

parser.parse(value);

if (parser.isValidTemperature()) {

int airTemperature = parser.getAirTemperature(); if (airTemperature > 1000) {

System.err.println("Temperature
over 100 degrees for input: " + value); context.setStatus("Detected
possibly corrupt record: see logs
,〉;

context.getCounter(Temperature.OVER_100.increment(1));

}

context.write(new Text(parser.getYear), new IntWritable(airTemperature));

如果气温超过i(rc(表示为looo,因为气温只保留小数点后一位),我们输出一行到标准错误流以代表有问题的行,同时使用ContextsetStatus()方法来更新map中的状态信息,引导我们査看日志。我们还增加了计数器,表示为Javaenum类型的字段。在这个程序中,定义一个OVERJL00字段来统计气温超过l(TC的记录数。

完成这些修改,我们重新编译代码,重新创建JAR文件,然后重新运行作业并在运行时进入任务页面。

 

1.任务页面

任务页面包括一些査看作业中任务细节的链接。例如,点击map链接,进入一个页面,所有map任务的信息都列在这一页上。还可以只査看已完成的任务。图5-3中的截图显示了带有调试语句的作业页面中的一部分。表中的每行代表一个任务,提供的信息包括每个任务的开始时间和结束时间,来自tasktracker的错误报告,一个用来査看每个任务的计数器的链接。

Completed Tasks

Task

Complele

Status

StartTime

FinishTune

Errors

Counters

task?00904110B110003mOOQC43

100.00*4

hdfs;//ip

10*250-110-47ec2.in«emal

i'user/root/input/nr^lc/all

yid4d.g2<}+2203.»475

1tApr-2009 09:00:06

11-Apr-200S

09:01:25

ISsqc)

in

task200904110811QQQ3mQ0Q044

100.00%

Detectedpossiblycorrupt record:seelogs.

11-Apr-2009 09.00:06

11-Apr-2009

09:01:28

<1mins.

21sec)

n

task200904110B11 0003mO0QD4S

100.00%

hdfe://ip

10-250-11j>-47ec2.inlemflJ

UApr-2009 0900:06

11-Apr-2009 09 01:28

21sec)

ifl

;/1970.g7Di-2083M610

 

 

 

 

5-3.任务页面的屏幕截图

 

Status列对调试非常有用,因为它显示了任务的最新状态信息。任务开始之前,显示的状态为initializing,—旦开始读取记录,它便以字节偏移 量和长度作为文件名,显示它正在读取的文件的划分信息。你可以看到我 们为任务task_200904110811*003_m_000044进行调试时的状态显示,单击日志页面找到相关的调试信息。注意,这个任务有一个附加计数器,因为这个任务的用户计数器有一个非零的计数。

2.任务详细信息页面

从任务页面中,可以单击任何任务获得更多相关信息。图5-4的详细任务信息页面显示了每个taskattempt。在这个范例中,只有一个成功完成的taskattempt。此图表进一步提供了十分有用的数据,如taskattempt的运行节点和指向任务日志文件和计数器的链接。

 

Twfc.AiluK**

*:js

iAcioi*

一軟HtfUCOKW.t KM rl,,,»〇〇〇

",Apr.

1

ST

12

 

 

5-4.任务详细信息页面的屏幕截图

Actions列包括终止taskattempt的链接。在默认情况下,这项功能是禁用的,Web用户界面是只读接口。将webinterface.private.actions设置成true,即可启用此动作的链接。

f:将webinterface.Private.actions设置为true,意味着允许任

何人访问HDFS Web界面来删除文件。dfs.web.ugi属性决定以哪个用户身份运行HDFS Web UI,从而控制可以査看或删除哪些文件。

对于map任务,页面中还有一部分显示了输入分片分布在哪些节点上。

通过跟踪成功taskattempt的日志文件链接(可以看到每个日志文件的最后 4KB8KB或整个文件),会发现存在问题输入记录。这里考虑到篇幅,已经进行了转行和截断处理:

Temperature over100degrees for input:

0335999999433181957042302005+37950+139117SAO
+ 0004R3SNV020113590031500703569999994
33201957010100005+35317+1B9650SAO+000899999V02002359002650076249N0040005994-0067…

此记录的格式看上去与其他记录不同。可能是因为行中有空格,规范中没有这方面的描述。

作业完成后,査看我们定义的计数器的值,检査在整个数据集中有多少记录超过100‘C。通过Web界面或命令行,可以査看计数器:

%hadoop job -counter job_200904110811_0003,v4.MaxTemperatureMapper$Temperature'\ OVER_100

3

 

-counter选项的输入参数包括作业ID,计数器的组名(这里一般是类名)和 计数器名称(enum名)。这里,在超过十亿条记录的整个数据集中,只有三个异常记录。直接扔掉不正确的记录,是许多大数据问题中的标准做法。然而,这里我们需要谨慎处理这种情况,因为我们寻找的是一个极限值-最 高气温值,而不是一个总量。当然,扔掉三个记录也许不会改变最终 结果。

3.处理不合理的数据

捕获引发问题的输入数据是很有价值的,因为我们可以在测试中用它来检査mapper的工作是否正常:

@Test

public void parsesMalformedTemperature() throws IOException, InterruptedException {

Text value = new Text(,,0335999999433181957042302005+37950+139117SAO +0004" +

// YearAAAA

"RDSN V02011359003150070356999999433201957010100005+353M);

// TemperatureAAAAACounters counters = new Counters();

new
MapDriver<longWritable, Text^ Text, IntWritable()> withMapper
[new MaxTemperature Mapper()] withlnputValue (value).
withCauters(counters) runTest();

OutputCollector<Text, IntWritable> output = mock(OutputCollector.class);

Reporter reporter = mock(Reporter.class)j

mapper.map(null>value, output, reporter);

verify(output, never()).collect(any(Text.class), any(IntWritable.class));

verify(reporter).incrCounter(MaxTemperatureMapper.Temperature. MALFORMED, 1);

} •

引发问题的记录与其他行的格式是不同的。范例5-12显示了修改过的程序(版本5),它使用的解析器忽略了那些没有首符号(+或_)气温字段的行。我们还引入一个计数器来统计因为这个原因而被忽略的记录数。

范例5-12.mapper用于查找最高气温

public class MaxTemperatureMapper extends MapReduceBase implements Mapper<LongWritable, Text, Text, IntWritable>,

enum Temperature {

•MALFORMED

 

private
NcdcRecordParser parser = new NcdcRecordParser(); public void
map(LongWritable key, Text value, context context throws IOException,
InterruptedException { parser.parse(value);

if (parser.isValidTemperature()) {

int airTemperature = parser.getAirTemperature();

context.write(new Text(parser.getYear), new IntWritable(airTemperatune));

} else if (parser.isMalformedTemperature()) {

System, err. print In ("Ignoring possibly corrupt input: .. + value); cotext•getCounter(Temperature.MALFORMED, 1);

转载请注明:全栈大数据 » 5.5.5 作业调试

喜欢 (0)or分享 (0)
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址