HDFS前世今生之分布式部署(二)

HDFS上路第二篇先上手编译部署新+旧版本的Hadoop-HDFS, 并了解基本的命令操作和配置项, 先学会使用, 文档方面优先参考官方文档, 再可以补充的看看其它博客

附: 从官方页面可以看到项目本身是Hadoop ,而不是直接称为HDFS的原因是因为Hadoop 是包括”HDFS + Yarn”两个大模块的, 但是我们现在先不多研究调度任务的Yarn, 就直接说HDFS了.

0x00. 准备

HDFS可以用三种模式搭建(单机/伪分布式/分布式), 单机伪分布式版可以参考这篇文章. 这里我就直接上分布式的正式版了(版本分1.x3.x两个), 准备和安装过程优先参考对应版本的官方文档, 有问题再单独搜索备注, 首先至少准备3个节点(1主2从), 并配置好主到从节点的SSH访问, 方便分发文件命令.

节点IP 功能(进程) 备注
10.162.94.85 NameNode, ResourceManager(可选) 主节点
10.162.94.86 DataNode, NodeManager(可选) 数据节点
10.162.94.87 DataNode, NodeManager(可选) 数据节点

基本配置+环境:

  • CentOS7.5
  • Hadoop 3.1.2

如果IP没有对应域名, 最好给每个节点取个别名比如hdfs01/02/03, 后续分发和操作会方便很多. 我这里简单起见都用ip了

1
2
3
4
5
6
7
8
# 给3台节点配置hostname,并修改hosts使互相认识(已有则不需要,可选)
# 3台节点间SSH免密,方便通用分发命令(可选)

# 每台节点所需基本JDK1.8环境,源码安装就替换一下环境变量的路径
sudo yum install -y java-1.8.0-openjdk-devel.x86_64
echo "export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.222.b10-1.el7_7.x86_64/" \
2>> ~/.bashrc && source ~/.bashrc
# 等0x01的编译完成之后在0x03步骤分发包.

很多文章上会说主节点还要启动secondaryNamenode, 但是这是0.x/1.x旧版无备用主才需要的, 实际在新版有HA功能之后, 这个是不需要也不应该启动的.

而HA作为核心的一个功能, 肯定是完整的分布式HDFS必须的, 加之HDFS的主节点状态信息很重, 所以HA结构还算比较复杂, 在集群基本可用之后再去单独构建, 最后理论上需要有7个节点为宜. (多出的4个用作HA相关)

0x01. 编译

1. 初次编译

HDFS跟大部分软件一样, 可以用两种方式获得最后的二进制包:

  1. 直接从官方下载编译好的binary file (访问此地址, 如果服务器下载很慢, 建议PC下好传到服务器, 有300MB+)
  2. Git下载source file(源码), 自行编译(我这取的是3.1.2版本)

而为了加深一些C++ native依赖问题的理解, 以及后续可能对源码进行修改, 所以自己学会编译还是需要的, 之前记得确认准备工作做好了, 然后按照我总结好的版本步骤去执行, 基本就会顺畅很多(OS基于Cent7.5), 有些编译可能很耗时, 此时同时去做其他的准备操作.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 注意: 如果'\'后系统提示命令不存在, 注意是否有空格
# 1.安装编译依赖和环境(JDK如上面已有则去)
sudo yum install -y gcc gcc-c++ openssl-devel make lzop openssl openssl-devel ncurses-devel \
zlib-devel snappy snappy-devel bzip2 bzip2-devel lzo lzo-devel
sudo yum erase -y cmkae # cent自带低版本cmake不可用,手动卸载并安装高版本
mkdir ~/tools

# 2.手动安装maven并配置环境变量(不推荐yum安装,会自动依赖低版JDK且不好找配置文件)
wget http://us.mirrors.quenda.co/apache/maven/maven-3/3.6.2/binaries/apache-maven-3.6.2-bin.tar.gz && \
2tar xzvf apache-maven-3.6.2-bin.tar.gz && rm *.gz
# 可选源2
wget http://mirrors.hust.edu.cn/apache/maven/maven-3/3.6.0/binaries/apache-maven-3.6.0-bin.tar.gz && \
2tar xzvf apache-maven-3.6.0-bin.tar.gz && rm *.gz
echo 'export PATH=~/apache-maven-3.6.0/bin:$PATH' >> ~/.bashrc && source ~/.bashrc

