MapReduce应用开发

用于配置的API

    Configuration conf = new Configuration();
    conf.addResource("configuration-1.xml");
    conf.addResource("configuration-2.xml");

辅助类GenericOptionsParser,Tool,ToolRunner

GenericOptionsParser是一个类,用来解释常用的Hadoop命令行选项,并根据需要,为Configuration对象设置相应的取值,

通常不直接使用,更方便的方式是使用Tool接口,通过ToolRunner来运行应用程序,ToolRunner内部调用GenericOptionsParser

public class ConfigurationPrinter extends Configured implements Tool {
  
  static {
    Configuration.addDefaultResource("hdfs-default.xml");
    Configuration.addDefaultResource("hdfs-site.xml");
    Configuration.addDefaultResource("yarn-default.xml");
    Configuration.addDefaultResource("yarn-site.xml");
    Configuration.addDefaultResource("mapred-default.xml");
    Configuration.addDefaultResource("mapred-site.xml");
  }

  @Override
  public int run(String[] args) throws Exception {
    Configuration conf = getConf();
    for (Entry<String, String> entry: conf) {
      System.out.printf("%s=%s\n", entry.getKey(), entry.getValue());
    }
    return 0;
  }
  
  public static void main(String[] args) throws Exception {
    int exitCode = ToolRunner.run(new ConfigurationPrinter(), args);
    System.exit(exitCode);
  }
}
Hadoop -D color=yellow 用于将color的配置属性设置为yellow,-D优先级要高于配置文件里的其他属性

MRUnit写单元测试
MRUnit是一个测试库,便于将一直的输入传递给Mapper或者检查reducer的输出是否符合预期
 @Test
  public void processesValidRecord() throws IOException, InterruptedException {
    Text value = new Text("0043011990999991950051518004+68750+023550FM-12+0382" +
                                  // Year ^^^^
        "99999V0203201N00261220001CN9999999N9-00111+99999999999");
                              // Temperature ^^^^^
    new MapDriver<LongWritable, Text, Text, IntWritable>()
      .withMapper(new MaxTemperatureMapper())
      .withInput(new LongWritable(0), value)
      .withOutput(new Text("1950"), new IntWritable(-11))
      .runTest();
  }
public class MaxTemperatureReducerTest {
  
  //vv MaxTemperatureReducerTestV1
  @Test
  public void returnsMaximumIntegerInValues() throws IOException,
      InterruptedException {
    new ReduceDriver<Text, IntWritable, Text, IntWritable>()
      .withReducer(new MaxTemperatureReducer())
      .withInput(new Text("1950"),
          Arrays.asList(new IntWritable(10), new IntWritable(5)))
      .withOutput(new Text("1950"), new IntWritable(10))
      .runTest();
  }
  //^^ MaxTemperatureReducerTestV1
}
本地运行测试数据
在本地作业运行期上运行作业
public class MaxTemperatureDriver extends Configured implements Tool {

  @Override
  public int run(String[] args) throws Exception {
    if (args.length != 2) {
      System.err.printf("Usage: %s [generic options] <input> <output>\n",
          getClass().getSimpleName());
      ToolRunner.printGenericCommandUsage(System.err);
      return -1;
    }
    
    Job job = new Job(getConf(), "Max temperature");
    job.setJarByClass(getClass());

    FileInputFormat.addInputPath(job, new Path(args[0]));
    FileOutputFormat.setOutputPath(job, new Path(args[1]));
    
    job.setMapperClass(MaxTemperatureMapper.class);
    job.setCombinerClass(MaxTemperatureReducer.class);
    job.setReducerClass(MaxTemperatureReducer.class);

    job.setOutputKeyClass(Text.class);
    job.setOutputValueClass(IntWritable.class);
    
    return job.waitForCompletion(true) ? 0 : 1;
  }
  
  public static void main(String[] args) throws Exception {
    int exitCode = ToolRunner.run(new MaxTemperatureDriver(), args);
    System.exit(exitCode);
  }
}
测试驱动程序
1.使用本地作业运行
 @Test
  public void test() throws Exception {
    Configuration conf = new Configuration();
    conf.set("fs.defaultFS", "file:///");
    conf.set("mapreduce.framework.name", "local");
    conf.setInt("mapreduce.task.io.sort.mb", 1);
    
    Path input = new Path("input/ncdc/micro");
    Path output = new Path("output");
    
    FileSystem fs = FileSystem.getLocal(conf);
    fs.delete(output, true); // delete old output
    
    MaxTemperatureDriver driver = new MaxTemperatureDriver();
    driver.setConf(conf);
    
    int exitCode = driver.run(new String[] {
        input.toString(), output.toString() });
    assertThat(exitCode, is(0));
    
    checkOutput(conf, output);
  }
