第1章 环境准备
一般而言,在深入研究一个系统的技术细节之前,先要进行一些基本的准备工作,比如准备源代码阅读环境,搭建运行环境并尝试使用该系统等。然而,对于Hadoop而言,由于它是一个分布式系统,由多种守护进程组成,具有一定的复杂性,如果想深入学习其设计原理,仅仅进行以上几项准备工作是不够的,还要学习一些调试工具的使用方法,以便对Hadoop源代码进行调试、跟踪,边用边学,这样才能事半功倍。
本章编写目的是帮助读者构建一个“高效”的Hadoop源代码学习环境,包括Hadoop源代码阅读环境、Hadoop使用环境和Hadoop源代码编译调试环境等,主要涉及如下内容:
❑在Linux环境下搭建Hadoop源代码阅读环境;
❑在Linux环境下搭建一个Hadoop集群(包括YARN和HDFS两个系统);
❑Hadoop的基本使用方法,主要涉及Hadoop Shell和Eclipse插件两种工具的使用;
❑Hadoop源代码编译和调试方法,其中调试方法包括使用Eclipse远程调试和打印调试日志两种。
考虑到大部分用户在单机上学习Hadoop源代码,所以本章内容均是基于单机环境的。本章大部分内容较为基础,已经掌握这部分内容的读者可以直接跳过本章。
1.1 准备学习环境
对于大部分公司而言,实验和生产环境中的服务器集群部署的是Linux操作系统,考虑到Linux在服务器市场中具有统治地位,Hadoop从一开始便是基于Linux操作系统开发的,因而对Linux有非常完美的支持。尽管Hadoop采用了具有跨平台特性的Java作为主要编程语言,但由于它的一些功能实现用到了Linux操作系统相关的技术,因而对其他平台支持不够友好,且没有进行过严格测试。换句话说,其他操作系统(如Windows)仅可作为开发环境,不可作为生产环境。对于学习源代码而言,操作系统的选择显得不是非常重要,读者可根据个人爱好自行决定。本节以64bit Linux为例,介绍如何在单机上准备Hadoop源代码学习环境。
1.1.1 基础软件下载
前面提到Hadoop采用的开发语言主要是Java,因而搭建Hadoop环境所需的最基础软件首先应该包括Java基础开发包JDK和Java项目管理工具Maven,考虑到源代码阅读和调试的便利性,本书采用功能强大的集成开发环境Eclipse。搭建Hadoop阅读环境需要的各种软件以及下载方式如表1-1所示。
表1-1 搭建Hadoop阅读环境所需的软件
1.1.2 如何准备Linux环境
本节主要介绍如何准备Linux下Hadoop学习环境。搭建Linux学习环境需要安装JDK和Eclipse等软件。为了方便1.6节介绍Hadoop源代码编译方法,本节顺便安装Hadoop项目管理工具Maven。本文以64bit Ubuntu为例,介绍安装这些软件的方法,最终安装完成的目录结构为:
ROOT ├─home │ └─dong │ └─eclipse └─usr └─lib ├─apache-maven-3.0.5 └─jvm └─jdk1.6.0_25
1.JDK安装与配置
一般而言,Ubuntu系统会自带JDK,如果没有或者版本不合要求,可按以下步骤进行安装。
步骤1 安装JDK。
将下载的.bin文件复制到Linux的某个目录下,比如/usr/lib/jvm/,然后在Shell中执行以下命令为该文件添加可执行权限:
chmod +x /usr/lib/jvm/jdk1.6.0_25.bin
然后执行以下命令安装JDK:
sudo /usr/lib/jvm/jdk1.6.0_25.bin
之后将会出现安装信息,直至屏幕显示要求按下回车键,此时输入回车键后,会把JDK解压到文件夹jdk1.6.0_25中。至此,JDK已安装完毕,下面进行配置。
步骤2 配置JDK。
修改/etc/profile文件,在里面添加以下内容:
export JAVA_HOME=/usr/lib/jvm/jdk1.6.0_25 export PATH=$PATH:$JAVA_HOME/bin export CLASSPATH=$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib
输入以下命令使配置生效:
source /etc/profile
步骤3 修改默认JDK版本。
Ubuntu中可能会有默认的JDK,如openjdk,因而我们需要将自己安装的JDK设置为默认JDK版本,执行下面的代码:
sudo update-alternatives --install /usr/bin/java java /usr/lib/jvm/jdk1.6.0_25/bin/java 300 sudo update-alternatives --install /usr/bin/javac javac /usr/lib/jvm/jdk1.6.0_25/bin/javac 300 sudo update-alternatives --install /usr/bin/jar jar /usr/lib/jvm/jdk1.6.0_25/bin/jar 300 sudo update-alternatives --install /usr/bin/javah javah /usr/lib/jvm jdk1.6.0_25/bin/javah 300 sudo update-alternatives --install /usr/bin/javap javap /usr/lib/jvm/jdk1.6.0_25/bin/javap 300
然后执行以下代码选择我们安装的JDK版本:
sudo update-alternatives --config java
步骤4 验证JDK是否安装成功。
重启Shell终端,执行java -version命令,若输出以下内容,则说明安装成功:
java version "1.6.0_25" Java(TM) SE Runtime Environment (build 1.6.0_25-b06) Java HotSpot(TM) Client VM (build 20.0-b11, mixed mode, sharing)
2.安装、配置Maven及Eclipse
下面介绍Maven和Eclipse的安装、配置方法。
(1)安装与配置Maven
首先解压下载包,比如解压到文件/usr/lib/apache-maven-3.0.5目录下,然后修改/etc/profile文件,在里面添加以下内容:
export MAVEN_HOME=/usr/lib/apache-maven-3.0.5 export PATH=$PATH$:$ANT_HOME/bin
输入以下命令使配置生效:
source /etc/profile
同Windows下的验证方式一样,重启终端,执行mvn --version命令,若输出以下内容,则说明安装成功:
Apache Maven version 3.0.5 compiled on June 27 2008
(2)安装Eclipse
同Windows环境下安装方式一样,直接解压即可使用。
1.2 获取Hadoop源代码
当前比较流行的Hadoop源代码版本有两个:Apache Hadoop和Cloudera Distributed Hadoop(简称CDH)。Apache Hadoop是由雅虎、Cloudera、Facebook等公司组成的Hadoop社区共同研发的,它属于最原始的开源版本,在该版本基础上,很多公司进行了封装和优化,推出了自己的开源版本,其中,最有名的一个是Cloudera公司发布的CDH版本。
考虑到Apache Hadoop是最原始的版本,且使用最为广泛,因而本书选用了Apache Hadoop版本作为分析对象。自从Apache Hadoop发布以来,已经陆续推出很多版本(具体见2.2节),读者可自行在Hadoop SVN 地址http://svn.apache.org/repos/asf/hadoop/common/branches/查看或者下载所有版本,也可以从Apache官方主页http://hadoop.apache.org/releases.html上下载最新版本。
本书介绍的YARN属于Hadoop 2.0的一个分支(另外两个分支分别是HDFS和MapReduce),Hadoop 2.0的命名方式一般为hadoop-2.x.x。Apache官方主页提供了两个压缩包,一个是Hadoop源代码(hadoop-{VERSION}-src.tar.gz),一个是可直接用于部署的JAR包(hadoop-{VERSION}.tar.gz),Cloudera发布的CDH版本则将源代码和JAR包存放在一起组成一个压缩包(hadoop-2.0.0-cdh4.x.x.tar.gz)。
本书介绍的YARN设计思想适用于所有Apache Hadoop 2.x版本,但涉及具体的实现(指源代码级别的实现)时,则以Apache Hadoop 2.2.0及更高稳定版本为主,因此,如果你想对比Hadoop源代码阅读本书,推荐下载Apache 2.2.0或更高版本。
1.3 搭建Hadoop源代码阅读环境
1.3.1 创建Hadoop工程
本节将介绍如何创建一个Hadoop源代码工程以方便阅读源代码。总体上说,目前存在两种Hadoop源代码阅读环境搭建方法,分别是构建Maven工程和构建Java工程。两种方法各有利弊:前者可通过网络自动下载依赖的第三方库,但源代码会被分散到多个工程中进而带来阅读上的不便;后者可将所有源代码组织在一个工程中,但需要自己添加依赖的第三方库,大家可根据自己的喜好选择一种方法。本节将依次介绍这两种方法。
(1)构建Maven工程
通过Maven工程搭建Hadoop源代码阅读环境的步骤如下:
步骤1 解压缩Hadoop源代码。
将下载到的Hadoop源代码压缩包解压到工作目录下,比如hadoop-2.0-src.tar.gz(注意,为了方便,此处直接使用版本号2.0,实际下载到的源代码版本号并不是这样的,可能是2.2.0,这样压缩包的名字实际为hadoop-2.2.0-src.tar.gz)。
步骤2 导入Maven工程。
在Eclipse中,依次选择"File"→"Import"→"Maven"→"Existing Maven Project",在弹出的对话框中的"Root Directory"后面,选择Java源代码所在的目录。
单击"Next"按钮,在弹出的对话框中选择"Resolve All Later",并单击"Finish"按钮完成Maven项目导入。之后,Eclipse会自动通过网络从Maven库中下载依赖的第三方库(JAR包等)。注意,你所使用的电脑必须能够联网。
将Hadoop 2.0源代码导入Maven项目后,会生成50个左右的工程,这些都是通过Maven构建出来的,每个工程是一个代码模块,且彼此相对独立,可以单独编译。你可以在某个工程下的"src/main/java"目录下查看对应的源代码。
(2)构建Java工程
通过Java工程搭建Hadoop源代码阅读环境的步骤如下:
步骤1 解压缩Hadoop源代码。
同“构建Maven工程”中的步骤1类似。
步骤2 新建Java工程。
打开Eclipse,进入Eclipse可视化界面后,如图1-1所示,依次单击"File"→"New"→"Java Project",并在弹出的对话框中去掉"Use default location"前的勾号,然后选择Hadoop安装目录的位置,默认情况下,工程名称与Hadoop安装目录名称相同,用户可自行修改。单击“完成”按钮,Hadoop源代码工程创建完毕。
图1-1 新建Hadoop工程
回到Eclipse主界面后,打开新建的Hadoop工程,可看到整个工程按图1-2所示组织代码:按目录组织源代码,且每个目录下以JAR包为单位显示各个Java文件。
图1-2 Hadoop工程展示(部分)源代码方式
除了使用源代码压缩包导入Eclipse工程的方法外,读者可也尝试直接从Hadoop SVN上导入Hadoop源代码。
需要注意的是,通过以上方法导入Hadoop 2.0源代码后,很多类或者方法找不到对应的JAR包,为了解决这个问题,你需要将第三方JAR包导入工程中,如图1-3所示,方法如下:解压存放JAR包的压缩包,然后右击Project名称,在弹出的快捷菜单中选择"Properties"命令,将会弹出一个界面,然后在该界面中依次选择"Java Build Path"→"Libraries"→"Add External JARs...",将解压目录中share/hadoop目录下各个子目录中lib文件夹下的JAR包导入工程。
前面提到CDH版本将源代码和JAR包放到了一起,因此,如果使用CDH版本,则直接按照上述方法将源代码导入Eclipse工程即可。
细心的读者在阅读源代码过程中仍会发现部分类或者函数无法找到,这是因为Hadoop 2.0使用了Protocol Buffers定义了RPC协议,而这些Protocol Buffers文件在Maven编译源代码时才会生成对应的Java类,因此若其他类在源代码中引用这些类则暂时无法找到,解决方法是先编译Hadoop 2.0源代码再倒入Eclipse工程,具体方法如下(注意,进行以下步骤之前,需先完成1.6.1节中的准备工作)。
首先,使用以下命令安装Elicpse插件hadoop-maven-plugins:
图1-3 导入依赖的第三方JAR包
$ cd ${HADOOP_HOME}/hadoop-maven-plugins $ mvn install
然后生成Eclipse工程文件:
$ cd ${HADOOP_HOME} $ mvn eclipse:eclipse -DskipTests
最后在Eclipse中按照以下流程导入源代码:"File"→"Import"→"Existing Projects into Workspace"。
1.3.2 Hadoop源代码阅读技巧
本节介绍在Eclipse下阅读Hadoop源代码的一些技巧,比如:如何查看一个基类有哪些派生类,一个方法被其他哪些方法调用等。
(1)查看一个基类或接口的派生类或实现类
在Eclipse中,选中某个基类或接口名称,右击,在弹出的快捷菜单中选择"Quick Type Hierarchy",可在新窗口中看到对应的所有派生类或实现类。
例如,如图1-4所示,打开hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java目录下org.apache.hadoop.mapred包中的InputFormat.java文件,查看接口InputFormat的所有实现类,结果如图1-5所示。
(2)查看函数的调用关系
在Eclipse中,选中某个方法名称,右击,在弹出的快捷菜单中选择"Open Call Hierarchy",可在窗口"Call Hierarchy"中看到所有调用该方法的函数。
图1-4 在Eclipse中查看Hadoop源代码中接口InputFormat的所有实现类
图1-5 Eclipse列出接口InputFormat的所有实现类
例如,如图1-6所示,打开hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java目录下org.apache.hadoop.mapred包中的Task.java文件,查看调用getJobID方法的所有函数,结果如图1-7所示。
图1-6 在Eclipse中查看Hadoop源代码中所有调用Task.java中getJobID方法的函数
图1-7 Eclipse列出所有调用getJobID方法的函数
(3)快速查找类对象的相关信息
与前两个小节类似,选中类对象,右击,在弹出的快捷菜单中选择"Open Declaration",可跳转到类定义;选择"Quick Outline",可查看类所有的成员变量和成员方法,具体细节在此不做详细介绍,读者自行尝试。
1.4 Hadoop源代码组织结构
在Hadoop的JAR压缩包解压后的目录hadoop-{VERSION}中包含了Hadoop全部的管理脚本和JAR包,下面简单对这些文件或目录进行介绍。
❑bin:Hadoop最基本的管理脚本和使用脚本所在目录,这些脚本是sbin目录下管理脚本的基础实现,用户可以直接使用这些脚本管理和使用Hadoop。
❑etc:Hadoop配置文件所在的目录,包括core-site.xml、hdfs-site.xml、mapred-site.xml等从Hadoop 1.0继承而来的配置文件和yarn-site.xml等Hadoop 2.0新增的配置文件。
❑include:对外提供的编程库头文件(具体动态库和静态库在lib目录中),这些头文件均是用C++定义的,通常用于C++语言访问HDFS或者编写MapReduce程序。
❑lib:该目录包含了Hadoop对外提供的编程动态库和静态库,与include目录中的头文件结合使用。
❑libexec:各个服务对应的Shell配置文件所在目录,可用于配置日志输出目录、启动参数(比如JVM参数)等基本信息。
❑sbin:Hadoop管理脚本所在目录,主要包含HDFS和YARN中各类服务的启动/关闭脚本。
❑share:Hadoop各个模块编译后的JAR包所在目录。
在Hadoop 源代码压缩包解压后的目录hadoop-{VERSION}-src中,可看到如图1-8所示的目录结构,其中,比较重要的目录有:hadoop-common-project、hadoop-mapreduce-project、hadoop-hdfs-project和hadoop-yarn-project等,下面分别介绍这几个目录的作用。
❑hadoop-common-project:Hadoop基础库所在目录,该目录中包含了其他所有模块可能会用到的基础库,包括RPC、Metrics、Counter等。
图1-8 Hadoop安装目录结构
❑hadoop-mapreduce-project:MapReduce框架的实现,在MRv1中,MapReduce由编程模型(map/reduce)、调度系统(JobTracker和TaskTracker)和数据处理引擎(MapTask和ReduceTask)等模块组成,而此处的MapReduce则不同于MRv1中的实现,它的资源调度功能由新增的YARN完成(编程模型和数据处理引擎不变),自身仅包含非常简单的任务分配功能。
❑hadoop-hdfs-project:Hadoop分布式文件系统实现,不同于Hadoop 1.0中单NameNode实现,Hadoop 2.0支持多NameNode,同时解决了NameNode单点故障问题。
❑hadoop-yarn-project:Hadoop资源管理系统YARN实现。这是Hadoop 2.0新引入的分支,该系统能够统一管理系统中的资源,并按照一定的策略分配给各个应用程序,本书将重点剖析YARN的实现。
本书重点介绍YARN的实现原理,下面就对Hadoop YARN源代码组织结构进行介绍。YARN目录组织结构如图1-9所示。
总体上看,Hadoop YARN分为5部分:API、Common、Applications、Client和Server,它们的内容具体如下:
❑YARN API(hadoop-yarn-api目录):给出了YARN内部涉及的4个主要RPC协议的Java 声明和Protocol Buffers定义,这4个RPC协议分别是ApplicationClientProtocol、ApplicationMasterProtocol、ContainerManagementProtocol和ResourceManagerAdministrationProtocol,本书将在第2章对这部分内容进行详细介绍。
❑YARN Common(hadoop-yarn-common目录):该部分包含了YARN底层库实现,包括事件库、服务库、状态机库、Web界面库等,本书将在第3章对这部分内容进行详细介绍。
❑YARN Applications(hadoop-yarn-applications目录):该部分包含了两个Application编程实例,分别是distributedshell和Unmanaged AM,本书将在第4章对这部分内容进行详细介绍。
❑YARN Client(hadoop-yarn-client目录):该部分封装了几个与YARN RPC协议交互相关的库,方便用户开发应用程序,本书将在第4章对这部分内容进行详细介绍。
❑YARN Server(hadoop-yarn-server目录):该部分给出了YARN的核心实现,包括ResourceManager、NodeManager、资源管理器等核心组件的实现,本书将在第5~7章对这部分内容进行详细介绍。
图1-9 Hadoop YARN目录组织结构
1.5 Hadoop初体验
一般而言,我们想要深入学习一个新的系统时,首先要尝试使用该系统,了解系统对外提供的功能,然后再通过某个功能逐步深入其实现细节。本节将介绍如何在伪分布式工作模式下使用Hadoop,包括搭建Hadoop环境、访问HDFS以及向YARN提交应用程序等最基本的操作。本节只是有代表性地介绍Hadoop的一些基本使用方法,使读者对Hadoop有一个初步认识,并引导读者逐步进行更全面的学习。
1.5.1 搭建Hadoop环境
本小节仅介绍单机环境的搭建方法,更加完整的Hadoop安装步骤和配置方法可参考本书最后的附录A和附录B。另外,需要注意的是,由于不同用户拥有的Linux环境不尽相同(比如已经安装的软件不同、统一软件的版本不同等),每个人安装Hadoop过程中遇到的问题可能不同,此时需要根据具体的日志提示解决问题。本小节仅给出一般情况下,Hadoop 2.0的安装步骤。
步骤1 修改Hadoop配置文件。
1)设置环境变量。在${HADOOP_HOME}/etc/hadoop/hadoop-env.sh中,添加JAVA安装目录,命令如下:
export JAVA_HOME=/usrb/jvm/java-6-openjdk
修改conf目录下的mapred-site.xml、core-site.xml、yarn-site.xml和hdfs-site.xml四个文件,在<configuration>与</configuration>之间添加的内容见下面的介绍。
2)在${HADOOP_HOME}/etc/hadoop/下,将mapred-site.xml.templat重命名成mapred-site.xml,并添加以下内容:
<property> <name>mapreduce.framework.name</name> <value>yarn</value> </property>
【解释】相比于Hadoop1.0,用户无须再配置mapred.job.tracker,这是因为JobTracker相关实现已变成客户端的一个库(实际上在Hadoop 2.0中,JobTracker已经不存在,它的功能由另外一个称为MRAppMaster的组件实现),它可能被随机调度到任何一个slave上,也就是它的位置是动态生成的。需要注意的是,在该配置文件中需用mapreduce.framework.name指定采用的运行时框架的名称,在此指定"yarn"。
3)在${HADOOP_HOME}/etc/hadoop/中,修改core-site.xml,为了简单,我们仍采用Hadoop 1.0中的HDFS工作模式(不配置HDFS Federation),修改后如下:
<property> <name>fs.default.name</name> <value>hdfs://YARN001:8020</value> </property>
其中,YARN001表示节点的IP或者host。
4)在${HADOOP_HOME}/etc/hadoop/中,修改yarn-site.xml,修改后如下:
<property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce-shuffle</value> </property>
【解释】为了能够运行MapReduce程序,需要让各个NodeManager在启动时加载shuffle server,shuffle server实际上是Jetty/Netty Server,Reduce Task通过该server从各个NodeManager上远程复制Map Task产生的中间结果。上面增加的两个配置均用于指定shuffle server。
5)修改${HADCOP_HOME}/etc/hadoop中的hdfs-site.xml文件:
<property> <name>dfs.replication</name> <value>1</value> </property>
【解释】默认情况下,HDFS数据块副本数是3,而在集群规模小于3的集群中该参数会导致出现错误,这可通过将dfs.replication调整为1解决。
注意 如果你是在虚拟机中搭建Hadoop环境,且虚拟机经常关闭与重启,为了避免每次重新虚拟机后启动Hadoop时出现各种问题,建议在core-site.xml中将hadoop.tmp.dir属性设置为一个非/tmp目录,比如/data或者/home/dongxicheng/data(注意该目录对当前用户需具有读写权限)。
步骤2 设置免密码登录。
前面提到Hadoop启动/停止脚本需要通过SSH发送命令启动相关守护进程,为了避免每次启动/停止Hadoop都要输入密码进行验证,需设置免密码登录,步骤如下。
1)打开命令行终端,输入以下命令:
ssh-keygen -t rsa
将会在"~/.ssh/"目录下生成公钥文件id_rsa.pub和私钥文件id_rsa。
2)将公钥文件id_rsa.pub中的内容复制到相同目录下的authorized_keys文件中:
cd ~/.ssh/ cat id_rsa.pub >> authorized_keys
步骤3 启动Hadoop。
在Hadoop安装目录中,按以下三步操作启动Hadoop,我们单步启动每一个服务,以便于排查错误,如果某一个服务没有启动成功,可查看对应的日志查看启动失败原因。
1)格式化HDFS,命令如下:
bin/hadoop namenode -format
2)启动HDFS。你可以使用以下命令分别启动NameNode和DataNode:
sbin/hadoop-daemon.sh start namenode sbin/hadoop-daemon.sh start datanode
如果有多个DataNode,可使用hadoop-daemons.sh启动所有DataNode,具体命令如下:
sbin/hadoop-daemons.sh start datanode
你也可以使用以下命令一次性启动NameNode和所有DataNode:
sbin/ start-dfs.sh
3)启动YARN。你可以使用以下命令分别启动ResourceManager和NodeManager:
sbin/hadoop-daemon.sh start namenode sbin/hadoop-daemon.sh start datanode
如果有多个NodeManager,可使用yarn-daemon.sh启动所有NodeManager,具体命令如下:
sbin/yarn-daemon.sh start nodemanager
你也可以使用以下命令一次性启动ResourceManager和所有NodeManager:
sbin/start-yarn.sh
通过如下jps命令查看是否启动成功:
dong@YARN001:/opt/hadoop/hadoop-2.0$ jps 27577 NameNode 30315 ResourceManager 27924 SecondaryNameNode 16803 NodeManager
通过以下URL可查看YARN是否启动成功:
http://YARN001:8080/
YARN对外提供的Web运行界面如图1-10所示。
图1-10 YARN对外提供的Web界面
如果安装过程中出现问题,可通过查看日志发现问题所在。Hadoop日志存放在$HADOOP_HOME/logs目录下的以".log"结尾的文件中,比如yarn-dongxicheng-resourcemanager-yarn001.log就是ResourceManager产生的日志。
经过以上三步操作,Hadoop成功启动后,接下来可以通过Hadoop Shell或者Eclipse插件访问HDFS和提交MapReduce作业。下面两小节分别介绍Hadoop Shell和Eclipse插件使用方法。
1.5.2 Hadoop Shell介绍
在1.4节我们曾提到,bin目录下是最基础的集群管理脚本,用户可以通过该脚本完成各种功能,如HDFS文件管理、MapReduce作业管理等,更加详细的脚本使用说明,可参考附录C。
作为入门,本节介绍的是bin目录下Hadoop脚本的使用方法。如果你已经对Hadoop 1.0有所了解(比如尝试安装和使用过Hadoop 1.0),那么可直接使用该脚本,因为该脚本的功能与Hadoop 1.0对应的Hadoop脚本功能完全一致。
该脚本的使用方法为:
hadoop [--config confdir] COMMAND
其中,--config 用于设置Hadoop配置文件目录。默认目录为${HADOOP_HOME}/conf。而COMMAND是具体的某个命令,常用的有HDFS管理命令fs、作业管理命令job和作业提交命令jar等,它们的使用方法如下。
(1)HDFS管理命令fs和作业管理命令job
它们的用法一样,均为:
bin/hadoop command [genericOptions] [commandOptions]
其中,command可以是fs或者job,genericOptions是一些通用选项,commandOptions是fs或者job附加的命令选项,看下面两个例子。
❑在HDFS上创建一个目录/test,命令如下:
bin/hadoop fs -mkdir /test
❑显示所有Hadoop上正在运行的作业,命令如下:
bin/hadoop job -list
(2)作业提交命令jar
这个命令的用法是:
hadoop jar <jar> [mainClass] args..
其中,<jar>表示JAR包名,mainClass表示main class名称,可以不必输入而由jar命令自动搜索,args是main class输入参数。举例如下:
bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-*.jar pi 5 10
其中pi是hadoop-mapreduce-examples-*.jar 中一个作业名称,该作业主要功能是采用拟蒙特卡罗法估算圆周率pi(3.1415926…)的大小,它有两个整型输入参数:Map Task数目和样本数目。
其他更多命令,读者可自行查阅Hadoop官方设计文档。
1.6 编译及调试Hadoop源代码
读者在阅读源代码过程中,可能需要修改部分源代码或者使用调试工具以便跟踪某些变量值变化过程,此时要用到Hadoop源代码编译和调试方法。本节将介绍Hadoop在伪分布式模式下的编译和调试方法,其中调试方法主要介绍使用Eclipse远程调试工具和打印调试日志两种。
Hadoop天生支持Linux而对其他操作系统(如Windows)很不友好,本书也鼓励读者直接在Linux平台下编译和调试Hadoop源代码,因此,本节介绍的内容全部在Linux环境下。
1.6.1 编译Hadoop源代码
在Linux环境下编译源代码之前,需进行以下准备工作:
❑确保安装的Maven版本在3.0.2以上;
❑Protocol Buffers安装版本为2.5.0;
❑如果要启用findbugs,则需确认已经安装了Findbugs;
❑如果要编译native code,则需确认安装了CMake 2.6或者更新版本;
❑第一次编译代码,需确认可以连接互联网(Maven要从代码库中下载依赖包)。
Maven编译命令如表1-2所示。
表1-2 Maven编译命令
如果仅编译生成JAR包而无须编译native code、测试用例和生成文档,可在Hadoop安装目录下并输入以下命令(推荐使用该命令编译Hadoop源代码):
mvn package -Pdist -DskipTests -Dtar
如果编译JAR包、native code并生成文档,可使用以下命令:
mvn package -Pdist,native,docs -DskipTests -Dtar
每个子模块编译后生成的JAR包放到了与源代码目录平级的target目录中,比如ResourceManager的源代码目录是:
${YARN_HOME}/hadoop-yarn-project/hadoop-yarn/hadoop-yarn- server/hadoop-yarnserver-resourcemanager/src
它对应生成JAR包放在了以下目录中:
${YARN_HOME}/hadoop-yarn-project/hadoop-yarn/hadoop-yarn- server/hadoop-yarnserver-resourcemanager/target
如果修改了某个模块的代码,可编译后,将对应的JAR包覆盖到${HADOOP_HOME}/share/hadoop目录中对应的JAR包上。
如果仅编译Hadoop的某一个子模块,需将该模块依赖的JAR包作为它的第三方库引入。一种简单的实现方式是在Hadoop安装目录下输入以下命令编译所有源代码:
mvn install -DskipTests
然后进入子模块目录,编译生成对应的JAR包。
1.6.2 调试Hadoop源代码
本节介绍两种调试Hadoop源代码的方法:利用Eclipse远程调试工具和打印调试日志。这两种方法均可以调试伪分布式工作模式和完全分布式工作模式下的Hadoop。本节主要介绍伪分布式工作模式下的Hadoop调试方法。
(1)利用Eclipse进行远程调试
下面以调试ResourceManager为例,介绍利用Eclipse远程调试的基本方法,这可分两步进行。
步骤1 调试模式下启动Hadoop。
在Hadoop安装目录下运行如下的Shell脚本:
export YARN_NODEMANAGER_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,address=8788, server=y,suspend=y" sbin/start-all.sh
运行了脚本后会看到Shell命令行终端显示如下信息:
Listening for transport dt_socket at address: 8788
此时表明ResourceManager处于监听状态,直到收到debug确认信息。
步骤2 设置断点。
在前面新建的Java工程"hadoop-2.0"中,找到ResourceManager相关代码,并在感兴趣的地方设置一些断点。
步骤3 在Eclipse中调试Hadoop程序。
在Eclipse的菜单栏中,依次选择"Run"→"Debug Configurations"→"Remote Java Applications",并按照要求填写远程调试器名称(自己定义一个即可),ResourceManager所在host以及监听端口号等信息,并选择Hadoop源代码工程,便可进入调试模式。
调试过程中,ResourceManager输出的信息被存储到日志文件夹下的yarn-XXX-resourcemanager-localhost.log文件(XXX为当前用户名)中,可通过以下命令查看调试过程中打印的日志:
tail -f logs/yarn-XXX-resourcemanager-localhost.log
(2)打印Hadoop调试日志
Hadoop使用了Apache log4j作为基本日志库,该日志库将日志分别5个级别,分别为DEBUG、INFO、WARN、ERROR和FATAL。这5个级别是有顺序的,即DEBUG <INFO <WARN <ERROR <FATAL,分别用来指定日志信息的重要程度。日志输出规则为:只输出级别不低于设定级别的日志信息,比如若级别设定为INFO,则INFO、WARN、ERROR和FATAL级别的日志信息都会输出,但级别比INFO低的DEBUG则不会输出。
在Hadoop源代码中,大部分Java文件中存在调试日志(DEBUG级别日志),但默认情况下,日志级别是INFO,为了查看更详细的运行状态,可采用以下几种方法打开DEBUG日志。
方法1 使用Hadoop Shell命令。
可使用Hadoop脚本中的daemonlog命令查看和修改某个类的日志级别,比如,可通过以下命令查看NodeManager类的日志级别:
bin/hadoop daemonlog -getlevel ${nodemanager-host}:8042 \ org.apache.hadoop.yarn.server.nodemanager.NodeManager
可通过以下命令将NodeManager类的日志级别修改为DEBUG:
bin/hadoop daemonlog -setlevel ${nodemanager-host}:8042 \ org.apache.hadoop.yarn.server.nodemanager.NodeManager DEBUG
其中,nodemanager-host为NodeManager服务所在的host,8042是NodeManager的HTTP端口号。
方法2 通过Web界面。
用户可以通过Web界面查看和修改某个类的日志级别,比如,可通过以下URL修改NodeManager类的日志级别:
http://${nodemanager-host}:8042/logLevel
方法3 修改log4j.properties文件。
以上两种方式只能暂时修改日志级别,当Hadoop重启后会被重置,如果要永久性改变日志级别,可在目标节点配置目录下的log4j.properties文件中添加以下配置选项:
log4j.logger.org.apache.hadoop.yarn.server.nodemanager.NodeManager=DEBUG
此外,有时为了专门调试某个Java文件,需要把该文件的相关日志输出到一个单独文件中,可在log4j.properties中添加以下内容:
# 定义输出方式为自定义的TTOUT log4j.logger. org.apache.hadoop.yarn.server.nodemanager.NodeManager=DEBUG,TTOUT # 设置TTOUT 的输出方式为输出到文件 log4j.appender.TTOUT =org.apache.log4j.FileAppender # 设置文件路径 log4j.appender.TTOUT.File=${hadoop.log.dir}/NodeManager.log # 设置文件的布局 log4j.appender.TTOUT.layout=org.apache.log4j.PatternLayout # 设置文件的格式 log4j.appender.TTOUT.layout.ConversionPattern=%d{ISO8601} %p %c: %m%n
这些配置选项会把NodeManager.java中的DEBUG日志写到日志目录下的NodeManager.log文件中。
在阅读源代码的过程中,为了跟踪某个变量值的变化,读者可能需要自己添加一些DEBUG日志。在Hadoop源代码中,大部分类会定义一个日志打印对象,通过该对象可打印各个级别的日志。比如,在NodeManager中用以下代码定义对象LOG:
public static final Log LOG = LogFactory.getLog(NodeManager.class);
用户可使用LOG对象打印调试日志。比如,可在NodeManager的main函数首行添加以下代码:
LOG.debug("Start to lauch NodeManager...");
然后重新编译Hadoop源代码,并将org.apache.hadoop.yarn.server.nodemanager.NodeManager的调试级别修改为DEBUG,重新启动Hadoop后便可以看到该调试信息。
1.7 小结
搭建一个高效的源代码学习环境是深入学习Hadoop的良好开端,本章主要内容正是帮助读者搭建一个这样的学习环境。在笔者看来,一个高效的Hadoop学习环境至少应该包括源代码阅读环境、Hadoop使用环境和源代码编译调试环境,而本章正是围绕这三个环境的搭建方法组织的。
本章介绍了Linux环境下搭建Hadoop源代码阅读环境的方法,在此基础上,进一步介绍了Hadoop的基本使用方法,主要涉及Hadoop Shell和Eclipse插件两种工具的使用。最后介绍了Hadoop源代码编译和调试方法,其中,调试方法主要介绍了使用Eclipse远程调试和打印调试日志两种。