# 3.手动安装3.1以上cmake
wget https://cmake.org/files/v3.10/cmake-3.10.2.tar.gz && tar xzvf cmake-3.10.2.tar.gz && \
2mv cmake-3.10.2 ~/tools && rm *.gz && cd ~/tools/cmake-3.10.2
# 确认在cmake目录下后开始编译安装,建议分步骤执行.
./configure
make -j8
sudo make install && sudo cp ./bin/cmake /usr/bin

# 4.安装protobuf2.5版本(版本严格一致)
wget https://github.com/protocolbuffers/protobuf/releases/download/v2.5.0/protobuf-2.5.0.tar.gz && \
2tar xzvf protobuf-2.5.0.tar.gz && mv protobuf-2.5.0 ~/tools && rm *.gz && cd ~/tools/protobuf-2.5.0
./configure
make -j8 && sudo make install && sudo ldconfig # protoc --version可以确认一下是否正确

然后为了加速仓库包下载, 强烈建议替换默认源, 如果有私有仓库更好, 那下载更快了: (修改/替换~/apache-maven-3.6.0/conf/setting.xml)

1
2
3
4
5
6
7
<!--注意复制粘贴的空字符可能报错-->
<mirror>
<id>alimaven</id>
<name>aliyunmaven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>

最后执行编译命令, 为了加快速度, 强烈建议跳过测试和文档编译. (编译主要耗时还是在下包上, 所以甚至可以直接把他人的~/.m2复制一份)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 编译普通源码, native库, 但跳过文档和测试. 最后打包 (30min+)
# -e参数是简单输出错误信息的,还不行再考虑使用-X
# -T 类似于make编译指定多线程,最好数目等于你的逻辑核个数(beta,可选)
mvn install -T 8 -e -Pdist,native -Dtar -DskipTests -Dmaven.javadoc.skip=true
# 如果提示比如MR依赖模块顺序, 那就-rf指定从MR单独单线程编译就行

# 如果你没有内部源,就算用阿里源也可能会遇到一些不得不使用海外导致很慢中断/报错的
# 这个时候可以调到中断的模块(比如client)直接开始,而不是从头又扫一遍(费时)
mvn install -e -Pdist,native -Dtar -DskipTests -Dmaven.javadoc.skip=true -rf :hadoop-client-api

# 检测编译native是否生效
file ~/hadoop-3.1.2/hadoop-dist/target/hadoop-3.1.2/lib/native/libhadoop.so.1.0.0
"ELF 64-bit LSB shared" #有64位标志则成功.

# 最后编译成功之后,hadoop帮我们整合打了个包,位于dist模块下↓
mv ~/hadoop-3.1.2/ tools && mv ~/tools/hadoop-3.1.2/hadoop-dist/target/hadoop-3.1.2 ~/

# 更新,生产环境客户端一般都会用压缩算法,所以你编译还得带上这些库(最完整版,测试可不用)
mvn install -T 8 -e -Pdist,native -Dtar -DskipTests -Dmaven.javadoc.skip=true \
-Pyarn-ui -Dsnappy.lib=/usr/lib64/ -Dbundle.snappy -Dzstd.lib=/usr/lib64/ \
-Dbundle.zstd -Dopenssl.lib=/usr/lib64/ -Dbundle.openssl -Disal.lib=/usr/lib64/ -Dbundle.isal

如果是非native报错, 一般默认-e输出的信息已经可以排查, 如果是C++(native)的报错, 那么用-X 查看具体是编译什么地方出错了, 有具体的cmake报错日志和提示, 肯定是可以定位到问题所在的, 下包顺利的话半小时就能编译完成, 接着进入分布式版部署的阶段.

2. 二次编译 (修改后)

