以下备忘自己学习 Hadoop 过程中学到的内容。
1. 狭义 Hadoop 与 广义 Hadoop
如 Hadoop 官网 所说,Hadoop 项目包含四部分:
The project includes these modules:
Hadoop Common: The common utilities that support the other Hadoop modules.
Hadoop Distributed File System (HDFS™): A distributed file system that provides high-throughput access to application data.
Hadoop YARN: A framework for job scheduling and cluster resource management.
Hadoop MapReduce: A YARN-based system for parallel processing of large data sets.
随着大数据技术的蓬勃发展,人们提起 Hadoop 时,已经将其作为大数据生态的代名词。后续大量的大数据相关项目都或多或少地基于或提供了对 Hadoop 模块的支持。
以下对 Hadoop 中 hdfs 和 YARN 模块的架构进行介绍。
2. hdfs 架构
2.1 NameNode & DataNode
在 hdfs 架构中,文件按照配置被拆分成多个文件块进行存储( 默认为 128M )。基于此,在 hdfs 中主要有两个角色。其中,NameNode,简称 NN,负责应对客户端的请求、并记录文件块的元信息,如文件被如何拆分、如何存储等;而 DataNode,简称 DN,则负责对文件块进行读写,并以心跳包的方式按时上报自己的存活情况及所存储文件块的情况,用于 NameNode 进行实时容错排查。
在 hdfs 中,有以下内容需要注意:
- hdfs 属于 Master/Slave 架构的。在集群中,一般存在一个 NameNode 和多个 DataNode;
- 由于存在文件块的机制,对一个文件而言,分解之后,其只有最后一个文件块的大小不是 128M( 配置 );
- 又由于 NameNode 上存储着所有文件块的元信息,可想而知,大量的小文件必将增加 NameNode 的负载;
- 在同一时间只能有一个进程在 hdfs 上进行写操作。
2.2 hdfs 副本机制
在集群中,hdfs 会根据配置对文件块进行冗余存储。其副本存储策略为:首先挑选网络拓扑中距离最近的一个节点(一般在同一机架)存储一份;然后在相邻机架上挑选两个节点各存储一份;如果副本因子大于 3,则后续的副本存储会随机挑选节点进行。
2.3 hdfs 中的读操作
对于一个 User 端的请求( 来自 hdfs 交互式终端或编程接口 ),首先会在向 NameNode 中获取元数据信息。由于每一个文件可能被拆分为多个文件块进行存储,且每一个文件块都含有若干备份,所以 NameNode 会返回该文件所对应的所有文件块,且对于每一个文件块,都附带其备份所在的 DataNode 以用于读取( 备份 DataNode 列表是已排序的 )。
对于每一个文件块,Client Node 会进行如下操作:
- Client Node 发起读请求,向该文件块所在 DataNode 列表中的第一个节点( 即排序最优的备份 )进行读取;
- 当该文件块读取完毕后,关闭与该 DataNode 的连接,并继续读取下一个文件块,方式同 1;
- 重复 2 直到该文件所有的文件块读取完毕。
上图中所示的 InputStream
对象是文件系统为用户创建的操作节点进行读取操作的对象。
2.4 hdfs 中的写操作
对于一个 User 端的请求( 来自 hdfs 交互式终端或编程接口 ),首先会在 Client Node 中按照用户配置的块大小进行拆分,然后对于每一个文件块,会有如下步骤执行:
- Client Node 向 NameNode 发起请求;
- NameNode 按照副本系数和 DataNode 的情况返回需要存储该文件块的 DataNode 序列( 已排序的 );
- Client Node 向列表中的第一个 DataNode 发起写文件块请求;
- Client Node 在成功将文件块数据写入磁盘后,会将写磁盘块数据的任务发送给列表中的下一个节点;
- 重复上一步直到列表的最后一个节点;
- 当所有节点都写出完成后,Client Node 会收集写入成功的确认信息,并向 NameNode 确认节点写入完毕。
上图中所示的 OutputStream
对象是文件系统为用户创建的操作节点进行写入操作的对象。
有关上述过程的 API 操作过程可以参考:Hadoop之HDFS文件读写过程
2.5 hdfs 容错机制
对分布式文件存储而言,由于其产生的最初场景就是针对大规模廉价存储介质,因而其对高可用的保证是足够到位的。以下就介绍多种故障场景及其容错机制。
0. 心跳包机制
NameNode 上不仅记录了所有文件的元数据,还记录了所有节点的信息。即每一个文件所对应的文件块及其存储的 DataNode 列表、以及每一个 DataNode 上存储的文件块信息与健康状态。
每隔一段时间,DataNode 都会上报自己所维护的所有文件块情况,这一周期性的心跳包机制可以起到如下作用:
- 判断该 DataNode 是否存活,故障的 DataNode 会在读写操作中被移除,并触发备份的重新规划;
- 判断该 DataNode 上存储的文件块信息与自己存储的文件块信息是否匹配。
此外,对于「丢失连接」的节点,NameNode 还会定期试探其是否恢复了连接。
1. NameNode 节点损坏或无法连接
如果发生这种事件,在单 NameNode 情况下,整个 hdfs 集群就完全崩溃了。因为即使文件真正存储的地方—— DataNode 没有损坏,由于失去了元数据,因而也无法将文件块拼凑成完整的文件。
但现在一般都会默认开启 SecondaryNameNode,或采用多 NameNode 节点的方式来规避这一问题。但由于同一时间只会有一个 NameNode 起作用,且备用 NameNode 中的元信息并不是完全一致的。因而当这一情况发生时,也很可能发生一定的文件丢失。
2. 某一 DataNode 节点损坏或无法连接
只要备份系数是大于一的( 且有多个 DataNode ),则出现这一情况时,文件不会发生丢失。且由于心跳包机制,丢失节点上所负责的备份会转移到其他节点上。
3. 全部 DataNode 节点损坏或无法连接
如果某一文件对应文件块所存储于的所有 DataNode 都发生了损坏,则该文件也就丢失了。
但考虑到 NameNode 会在心跳包中对损坏节点上所维护的文件块进行再分配,除非这些节点在很短时间内全部损坏,否则是不会发生这种情况的。
4. 在读取文件过程中,某一文件块所在 DataNode 无法连接
由于每一个文件块都有若干个备份,被存储在不同的 DataNode 上,在读取过程中,如果有 DataNode 发生了损坏,则会顺延地到 DataNode 列表的下一个节点上读取。
5. 读取的文件块数据损坏
由于每一个文件块之后都存在校验机制,如果某一文件块中的数据发生了损坏,在读取该文件块后,可以通过对比发现这一问题。
此外,由于 DataNode 也会周期性自检内部数据的完整性和正确性,并周期性上报这一信息,因而这样的情况也不易发生。
6. 在写入文件过程中,某一文件块所在 DataNode 无法连接
如果在某一文件块的写入过程中,需要写入的 DataNode 列表中存在某一个损坏的节点,则会返回错误,Client Node 会将成功的节点和失败的节点上报 NameNode。由于在这一情况发生时,文件块的备份 DataNode 情况是不符合要求的,在之后的调整机制中,会对此进行弥补。
3. YARN 架构
3.1 YARN 背景
如上图所示,在 Hadoop 1.x 中,任务调度采用 JobTracker 和 TaskTracker 的机制。
对集群而言,这一架构使得资源调度模型只能适用于 MapReduce 任务。主要基于这个原因( 还包括如 JobTracker 承担过多指责而导致的性能问题、单点故障等 ),催生了 YARN 的诞生。YARN 可以使得集群资源为其上运行的多种框架共享,从而提高了资源的利用率。
3.2 ResourceManager & NodeManager & ApplicationMaster & Container
在 YARN 架构中,由以下四个重要的角色:
- ResourceManager:简称 RM,是同一时间集群上唯一的一个资源管理和调度者。负责处理 Client 的请求、并对 NM 进行管理;
- NodeManager:简称 NM,集群上每个节点都会运行一个 NM,负责管理与上报当前节点的资源情况和 Container 运行状态,并根据 AM 的指令对 Continer 进行启动、停止等多种请求。当 RM 宕机时,会自动连接备用 RM 节点;
- ApplicationMaster:简称 AM,每个应用程序对应一个 AM。负责为自身的任务向 RM 索要资源。且需要与 NM 进行通信,用于控制 Container 的启动和停止( AM 也运行在 Container 之中 );
- Container:是 CPU、内存等资源的抽象;也是任务运行的容器。
3.3 YARN 工作机制
如图所示,当有 Client 提交任务时,会发生以下步骤:
- RM 会为其选择一个 NM 并创建 AM,AM 会想 RM 注册自己,此后 AM 和 RM 会保持心跳;
- AM 会将任务所需要的资源上报 RM;
- RM 会根据 AM 的申请和现有资源状况分配资源,这些资源信息会由 AM 进行初始化,与对应的 NM 通信以创建 Container,此后 AM 会与这些 NM 保持心跳以监控其上任务的运行;
- Container 会在运行期间通过 RPC 向 AM 汇报进度和状态信息;
- 在整个运行期间,Client 会与 AM 直接通信以获得任务的运行状态;
- 当应用结束后,AM 会向 RM 注销自己,并允许其释放分配给自己的 Container。
4. 关于 MapReduce
有关 MapReduce 可以参考 MapReduce原理与设计思想 或其他文章。
5. 安装单机 Hadoop
5.1 配置本地 SSH 免登陆
由于 NameNode 在启动后会通过 SSH 完成对 DataNode 节点上守护进程的启动和停止,所以我们需要在 NameNode 上配置好对 DataNode 的免密登陆( 注意这里是单机模式,NameNode 和 DataNode 启动在同一台主机上 )。
执行以下命令,生成公私钥对:
ssh-keygen -t rsa
一路回车后,执行以下命令,配置本地对本地的免登陆:
ssh-copy-id -i ~/.ssh/id_rsa.pub localhost
此后,执行:
ssh root@localhost
便可以无密码登录了。
5.2 安装 JDK
由于大部分较新版本的大数据软件都要求使用 JDK1.8 以上,这里也依次为准。
首先,由 官网 下载 jdk-8u151-linux-x64.tar.gz。而后解压到某一目录( 这里选择 /app
,后续均为此目录 ):
tar -zxvf jdk-8u151-linux-x64.tar.gz -C /app
之后将其 bin
子目录添加到环境变量之中。修改 ~/.bash_profile
文件:
JAVA_HOME=/app/jdk1.8.0_151
export PATH=$PATH:$JAVA_HOME/bin
5.3 安装 Hadoop
由于 CDH 版本在企业中使用的比例较高,这里也选用这个版本。在以下网址中下载 hadoop-2.6.0-cdh5.7.0.tar.gz :
http://archive-primary.cloudera.com/cdh5/cdh/5/
将下载后的文件解压:
tar -zxvf hadoop-2.6.0-cdh5.7.0.tar.gz -C /app
并将子目录 bin
其配置到环境变量之中。修改 ~/.bash_profile
,并添加:
HADOOP_HOME=/app/hadoop-2.6.0-cdh5.7.0
export PATH=$PATH:$HADOOP_HOME/bin
5.4 修改 Hadoop 配置
1. 修改 $HADOOP_HOME/etc/hadoop/hadoop-env.sh
:
将:
export JAVA_HOME=${JAVA_HOME}
修改为:
export JAVA_HOME=/app/jdk1.8.0_151
2. 修改 $HADOOP_HOME/etc/hadoop/core-site.xml
在 configuration
标签中添加:
<property>
<name>fs.default.name</name>
<value>hdfs://localhost:8082</value>
</property>
3. 修改 $HADOOP_HOME/etc/hadoop/slaves
文件
由于我们这里使用的是单机模式的 Hadoop,此文件无需改动。
5.5 hdfs 配置与启动
1. 修改 hdfs 相关配置
修改 $HADOOP_HOME/etc/hadoop/hdfs-site.xml
,在 configuration
标签中添加:
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
<property>
<name>dfs.namenode.name.dir</name>
<value>/app/hdfs_tmp/dfs/name</value>
</property>
<property>
<name>dfs.datanode.data.dir</name>
<value>/app/hdfs_tmp/dfs/data</value>
</property>
2. 格式化 NameNode
执行以下命令以格式化 NameNode。此命令的执行与 hdfs-site.xml
中配置的 dir
有关。此外,由于每次执行都会重置文件系统,需要特别注意误操作。
hdfs namenode -format
3. 启动
执行以下指令:
cd $HADOOP_HOME/sbin
./start-dfs.sh
4. 检验启动结果
我们可以使用以下两种方式检验 hdfs 的启动情况:
1. 通过 jps
命令
执行以下命令:
jps
查看是否已经启动了如下进程:
DataNode
NameNode
SecondaryNameNode
2. 通过 UI 方式查看
通过访问:
http://${IP}:50070
可以查看 hdfs 的启动情况。
5. 部分问题解决
当对 hdfs 进行操作,如使用 hdfs dfs -mkdir /test
时,可能会出现:Hadoop Name node is in safe mode
的提示。此时可以通过以下命令移除安全模式:
hdfs dfsadmin -safemode leave
5.6 YARN 配置与启动
1. 修改 YARN 相关配置
将 $HADOOP_HOME/etc/hadoop/mapred-site.xml.template
复制一份名为: mapred-site.xml
,为其 configuration
添加内容:
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
修改 $HADOOP_HOME/etc/hadoop/yarn-site.xml
,为其 configuration
添加内容:
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
2. 启动 YARN
使用以下命令启动 YARN:
$HADOOP_HOME/sbin/start-yarn.sh
3. 查看启动情况
同样的,我们可以使用以下两种方式检验 YARN 的启动情况:
1. 通过 jps
命令:
jps
查看是否已经启动了如下进程:
ResourceManager
NodeManager
2. 通过 UI 方式查看
通过访问:
http://${IP}:8088
可以查看 yarn 的启动情况。
4. 运行测试用例
我们可以使用官方提供的测试用例来测试效果:
hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.6.0-cdh5.7.0.jar pi 2 3
5. 其他启动方式
在 $HADOOP_HOME/sbin
下,我们可以通过:
./start-all.sh
的方式启动 YARN 和 hdfs,但我们会收到提示:
This script is Deprecated. Instead use start-dfs.sh and start-yarn.sh
6. 安装集群 Hadoop
这里只介绍搭建集群时,需要额外进行的配置。
假设我们现在有三台机器,分别为:
192.168.0.1(主)
192.168.0.2(从)
192.168.0.3(从)
如上,我们把 192.168.0.1
当做主节点。由上述内容可知,该机器会在之后承担 hdfs 中 NameNode
和 YARN 中 ResourceManager
的角色。
由此,我们可以知道,在预期搭建的集群中,承担 DataNode
和 NodeManager
的为:
192.168.0.1
192.168.0.2
192.168.0.3
6.1 配置 SSH 免密码登录
首先,我们要确保三台机器都已经安装了 SSH。且都已执行以下代码生成了公私钥对:
ssh-keygen -t rsa
由于 NameNode
需要通过 SSH 对 DataNode
进行操作,所以我们需要为 192.168.0.1
配置好对其他节点( 包括自己 )的免登陆,即在 192.168.0.1
上执行:
ssh-copy-id -i ~/.ssh/id_rsa.pub 192.168.0.1
ssh-copy-id -i ~/.ssh/id_rsa.pub 192.168.0.2
ssh-copy-id -i ~/.ssh/id_rsa.pub 192.168.0.3
6.2 集群配置
首先,我们需要在主节点 192.168.0.1
上将 JDK 和 Hadoop 下载解压到 /app
目录,并按照单节点方式对其进行了配置( 包括环境变量和 Hadoop 配置 )。
接着我们需要针对集群情况对之前的配置进行一定修改。
1. hadoop-env.sh
该文件无需额外修改。
2. core-site.xml
该文件无需额外修改。
3. hdfs-site.xml
我们需要将副本系数改为 3,而关于 name.dir
和 data.dir
的配置可以不做修改:
<property>
<name>dfs.replication</name>
<value>3</value>
</property>
<property>
<name>dfs.namenode.name.dir</name>
<value>/app/hdfs_tmp/dfs/name</value>
</property>
<property>
<name>dfs.datanode.data.dir</name>
<value>/app/hdfs_tmp/dfs/data</value>
</property>
由于 hdfs 默认的副本系数即为 3,这里也可以省略有关 dfs.replication
的配置。
4. yarn-site.xml
除了之前对 nodemanager.aux-services
的修改,我们还需要添加一些配置,修改后的结果为:
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<name>yarn.resourcemanager.hostname</name>
<value>192.168.0.1</value>
</property>
注意:由于这些配置文件会被分发到各个子节点,resourcemanager.hostname
切勿写成 localhost
5. mapred-site.xml
该文件无需额外修改。
6. slaves
该文件与上述文件在同一路径下,在集群配置中,我们需要对此进行修改:
192.168.0.1
192.168.0.2
192.168.0.3
注意,由于我们在主节点上也运行了一个 DataNode
和 NodeManager
,故而该节点既起到了主节点作用,也承担了从节点的服务。
6.3 分发 JDK & Hadoop
按照之前的做法,我们已经对主节点完成了 JDK、Hadoop 的安装和配置,此时可以直接将该文件夹通过以下指令发送到其他其他两台机器上:
scp -r /app 192.168.0.2:/
scp -r /app 192.168.0.3:/
这样一来,只需等待传输结束,就可以在其他两台机器上完成相关软件的安装和配置。
6.4 分发环境变量配置
由于我们还在 ~/.bash_profile
中配置了环境变量,所以该文件也需要发送到两台从服务器上:
scp ~/.bash_profile 192.168.0.2:~/
scp ~/.bash_profile 192.168.0.3:~/
这之后,我们需要登录到两台从服务器上,使用以下命令使该配置文件生效:
source ~/.bash_profile
6.5 NameNode 格式化
在主节点上,执行以下指令,进行 NameNode 的格式化:
hdfs namenode -format
注意,如果在先前的单机配置中已经进行过了格式化,需要将原有的 hdfs_tmp
文件夹删除(该目录与 hdfs-site.xml
中配置的 dir
有关),再重新进行格式化。
6.6 集群搭建检验
在主节点上,进入 $HADOOP_HOME/sbin
,执行:
./start-all
在主节点上,使用 jps
可以查看有以下进程启动:
DataNode
NameNode
SecondaryNameNode
ResourceManager
NodeManager
而在从节点上,则为:
DataNode
NodeManager
自此,集群已经成功的搭建。