2.使用一个mini集群运行,Hadoop有一组测试类,MiniDFSCluster,MiniMRCluster,MiniYARN
Cluster
在集群上运行
本地左右使用单JVM运行一个作业
在分布式中:
JobConf 或 Job上的 setJarByClass()方法中设置类
setJar() 通过文件路径设置一个指定的JAR文件

客户端的类路径:
hadoop jar <jar>组成部分:
 作业的jar文件
 所有jar文件包含的lib文件
HADOOP_CLASSPATH定义的类路径(如果设置了)
任务类路径,不受HADOOP_CLASSPATH控制
 作业的jar文件
 所有jar文件包含的lib文件
 使用-libjars选项 添加到分布式缓存的所有文件
启动作业
 -conf选项指定要运行的作业集群 hadoop -conf hadoop-cluster.xml
MapReduce作业ID有Yarn资源管理器创建,一个应用id包含两部分:
开始时间和计数器:application_124324234234234_003 003表示第三个应用
作业ID : application替换为job: job_124324234234234_003
任务ID : task_124324234234234_003_m_00003 表示ID为task_124324234234234_003_m_00003
  作业的第4个map任务,由0开始
任务尝试:task_124324234234234_003_m_00003_0 0表示第一次尝试


MapReduce页面
 作业历史由MapReduce的 application_master存放在HDFS中
通过mapreduce.jobhistory.done-dir 设置存放目录


获取结果
每个reduce产生一个输出文件,以下命令得到了源模式指定目录下所有文件,并将其合并为本地文件系统
的一个文件:
hadoop fs -getmerge max-temp max-temp-local
sort max-temp-local | tail
或使用 -cat命令打印到控制台

作业调试
调试一个作业是,应当总想是否能够使用计数器来获得需要找出时间发生来源的相关信息。
如果日志数据规模比较大:
 一种是将这些信息写到map的输出流,供reduce任务分析和汇总,而不是写到标准
 错误流
 一种是写程序分析作业产生的日志
public class MaxTemperatureMapper
  extends Mapper<LongWritable, Text, Text, IntWritable> {

  /*[*/enum Temperature {
    OVER_100
  }/*]*/
  
  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));
    }
  }
}
处理不合理的数据
public class MaxTemperatureMapper
  extends Mapper<LongWritable, Text, Text, IntWritable> {
  
  enum Temperature {
    MALFORMED
  }

  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();
      context.write(new Text(parser.getYear()), new IntWritable(airTemperature));
    } else if (parser.isMalformedTemperature()) {
      System.err.println("Ignoring possibly corrupt input: " + value);
      context.getCounter(Temperature.MALFORMED).increment(1);
    }
  }
}

Hadoop日志
日志聚合:YARN中可以获取到已完成的应用任务日志,并把其搬移到HDFS中,如果被启用,可通过集群上将
    yarn.log-aggregation-enable设置为true,可点击web界面中的logs链接,或使用命令
    默认关闭状态
  
 
public class LoggingIdentityMapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT>
  extends Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT> {
  
  private static final Log LOG = LogFactory.getLog(LoggingIdentityMapper.class);
  
  @Override
  @SuppressWarnings("unchecked")
  public void map(KEYIN key, VALUEIN value, Context context)
      throws IOException, InterruptedException {
    // Log to stdout file
    System.out.println("Map key: " + key);
    
    // Log to syslog file
    LOG.info("Map key: " + key);
    if (LOG.isDebugEnabled()) {
      LOG.debug("Map value: " + value);
    }
    context.write((KEYOUT) key, (VALUEOUT) value);
  }
}
默认日志级别是INFO,因此debug不显示在syslog中,需要设置mapreduce.map.log.level

远程调试
作业调优
mapper数量 
reducer数量 
combiner 
中间值压缩 
自定义序列 
调整shuffle 



  分析任务
必须不断运行,改变或不改变代码,并检查是否有明显的改进
有些问题(如内存溢出)只能在集群上重现
1.HPROF分析工具
mapreduce.task.profile设置为true
能提供程序的CPU和堆使用情况能有价值的信息

MapReduce的工作流
增加更多作业,而不是增加作业复杂度
更复杂问题,可考虑更高级语言,Pig,Hive,Spark...
JobControl
当MapReduce工作流的作业不止一个时,考虑是否用一个线性作业链,或一个更复杂的有向无环图
JobClient.runjob(conf1)
JobClient.runjob(conf2)
Apache Oozie 
运行工作流的系统,该工作流由相互依赖的作业组成
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值