这里是说如果修改了HDFS的源码之后的编译, 普通情况无需参考, 因为Hadoop整个项目很大, 除了第一次熟悉环境和上手建议全量编译 + native库编译, 后面如果是少量的改动, 一般就是按需编译, 然后替换了, 比如如下场景:

线上运行了官方HDFS3.1.2的环境, 我在master的基础上创建了一个新分支修改了点代码, 希望看看修改后的运行效果, 我应该怎么做最高效?

  1. 切换分支, 到hdfs模块里, 只编译此模块
  2. 线上已有环境不重新搭建 ,而是替换一下相关jar
  3. 重启线上环境(NN/DN)
1
2
3
4
5
6
7
8
# 只编译hdfs代码,同样别用默认源(编译环境建议统一在一台机器)
cd ./hadoop-3.1.2/hadoop-hdfs-project/hadoop-hdfs
mvn package -T 8 -e -Pdist -Dtar -DskipTests -Dmaven.javadoc.skip=true

# 替换原编译后的二进制包依赖的的hdfs-jar包
cp ./target/hadoop-hdfs-3.1.2.jar ~/hadoop-3.1.2/share/hadoop/hdfs/

# 重启NN & DN

0x02. 集群部署

A. 配置文件

这里关键就是配置HDFS的几个位于etc/hadoop/下的配置文件, 在configuration内添加属性项, 详细含义和默认端口参考官方最新文档: (自行创建对应的数据文件夹并确保读写权限正常)

  1. core-site.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <property>
    <!--指定默认HDFS访问路径-->
    <name>fs.defaultFS</name>
    <value>hdfs://10.162.94.85:9000</value>
    </property>
    <property>
    <!--指定Hadoop文件存放根目录-->
    <name>hadoop.tmp.dir</name>
    <value>/data01/test_hdp_data</value>
    </property>
  2. hdfs-site.xml

    这里还有两个场景配置项设置Namenode和Datanode的数据存储位置, 默认值是继承core-site的前缀file://${hadoop.tmp.dir}/dfs/name, 如果需要修改再配即可.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <property>
    <!--指定HDFS的副本数,默认3副本,这里两数据节点,就设置2-->
    <name>dfs.replication</name>
    <value>2</value>
    </property>
    <!--允许使用纯IP设置,否则会报错-->
    <property>
    <name>dfs.namenode.datanode.registration.ip-hostname-check</name>
    <value>false</value>
    </property>
  3. mapred-site.xml (可选, 不启动yanr则3,4 可跳)

    1
    2
    3
    4
    5
    <property>
    <!--指定Yarn作为MR调度器, 默认local-->
    <name>mapreduce.framework.name</name>
    <value>yarn</value>
    </property>
  4. yarn-site.xml (可选)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <!--Yarn就基本配置一下,其他参考文档-->
    <property>
    <name>yarn.nodemanager.aux-services</name>
    <value>mapreduce_shuffle</value>
    </property>
    <property>
    <!--注意这里不建议写localhost,如果有域名写域名-->
    <name>yarn.resourcemanager.hostname</name>
    <value>10.162.94.85</value>
    </property>
    <property>
    <name>yarn.nodemanager.pmem-check-enabled</name>
    <value>false</value>
    </property>
    <property>
    <name>yarn.nodemanager.vmem-check-enabled</name>
    <value>false</value>
    </property>
  1. 修改worker文件, 配置从节点地址, 建议写主机名/别名而不是IP (2.x旧版本是slaves文件)

    1
    2
    10.162.94.86
    10.162.94.97

B. 分发包文件

这里我参考常见写法, 整合写了个简单的shell, 避免重复分发和操作, 当然, ssh和scp的过程最好有免密, 不然不太友好:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/usr/bin/env bash

ip_prefix="10.162.94.8"
hdfs_path="~/hadoop-3.1.2" # 如果scp报错建议换为绝对路径

# 多行输入$按需转义,否则会展开
cat >> ~/.bashrc << EOF
export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.222.b10-1.el7_7.x86_64/

