CENTOS上的网络安全工具(十)走向Hadoop(2) MapReduce调试环境构建

        紧接上一篇,为了把MapReduce的示例搞明白,需要先把Hadoop上的java编译调试环境给整出来,毕竟,一些执行流程的具体细节被封装在了框架中,仅仅靠公开的源代码静态的解读还是太费事了。有了调试器就要方便得多,理解起来也会省事不少。

        一、构建基于CODE的Java编程调试环境

       1.安装配置Maven插件

        在已经安装好Single Node工作模式的Hadoop节点上,按照之前介绍过的方法,首先构建VSCODE环境。要在CODE上构建Java编程环境,需要安装Extension Pack For Java 插件包,主要安装了核Maven有关的6个插件:

        插件安装完成后记得重启一下VSCODE,否则在使用maven构建框架的时候有一定可能性会遇到莫名其妙退出的情况……

        新建一个testmr文件夹作为工作空间(比如本例在/root/testmr处),在该文件下环境下启动CODE。然后在文件标签页下面,也就是testmr这个空的工作空间下,右键,选择从Maven原型创建新项目:

         选择maven-archetype-quickstart构建一个Java框架

         在弹出的版本选择中,捡版本高的整吧:

         取个自己的组织名字(比如com.pigshome),注意这个名字后面会需要用到:

         给生成的框架起个名字(比如testmapreduce),框架会在testmr工作目录下生成一个名为testmapreduce的目录,并存放生成的App文件及测试文件。

         接下来会弹出一个对跨狂,要求选择项目所在的目录,我们将/root/testmr工作目录就作为项目的目录,所以选好了直接右上角的“selectDestination Folder”点击就行,然后等待CODE转啊转,此时是Maven在执行框架生成任务:

         转到进入交互式模式的时候,Maven会询问一些配置选择,不停的回车啊回车就可以了。

         到这里,框架就算生成完了。Maven会弹出一个对话框询问是新打开一个CODE还是使用当前这个。选open会新开一个,选add to worksapce就使用当前的。

        点开工作空间中testmapreduce的目录,会发现其下src目录下,有main、test两个子目录。我们主要在main下折腾,所以可以点开其下的App.java文件,这是一个java版本的hello world。

         选择调试标签,点击“运行和调试”,会启动当前打开的文件,也就是App.java。环境配置正常的话,应该会不出意外的输出“hello world!”。

        2.认识Pom.xml

        话说Maven作为java的编译环境构建者,其主要的环境配置信息是存储在名为Pom.xml的文件中的,这个在我们打开testmapreduce文件夹的时候就会发现,其内容如下所示:

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.pigshome</groupId>
  <artifactId>testmapreduce</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>testmapreduce</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <!-- 这里可以设置属性,类似宏变量,后面可以使用${名称}的方式引用
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <!-- 这里配置所有依赖项-->    
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-jar-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
        <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
        <plugin>
          <artifactId>maven-site-plugin</artifactId>
          <version>3.7.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-project-info-reports-plugin</artifactId>
          <version>3.0.0</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

        但在pom.xml文件中,目前除了properties组和dependencies组需要我们更改——实际一般dependencies就够了,其它可以暂时不关心。

        ——本文关于环境搭建的主要内容我们参考了VSCode+Maven+Hadoop开发环境搭建一文。该文中使用属性定义了版本号,故而在发生版本替代时,可以比较简单的更新一下属性的值就行。不过,在我们的试验中,更换版本号的事还是较少发生的,所以就不折腾了。:)

        二、配置MapReduce调试环境

        1.配置Hadoop依赖项仓库

         在Maven的仓库里搜索Hadoop的配置方法,按照Hadoop的要求增加依赖项。建议不要随意添加,那样可能会造成一些莫名奇妙的错误,比如dfs无法启动之类。

 

        再度核实一下版本号,别弄错了

         以hadoop-client为例

         点击3.3.3(因为我的hadoop安装版本是3.3.3)

        从Maven中复制 

<!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-client -->
<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-client</artifactId>
    <version>3.3.3</version>
    <scope>provided</scope>
