当前位置: > > > Hadoop - MapReduce任务日志查看教程(启动historyserver开启日志聚合功能)

Hadoop - MapReduce任务日志查看教程(启动historyserver开启日志聚合功能)

1,问题描述

(1)MapReduce 任务执行时,我们在控制台上是看不到任务中的日志信息的。因为我们相当于是通过一个客户端把任务提交到集群里面去执行了,所以日志是存在在集群里面的。

(2)如果要查看日志信息,先进入到 yarn web 界面,访问 8088 端口,点击对应任务的 history 链接:

(3)不过我们点击后可能会发现页面打不开,这里有两个原因:第一个原因是 windows hosts 文件中没有配置集群中各个节点的主机名和 ip 的映射关系:
注意:如果想使用主机名在浏览器中访问 8088 界面,不能开启翻墙工具,否则就算在 windows hosts 文件中配置了虚拟机的 ip 和主机名的映射关系,在浏览器中也无法使用主机名访问,因为此时请求会被翻墙工具所拦截,但是翻墙工具中无法识别这个主机名。
192.168.60.9 node1
192.168.60.10 node2
192.168.60.11 node3

(4)第二个原因就是这里必须要启动 historyserver 进程才可以,并且还要开启日志聚合功能,才能在 web 界面上直接查看任务对应的日志信息。
  • 因为默认情况下任务的日志是散落在 nodemanager 节点上的,想要查看需要找到对应的 nodemanager 节点上去查看,这样就很不方便,通过日志聚合功能我们可以把之前本来散落在 nodemanager 节点上的日志统一收集到 hdfs 上的指定目录中,这样就可以在 yarn web 界面中直接查看了。

2,开启日志聚合功能

(1)Hadoop 的相关配置文件都在 Hadoop 安装目录下的“etc/hadoop”目录下,首先我们进入 node1 节点下的该目录:
cd /usr/local/hadoop/etc/hadoop

(2)开启日志聚合功能需要修改 yarn-site.xml 的配置:
vi yarn-site.xml

(3)在配置中增加 yarn.log-aggregation-enable yarn.log.server.url 这两个参数:
<property> 
    <name>yarn.log-aggregation-enable</name>  
    <value>true</value>
</property>
<property>
    <name>yarn.log.server.url</name>
    <value>http://node1:19888/jobhistory/logs/</value>
</property>

(4)然后将修改后的配置文件复制到集群中的其他节点上:
scp -rq yarn-site.xml node2:/usr/local/hadoop/etc/hadoop/
scp -rq yarn-site.xml node3:/usr/local/hadoop/etc/hadoop/

(5)然后重启集群服务:
sbin/stop-all.sh
sbin/start-all.sh

(6)最后我们还要启动 historyserver 进程,注意需要在集群的所有节点上都启动这个进程:
bin/mapred --daemon start historyserver

3,测试验证

(1)首先我们准备一个如下的单词统计任务代码,并在里面添加一些日志打印动作:
  • 在自定义 mapper 类的 map 函数中增加一个输出,将 k1,v1 的值打印出来
  • 在自定义 reducer 类中的 reduce 方法中增加一个输出,将 k3,v3 的值打印出来
public class WordCountJob {
  /**
   * 创建自定义mapper类
   */
  public static class MyMapper extends Mapper<LongWritable,Text,Text,LongWritable>{
    /**
     * 需要实现map函数
     * 这个map函数就是可以接收k1,v1,产生k2,v2
     * @param k1
     * @param v1
     * @param context
     * @throws IOException
     * @throws InterruptedException
     */
    @Override
    protected void map(LongWritable k1, Text v1, Context context)
            throws IOException, InterruptedException {
      // k1代表的是每一行的行首偏移量,v1代表的是每一行内容
      // 对获取到的每一行数据进行切割,把单词切割出来
      String[] words = v1.toString().split(" ");

      // 迭代切割出来的单词数据
      for(String word:words){
        // 把迭代出来的单词封装成<k2,v2>的形式
        Text k2 = new Text(word);
        LongWritable v2 = new LongWritable(1L);
        System.out.println("k2:"+word+"...v2:1");
        // 输出k2,v2
        context.write(k2,v2);
      }
    }
  }

  /**
   * 创建自定义的reducer类
   */
  public static class MyReducer extends Reducer<Text,LongWritable,Text,LongWritable> {
    /**
     * 针对v2s的数据进行累加求和
     * @param k2
     * @param v2s
     * @param context
     * @throws IOException
     * @throws InterruptedException
     */
    @Override
    protected void reduce(Text k2, Iterable<LongWritable> v2s, Context context)
            throws IOException, InterruptedException {
      //v2s {1,1,1,1}
      //创建一个sum变量,保存v2s的和
      long sum = 0L;
      for(LongWritable v2:v2s){
        sum += v2.get();
      }
      //组装k3,v3
      Text k3 = k2;
      LongWritable v3 = new LongWritable(sum);
      //输出k3,v3的值
      System.out.println("<k3,v3>=<"+k3.toString()+","+v3.get()+">");
      //输出结果
      context.write(k3,v3);
    }
  }

  /**
   * 组装job = map + reduce
   */
  public static void main(String[] args){
    try{
      if(args.length != 2){
        //如果传递的参数不够,程序直接退出
        System.exit(100);
      }

      // job需要配置的参数
      // 创建一个配置对象
      Configuration conf = new Configuration();
      // 创建一个job
      Job job = Job.getInstance(conf);

      // 注意:这一行必须设置,否则在集群中执行的是找不到WordCountJob这个类
      job.setJarByClass(WordCountJob.class);

      // 指定输入路径
      FileInputFormat.setInputPaths(job,new Path(args[0]));
      // 指定输出路径
      FileOutputFormat.setOutputPath(job,new Path(args[1]));

      // 指定map相关的代码
      job.setMapperClass(MyMapper.class);
      // 指定k2的类型
      job.setMapOutputKeyClass(Text.class);
      // 指定v2的类型
      job.setMapOutputValueClass(LongWritable.class);

      // 指定reduce相关的代码
      job.setReducerClass(MyReducer.class);
      // 指定k3的类型
      job.setOutputKeyClass(Text.class);
      // 指定v3的类型
      job.setOutputValueClass(LongWritable.class);

      // 提交job
      job.waitForCompletion(true);
    }catch (Exception e){
      e.printStackTrace();
    }
  }
}

(2)接着提交这个任务,此时再进入 yarn 8088 界面,点击任务对应的 history 链接就可以打开了:

(3)此时,点击对应 map reduce 后面的链接就可以点进去查看日志信息了,点击 map 后面的数字 1,可以进入如下界面。点击这个界面中的 logs 文字链接,可以查看详细的日志信息:

(4)在这里能看到很多日志信息,我们刚才使用 sout 输出的日志信息需要到 Log Type: stdout 这里来查看,在这里可以看到 k1 v1 的值:

(5)同样的,想要查看 reduce 输出的日志信息需要到 reduce 里面查看,操作流程是一样的,可以看到 k2,v2 k3,v3 的值:

附:使用命令查看日志

(1)我们使用类似如下命令查看任务日志,注意命令后面指定的是任务 id,任务 id 可以到 yarn web 界面上查看。
yarn logs -applicationId application_1717051629400_0003

(2)不过这种方式会看到很多的日志信息,我们通过 grep 筛选一下日志,方便定位查看:
yarn logs -applicationId application_1717051629400_0003 | grep k3,v3
评论0