export HADOOP_HOME=$hdfs_path
export HADOOP_INSTALL=\$HADOOP_HOME
export HADOOP_MAPRED_HOME=\$HADOOP_HOME
export HADOOP_HDFS_HOME=\$HADOOP_HOME
export HADOOP_COMMON_HOME=\$HADOOP_HOME
export HADOOP_CONF_DIR=\$HADOOP_HOME/etc/hadoop

export PATH=\$PATH:\$HADOOP_HOME/sbin:\$HADOOP_HOME/bin
EOF

for i in {6..7}; do
echo "TransIP: ${ip_prefix}${i}"
scp ~/.bashrc ${ip_prefix}${i}:~/.bashrc # 分发.bashrc
ssh ${ip_prefix}${i} "source ~/.bashrc"
scp -r $hdfs_path ${ip_prefix}${i}:~/ # 分发hdfs包,配置确认已经都修改完了
done

当然, 远程分发命令可能没生效, 或者bash状态不好保持, 这个时候我建议使用Xshell 自带的多窗口发送命令更方便可靠 ,等于自带的分发, 也不用写shell了…

C. 启动运行

如果是第一次运行, 可以/建议先对NameNode就行格式化, 就像上一篇文章格式化的意义所说. 然后直接脚本启动 (目录结构如下)

hdpPkg00

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 仅第一次需要格式化
cd ~/hadoop-3.1.2/hadoop-dist/target/hadoop-3.1.2/
bin/hdfs namenode -format

# 1.启动hdfs,然后可以访问masterIP:50070的HDFS概览界面
sbin/start-dfs.sh # 需配置免密公私钥访问

# 1.1 手动启动方案,每个节点执行对应指令
# 注意,有HA方案后我们已经不需要启动SecondaryNamenode了
bin/hdfs --daemon start namenode # 主节点
bin/hdfs --daemon start datanode # 从节点

# 2.启动Yarn,然后可以范文masterIP:8088的任务管理界面
sbin/start-yarn.sh

# 2.1 同理手动启动如下
bin/yarn --daemon start resourcemanager # 主节点
bin/yarn --daemon start nodemanager # 从节点

# 最后可以jps看看系统起了哪些进程,可以看到如下
# 主节点
864 NameNode
2271 ResourceManager

#从节点
31973 DataNode
17046 NodeManager

# 其他
# 把启动的命令start换成stop就是关闭,生产一般建议手动.
sbin/stop-dfs.sh # 类似的一条龙停止HDFS,yarn类似
sbin/mr-jobhistory-daemon.sh start historyserver # 启动MR历史服务器(可选)
  • 启动HDFS之后, 就可以在默认的masterIP:9870 访问HDFS前端确认主节点Active , 并且Live Nodes 是2而不是0 (否则说明DN连接失败)
  • 启动Yarn后, 就可以在默认的masterIP:访问Yarn前端:

简单排错:

  1. 首先看日志, 看日志, 不瞎猜, 不管是数据节点还是Yarn没有正常启动/显示/工作, 先去logs/ 下看对应的日志文件, 解决90%的问题
  2. 剩下10%一般是网络/配置问题, 比如发现HDFS或Yarn的前端无法在你的浏览器访问, 请首先服务器本地curl masterIP:port , 或者wget看看是不是能获取正确内容, 如果能说明正常启动了, 但是没有正常暴露服务给外界, 自行排查包括IP设置/防火墙等, 肯定可以很快定位到问题.

0x03. HDFS客户端

HDFS部署好之后, 要从其他机器给集群发命令或者提交任务, 那就自然需要一个客户端, 这里也很简单, 直接使用就行了, 把之前Hadoop的包分发到需要当客户端的机器, 就能使用场景的HDFS命令操作了. (编译的时候可以看到, client已经被包含在了里面)

然后常见的HDFS命令使用在之前的文章说过, 也适合单独拆分方便查询, 参考Hadoop常用命令

待补 –> 旧版HDFS集群部署还没有单独说, 不过考虑到有特别的改动, 似乎也不适合通用的写..


参考资料:

  1. 官方编译文档参考(推荐)
  2. 官方分布式部署参考(推荐)