</dependency>

        将其放入dependencies组中。此时pom.xml如下所示:

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.pigshome</groupId>
  <artifactId>testmapreduce</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>testmapreduce</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-client -->
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-client</artifactId>
        <version>3.3.3</version>
        <scope>provided</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-common -->
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-common</artifactId>
        <version>3.3.3</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-hdfs -->
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-hdfs</artifactId>
        <version>3.3.3</version>
        <scope>test</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-yarn-api -->
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-yarn-api</artifactId>
        <version>3.3.3</version>
    </dependency>
  </dependencies>

  <build>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-jar-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
        <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
        <plugin>
          <artifactId>maven-site-plugin</artifactId>
          <version>3.7.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-project-info-reports-plugin</artifactId>
          <version>3.0.0</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

        看看是否设置成功,在App.java中加入hadoop的支持:

package com.pigshome;


import java.util.Random;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.*;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.SequenceFileInputFormat;
import org.apache.hadoop.mapreduce.lib.map.InverseMapper;
import org.apache.hadoop.mapreduce.lib.map.RegexMapper;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.output.SequenceFileOutputFormat;
import org.apache.hadoop.mapreduce.lib.reduce.LongSumReducer;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;
/**
 * Hello world!
 *
 */
public class App 
{
    public static void main( String[] args )
    {
        System.out.println( "Hello World!" );
    }
}

        仍然能够成功运行,证明导入是成功的,虽然黄线部分会警告说导入的包都没用过

        2. 导入MapReduce项目

         如上篇最后所述,Hadoop示例教程中使用了Grep,一个对输入文件中每行字符进行正则匹配并统计命中的MapReduce算法。Grep的源文件在hadoop/share/hadoop/mapreuce/sources/目录下,名字为hadoop-mapreduce-examples-3.3.3-sources.jar

        (1)拷贝源文件

        使用jar命令将其解压出来,找到Grep.java文件。

[root@pig1 testmr]# mkdir examples
[root@pig1 testmr]# cd examples
[root@pig1 examples]# jar -xvf /root/hadoop/share/hadoop/mapreduce/sources/hadoop-mapreduce-examples-3.3.3-sources.jar 
  已创建: META-INF/
  已解压: META-INF/MANIFEST.MF
  已解压: META-INF/LICENSE.txt
  已解压: META-INF/NOTICE.txt
  已创建: org/
  已创建: org/apache/
  已创建: org/apache/hadoop/
  已创建: org/apache/hadoop/examples/
  已创建: org/apache/hadoop/examples/dancing/
  已创建: org/apache/hadoop/examples/terasort/
  已创建: org/apache/hadoop/examples/terasort/2009-write-up/
  已创建: org/apache/hadoop/examples/pi/
  已创建: org/apache/hadoop/examples/pi/math/
  已解压: org/apache/hadoop/examples/WordCount.java
  已解压: org/apache/hadoop/examples/WordMedian.java
  已解压: org/apache/hadoop/examples/BaileyBorweinPlouffe.java
  已解压: org/apache/hadoop/examples/MultiFileWordCount.java
  已解压: org/apache/hadoop/examples/dancing/OneSidedPentomino.java
  已解压: org/apache/hadoop/examples/dancing/DancingLinks.java
  已解压: org/apache/hadoop/examples/dancing/DistributedPentomino.java
  已解压: org/apache/hadoop/examples/dancing/Pentomino.java
  已解压: org/apache/hadoop/examples/dancing/Sudoku.java
  已解压: org/apache/hadoop/examples/dancing/package.html
  已解压: org/apache/hadoop/examples/dancing/puzzle1.dta
  已解压: org/apache/hadoop/examples/Join.java
  已解压: org/apache/hadoop/examples/AggregateWordCount.java
  已解压: org/apache/hadoop/examples/WordMean.java
  已解压: org/apache/hadoop/examples/ExampleDriver.java
  已解压: org/apache/hadoop/examples/terasort/TeraSortConfigKeys.java
  已解压: org/apache/hadoop/examples/terasort/TeraScheduler.java
  已解压: org/apache/hadoop/examples/terasort/GenSort.java
  已解压: org/apache/hadoop/examples/terasort/TeraGen.java
  已解压: org/apache/hadoop/examples/terasort/Random16.java
  已解压: org/apache/hadoop/examples/terasort/TeraValidate.java
  已解压: org/apache/hadoop/examples/terasort/TeraOutputFormat.java
  已解压: org/apache/hadoop/examples/terasort/TeraSort.java
  已解压: org/apache/hadoop/examples/terasort/TeraInputFormat.java
  已解压: org/apache/hadoop/examples/terasort/2009-write-up/1PBTaskTime.png
  已解压: org/apache/hadoop/examples/terasort/2009-write-up/100TBTaskTime.png
  已解压: org/apache/hadoop/examples/terasort/2009-write-up/500GBTaskTime.png
  已解压: org/apache/hadoop/examples/terasort/2009-write-up/Yahoo2009.tex
  已解压: org/apache/hadoop/examples/terasort/2009-write-up/tera.bib
  已解压: org/apache/hadoop/examples/terasort/2009-write-up/1TBTaskTime.png
  已解压: org/apache/hadoop/examples/terasort/Unsigned16.java
  已解压: org/apache/hadoop/examples/terasort/TeraChecksum.java
  已解压: org/apache/hadoop/examples/terasort/package.html
  已解压: org/apache/hadoop/examples/SecondarySort.java
  已解压: org/apache/hadoop/examples/DBCountPageView.java
  已解压: org/apache/hadoop/examples/pi/Parser.java
  已解压: org/apache/hadoop/examples/pi/TaskResult.java
  已解压: org/apache/hadoop/examples/pi/DistSum.java
  已解压: org/apache/hadoop/examples/pi/DistBbp.java
  已解压: org/apache/hadoop/examples/pi/SummationWritable.java
  已解压: org/apache/hadoop/examples/pi/Container.java
  已解压: org/apache/hadoop/examples/pi/Combinable.java
  已解压: org/apache/hadoop/examples/pi/math/Modular.java
  已解压: org/apache/hadoop/examples/pi/math/Summation.java
  已解压: org/apache/hadoop/examples/pi/math/LongLong.java
  已解压: org/apache/hadoop/examples/pi/math/Montgomery.java
  已解压: org/apache/hadoop/examples/pi/math/Bellard.java
  已解压: org/apache/hadoop/examples/pi/math/package.html
  已解压: org/apache/hadoop/examples/pi/math/ArithmeticProgression.java
  已解压: org/apache/hadoop/examples/pi/Util.java
  已解压: org/apache/hadoop/examples/pi/package.html
  已解压: org/apache/hadoop/examples/Grep.java
  已解压: org/apache/hadoop/examples/AggregateWordHistogram.java
  已解压: org/apache/hadoop/examples/Sort.java
  已解压: org/apache/hadoop/examples/WordStandardDeviation.java
  已解压: org/apache/hadoop/examples/QuasiMonteCarlo.java
  已解压: org/apache/hadoop/examples/RandomWriter.java
  已解压: org/apache/hadoop/examples/RandomTextWriter.java
  已解压: org/apache/hadoop/examples/package.html
[root@pig1 examples]# ls
META-INF  org

         将其拷贝到CODE项目中的源码目录下。根据JAVA的默认项目框架,源代码应该在工作目录testmapreduce下的src/main/java/com/pigshome下,当然这里com/pigshome是我的项目标识。

[root@pig1 examples]# cp org/apache/hadoop/examples/Grep.java ../testmapreduce/src/main/java/com/pigshome
[root@pig1 examples]# cd ../testmapreduce/src/main/java/com/pigshome
[root@pig1 pigshome]# ls
App.java  Grep.java
[root@pig1 pigshome]# 

        所以,需要在Grep中,将下图中红线指出包名改成我们自己的包名,如com.pigshome,和App.java中的一样。

         (2)配置输入参数

        如同示例一样,需要准备一个输入目录,并将hadoop/etc/hadoop/下的几个xml文件当小白鼠。至于输入目录,其实随便找个地方就行,我们是就在测试程序的同目录下建了一个input目录

[root@pig1 testmr]# mkdir input
[root@pig1 testmr]# cp /root/hadoop/etc/hadoop/*.xml input
[root@pig1 testmr]# ls
examples  input  testmapreduce
[root@pig1 testmr]# ls input
capacity-scheduler.xml  hdfs-rbf-site.xml  kms-acls.xml     yarn-site.xml
core-site.xml           hdfs-site.xml      kms-site.xml
hadoop-policy.xml       httpfs-site.xml    mapred-site.xml
[root@pig1 testmr]# 

        准备好以后,需要配置项目的launch.json文件,用来指定调试启动时的命令行参数。

        在CODE的调试标签页中选择自定义lauch.json文件, 生成launch.json文件如下所示:

        因为我们的main/java/com/pigshome目录下有App.java和Grep.java两个文件,所以生成的launch.json文件中包含了当前文件、App、Grep共3个启动选择项。所以,根据这个文件夹底下的文件不同,可能launch.json文件的项数会有不同。我们需要更改的是Grep这个启动项的参数。

        参考上一篇中我们测试时候的参数,指定我们准备的输入文件夹的位置,在Lauch Grep的组中增加"args"选项,填入输入参数。

{
    // 使用 IntelliSense 了解相关属性。 
    // 悬停以查看现有属性的描述。
    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "java",
            "name": "Launch Current File",
            "request": "launch",
            "mainClass": "${file}"
        },
        {
            "type": "java",
            "name": "Launch App",
            "request": "launch",
            "mainClass": "com.pigshome.App",
            "projectName": "testmapreduce"
        },
        {
            "type": "java",
            "name": "Launch Grep",
            "request": "launch",
            "mainClass": "com.pigshome.Grep",
            "projectName": "testmapreduce",
            "args": "/root/testmr/input /root/testmr/output 'dfs[a-z.]+'"
        }
    ]
}

         因为有3个启动项,所以在调试菜单中需要选择一下:

         选择Launch Grep,然后启动,执行完毕后,可以直接在终端中输入cat output/* 参看结果。

        当然,这是因为我们的工作目录就下testmr下,而参数指明了output生成在testmr下。这里需要提一下,前面我们并没有手工生成output,因为hadoop并不希望我们代劳。如果这个目录已经存在,Grep程序会报错……

        3.准备源代码支持

        一般来说,在Maven的支持下,作为开源项目的Hadoop,其内部实现的源码应该是可以在我们搭建的调试环境中,以右键“转到定义”或者“转到引用”等直接查看的。但不幸的是,在我搭建的3.3.4环境下,尚能看到RegexMapper.java源文件,在3.3.3环境下,就看不到了,Maven会给出无法找到源文件的错误,所以其自己根据调用关系逆向分析,生成一个空的RegexMapper类。

        更崩溃的是,我搭的两个一摸一样的3.3.4的环境,虽然都能看见RegexMapper类的源码,但一个有Configuration的源码,另一个死活都没有。

        一开始我以为是我的maven设置除了问题,一通找,包括在settings.json文件中增加maven.downloadsources选项也没有用。还好后来意识到一件事,顺着这个思路不仅搞定了这个问题,捎带脚着也解决了离线环境下的调试环境构建问题:

        首先捋清楚的是,maven是一个jar依赖包构建工具(这句话很普通,含义很关键)。一个java程序会用到很多jar包,并且这些jar包之间还会有复杂的依赖关系,手工添加会相当麻烦,所以要maven来帮忙。——这个听起来是不是十分的耳熟,这个怎么这么像yum呢……

        其次,我们在pom.xml中填写的那些东西,实际和我们在yum.repo.d目录下构建repo文件时写的没什么两样。那些内容,只不过是知道maven到mvnrepository网站上去下载对应的jar包罢了。这个也和yum异曲同工。

        所以,源码问题大概率是库本身就有问题(出于更重莫名原因的没有下载下来),没有下载到我们需要的依赖项和源文件。碰到这种库问题的时候,我们有这么2种方法去解决: 一是更换源,不过有可能新的源也不见得有;二是构建本地源,就像yum的createrepo一样。但是我也没啥兴趣去研究maven的命令,不知道如何下载并构建本地源,但是有一点是比较容易的——就是等maven下载好了,我们拷贝并且改造一下:

        最后,我们只需要知道,maven下载的库是存放在~/.m2文件夹下的,这是个隐藏文件夹,所以ls需要-a一下,使用窗口要记得打开“显示隐藏文件”。和hadoop相关的在repository/org/apache/hadoop目录下        

         对于Configuration的源文件,在hadoop-common/3.3.4下面,如果这个文件夹下只有hadoop-common-3.3.4.jar而没有hadoop-common-3.3.4-sources.jar,那么是不可能看见源代码的。解决方法也很简单,找到hadoop-common-3.3.4-sources.jar并且拷贝过来就行。这个文件,要么在能够看见源码的环境的对应地方,要么可以直接从hadoop网站上去下载的hadoop-3.3.4-src.tar.gz里面找到。

        到这里,再打一个节吧,贴的图太多了,每次往上翻都很难受,再开一贴。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值