本篇篇幅较长,有许多集群搭建干货,和枯燥乏味但是面试可能问到的理论知识。
思来想去不知道怎样才能鼓励自己加油学习,想想要面对的生活还是假吧意思打开学习视频吧。
目录
一、引入
hdfs是什么
hdfs的由来
hdfs架构体系
hdfs的优缺点
优点
缺点
二、HDFS_block简介和注意事项
Block拆分标准
三、HDFS_block安全与管理
Block数据安全
Block 的管理效率
四、HDFS_Hadoop3完全分布式集群的搭建
1.集群的网络和节点规划
网络规划
节点规划
2.Hadoop下载与安装
3.配置Hadoop集群
配置环境变量
配置分布式集群环境
分发Hadoop集群安装目录及文件
启动和停止Hadoop集群
验证
Web端访问
4.时间同步
安装NTP服务器
配置其他机器的时间同步
五、HDFS_文件数据类型和启动检查脚本编写
文件数据类型
启动检查脚本编写
六、HDFS_NameNode(NN)
功能
性能
七、HDFS_DataNode(DN)
功能
八、HDFS_SNN与测试
SecondaryNameNode
传统解决方案
SNN解决方案
SecondaryNameNode测试
SNN数据恢复
九、HDFS_安全模式和权限
安全模式
权限
十、HDFS_机架感知与副本存放策略
节点距离
机架感知
十一、HDFS_数据写流程
宏观过程
微观过程
十二、HDFS_数据读流程
十三、Hadoop1 的困境
十四、HDFS_高可用Hadoop-HA
设计思想
ANN
SNN
DataNode(DN)
QJM
ZKFC
Zookeeper
十五、HDFS_高可用脑裂
脑裂 brain-split
十六、HDFS_水平扩展联邦机制
为什么需要联邦
Federation 架构设计
HDFS Federation 的不足
十七、HDFS_HA搭建
初始化
角色分配
配置文件
启动
十八、HDFS_java访问hdfs集群
HDFS的Java访问接口
Java访问HDFS主要编程步骤
使用FileSystem API读取数据文件
编程实现
环境介绍
代码实操
十九、HDFS_IDEA插件访问hdfs集群
安装插件
使用
结语
参考资料
hdfs即Hadoop分布式文件系统,是指被设计成适合运行在通用硬件(commodity hardware)上的分布式文件系统(Distributed File System)。
它和现有的分布式文件系统有很多共同点。但同时,它和其他的分布式文件系统的区别也是很明显的。HDFS是一个高度容错性的系统,适合部署在廉价的机器上。HDFS能提供高吞吐量的数据访问,非常适合大规模数据集上的应用。HDFS放宽了一部分POSIX约束,来实现流式读取文件系统数据的目的。HDFS在最开始是作为Apache Nutch搜索引擎项目的基础架构而开发的。HDFS是Apache Hadoop Core项目的一部分。
随着数据量越来越大,在一个操作系统存不下所有的数据,那么就分配到更到的操作系统管理的磁盘中,但是管理不方便和维护,迫切需要一种系统来管理多台机器上的文件,这就是分布式文件管理系统(DFS),它能够统一协调各个地理位置不同的机器拆分存储文件或合并聚合文件。而HDFS只是DFS中的一种。
文件切分思想
源文件直接存放在一个磁盘上效率肯定很低
字节数组
切分数据
拼接数据
偏移量
数据存储原理
HDFS采用了主从(Master/Slave)结构模型,一个HDFS集群是由一个NameNode和若干个DataNode组成的。其中NameNode作为主服务器,管理文件系统的命名空间和客户端对文件的访问操作;集群中的DataNode管理存储的数据。
高容错性
适合批处理
适合大数据处理
流式数据访问
可构建在廉价机器上
不适合低延时数据访问;
无法高效的对大量小文件进行存储
并发写入、文件随机修改
拆分的数据快需要等大
数据块 Block
注意事项
如果数据文件的切割点正好是一个单词的中间部分,切分数据如何保证数据的完整性?
需要专门给节点进行分工
注:前提是完成大数据学前准备--zookeeper详解与集群搭建(保姆级教程),这里重复操作将不再演示。
主机名 | IP地址 | 节点类型 |
node001 | 192.168.1.101 | master |
node002 | 192.168.1.102 | slave1 |
node003 | 192.168.1.103 | slave2 |
主机/服务 | NameNode | SecondaryNameNode | DataNode | ResourceManager | NodeManager |
node001 | √ | √ | √ | √ | |
node002 | √ | √ | √ | ||
node003 | √ | √ |
本次以hadoop-3.1.2.tar.gz为例搭建集群。
上传hadoop-3.1.2.tar.gz到node001;
执行解压命令:tar -zxvf hadoop-3.1.2.tar.gz -C /opt/hadoop-3.1.2
终端输入:vim /etc/profile
末行加入:
export HADOOP_HOME=/opt/hadoop-3.1.2
export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin
对于Hadoop分布式集群模式的部署,常常需要配置的文件:
hadoop-env.sh配置
终端输入:vim /opt/hadoop-3.1.2/etc/hadoop/hadoop-env.sh
末行加入:
export JAVA_HOME=/usr/java/jdk1.8.0_231-amd64
export HDFS_NAMENODE_USER=root
export HDFS_DATANODE_USER=root
export HDFS_SECONDARYNAMENODE_USER=root
export YARN_RESOURCEMANAGER_USER=root
export YARN_NODEMANAGER_USER=root
注意:yarn-env.sh
、mapred-env.sh
两个文件可以不用配置,如果要配置,可以在首次出现“export JAVA_HOME=……”
处配置为“export JAVA_HOME=/usr/java/jdk1.8.0_231-amd64”
core-site.xml配置
终端输入:vim /opt/hadoop-3.1.2/etc/hadoop/core-site.xml
加入:
fs.defaultFS
hdfs://node001:9000
hadoop.tmp.dir
/var/bdp/hadoop/full
参数说明:
fs.defaultFS:该参数是配置指定HDFS的通信地址。其值为hdfs://node001:9000,9000为端口号。
hadoop.tmp.dir:该参数配置的是Hadoop临时目录,即指定Hadoop运行时产生文件的存储路径,其值可以自行设置,不能设置为/tmp(/tmp是Linux的临时目录)。
注意:如果在普通用户配置临时目录/var/bdp/hadoop/full,需要手动创建及修改权限。
hdfs-site.xml配置
终端输入:vim /opt/hadoop-3.1.2/etc/hadoop/hdfs-site.xml
加入:
dfs.namenode.http-address
node001:50070
dfs.namenode.secondary.http-address
node002:50090
dfs.replication
2
dfs.namenode.name.dir
/opt/hadoopTmp/dfs/name
dfs.datanode.data.dir
/opt/hadoopTmp/dfs/data
参数说明:
dfs.namenode.http-address:该参数是配置NameNode的http访问地址和端口号。因为在集群规划中指定node001设为NameNode的服务器,故设置为node001:50070。
dfs.namenode.secondary.http-address:该参数是配置SecondaryNameNode的http访问地址和端口号。在集群规划中指定node002设为SecondaryNameNode的服务器,故设置为node002:50090。
dfs.replication:该参数是配置HDFS副本数量。
dfs.namenode.name.dir:该参数是设置NameNode存放的路径。
dfs.datanode.data.dir:该参数是设置DataNode存放的路径。
yarn-site.xml配置(这里可以暂时不配置,将在yarn篇专门介绍)
终端输入:vim /opt/hadoop-3.1.2/etc/hadoop/yarn-site.xml
yarn.resourcemanager.hostsname
node001
yarn.resourcemanager.webapp.address
node001:8088
yarn.nodemanager.aux-services
mapreduce_shuffle
yarn.nodemanager.aux-services.mapreduce.shuffle.class
org.apache.hadoop.mapred.ShuffleHandler
yarn.log-aggregation-enable
true
yarn.log-aggregation.retain-seconds
106800
yarn.nodemanager.remote-app-log-dir
/user/container/logs
参数说明:
yarn.resourcemanager.hostsname:该参数是指定ResourceManager运行在那个节点上。
yarn.resourcemanager.webapp.address:该参数是指定ResourceManager服务器的web地址和端口。
yarn.nodemanager,aux-services:该参数是指定NodeManager启动时加载server的方式。
yarn.nodemanager.aux-services.mapreduce.shuffle.class:该参数是指定使用mapreduce_shuffle中的类。
yarn.log-aggregation-enable:该参数是配置是否启用日志聚集功能。
yarn.log-aggregation.retain-seconds:该参数是配置聚集的日志在HDFS上保存的最长时间。
yarn.nodemanager.remote-app-log-dir:该参数是指定日志聚合目录。
mapred-site.xml配置
终端输入:vim /opt/hadoop-3.1.2/etc/hadoop/mapred-site.xml
加入:
mapreduce.framework.name
yarn
mapreduce.jobhistory.address
node003:10020
mapreduce.jobhistory.webapp.address
node003:19888
mapreduce.jobhistory.intermediate-done-dir
${hadoop.tmp.dir}/mr-history/tmp
mapreduce.jobhistory.done-dir
${hadoop.tmp.dir}/mr-history/done
参数说明:
mapreduce.framework.name:该参数是指定MapReduce框架运行在YARN上。
mapreduce.jobhistory.address:该参数是设置MapReduce的历史服务器安装的位置及端口号。
mapreduce.jobhistory.webapp.address:该参数是设置历史服务器的web页面地址和端口。
mapreduce.jobhistory.intermediate-done-dir:该参数是设置存放日志文件的临时目录。
mapreduce.jobhistory.done-dir:该参数是设置存放运行日志文件的最终目录。
slaves配置
终端输入:vim /opt/hadoop-3.1.2/etc/hadoop/slaves
添加所有节点主机名:
node001
node002
node003
将处理好的hadoop-3.1.2分发到node002和node003(时间有些许长~)
分发到node002:scp -r /opt/hadoop-3.1.2 root@node002:/opt/
分发到node003:scp -r /opt/hadoop-3.1.2 root@node003:/opt/
在启动hadoop集群前,需要先格式化NameNode,在Master主机下操作:
格式化命令:hdfs namenode -format 或者:hadoop namenode -format
格式化后即可
格式化后即可启动集群的节点,可以分别启动HDFS和YARN,也可以一起启动:
全部启动命令:
start-all.sh
如果启动报错:node001: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).
请参考《搭建hadoop报错》进行改错
启动和停止HDFS:
start-dfs.sh #启动HDFS
stop-dfs.sh #停止HDFS启动和停止YARN:
start-yarn.sh #启动YARN
stop-yarn.sh #停止YARN全部启动和停止:
start-all.sh #启动HDFS和YARN
stop-all.sh #停止HDFS和YARN启动和停止历史(日志)服务器:
mr-jobhistory-daemon.sh start historyserver #启动historyserver
mr-jobhistory-daemon.sh start historyserver #停止historyserver
命令:jps
成功开启后,会看到下图所示的节点显示:
Master: NameNode、DataNode、ResourceManager、NodeManager
slave1: SecondaryNameNode、DataNode、NodeManager
slave2: DataNode、NodeManager
关闭防火墙:
service iptables stop
访问HDFS:50070192.168.1.101:50070 #访问HDFS,50070是端口
192.168.1.101:8088 #访问YARN,8088是端口
到这,HDFS完全分布式集群搭建完毕!
集群常用命令如下:
hdfs dfs -ls xxx
hdfs dfs -mkdir -p /xxx/xxx
hdfs dfs -cat xxx
hdfs dfs -put local cluster
hdfs dfs -get cluster local
hdfs dfs -cp /xxx/xxx /xxx/xxx
hdfs dfs -chmod -R 777 /xxx
hdfs dfs -chown -R zyh:zyh /xxx
Hadoop集群对时间要求非常高,主节点与各从节点的时间都必须同步。NTP使用来使计算机时间同步的一种协议。配置时间同步服务器(NTP服务器)主要就是为了进行集群的时间同步。
这里主要以node001作为NTP服务器,从节点node002和node003每10分钟跟node001同步一次。
1 安装配置NTP服务器
查看是否安装NTP服务,如果出现
ntp-x.x.x
和ntpdate-x.x.x
则不需要再安装rpm -qa | grep ntp
安装命令:
yum install -y ntp # 使用yum在线安装
2 修改配置文件
ntp.conf
vim /etc/ntp.conf
① 启用restrice,修改网段
打开restrice的注释(删除前面的#号),修改为自己的网段
② 注释掉四行server域名,再添加两行:
server 127.127.1.0 fudge 127.127.1.0 stratum 10
如图所示:
③ 修改配置文件ntpd
命令:
vim /etc/sysconfig/ntpd
在此文件内,添加一行
SYNC_HWCLOCK=yes
,将同步后的时间写入CMOS里。④ 启动NTP服务
service ntpd start # 启动NTP服务
chkconfig ntpd on # 开机自启动,永久启动两个命令可以连用:service ntpd start & chkconfig ntpd on
首先要保证从节点(其他机器)安装有NTP,然后开始配置从节点跟主节点同步时间。以下操作是在node002和node003机器上配置(剩下的这两台都要配置):
① 注释掉四行server域名配置,其后添加一行:
server node001
vim /etc/ntp.conf
② 修改配置文件ntpd,此操作和前面的NTP服务器中配置一样
vim /etc/sysconfig/ntpd
添加一行
SYNC_HWCLOCK=yes
③ 启动时间同步
启动NTP服务:
service ntpd start & chkconfig ntpd on
也可以执行命令:
ntpdate node001
完成同步node003节点与node002操作一致,不再演示。
最后通过:date '+%Y-%m-%d %H:%M:%S' 测试三个节点时间是否一致。
文件有一个stat命令
数据信息-->描述文件的属性
文件有一个vim命令
分类
元数据
查看文件的数据信息
File 文件名
Size 文件大小(字节)
Blocks 文件使用的数据块总数
IO Block 数据块的大小
regular file:文件类型(常规文件)
Device 设备编号
Inode 文件所在的Inode
Links 硬链接次数
Access 权限
Uid 属主id/用户
Gid 属组id/组名
Access Time:简写为atime,表示文件的访问时间。当文件内容被访问时,更新这个时间
Modify Time:简写为mtime,表示文件内容的修改时间。当文件的数据内容被修改时,更新这个时间
Change Time:简写为ctime,表示文件的状态时间,当文件的状态被修改时,更新这个时间。例如文件的链接数,大小,权限,Blocks数
终端输入:vim start-bdp.sh
加入:
#!/bin/bash
echo "$(date)======启动node001的zookeeper========" >> /root/logs/start-bdp.log
zkServer.sh start >> /root/logs/start-bdp.log
echo "$(date)======启动node002的zookeeper========" >> /root/logs/start-bdp.log
ssh root@node002 "/opt/zookeeper-3.4.5/bin/zkServer.sh start" >> /root/logs/start-bdp.log
echo "$(date)======启动node003的zookeeper========" >> /root/logs/start-bdp.log
ssh root@node003 "/opt/zookeeper-3.4.5/bin/zkServer.sh start" >> /root/logs/start-bdp.log
echo " " >> /root/logs/start-bdp.log
echo " " >> /root/logs/start-bdp.log
echo " " >> /root/logs/start-bdp.log
echo " " >> /root/logs/start-bdp.log
echo -e "======启动hdfs完全分布式集群========" >> /root/logs/start-bdp.log
start-all.sh >> /root/logs/start-bdp.log
echo "$(date)-->启动hdfs完全分布式集群完成" >> /root/logs/start-bdp.log
echo " " >> /root/logs/start-bdp.log
echo " " >> /root/logs/start-bdp.log
echo " " >> /root/logs/start-bdp.log
echo " " >> /root/logs/start-bdp.log
echo "======当前各个节点状态为========" >> /root/logs/start-bdp.log
echo "$(date)======node001的zookeeper状态为========" >> /root/logs/start-bdp.log
zkServer.sh status >> /root/logs/start-bdp.log
echo "$(date)======node002的zookeeper的状态为========" >> /root/logs/start-bdp.log
ssh root@node002 "/opt/zookeeper-3.4.5/bin/zkServer.sh status" >> /root/logs/start-bdp.log
echo "$(date)======node003的zookeeper状态为========" >> /root/logs/start-bdp.log
ssh root@node003 "/opt/zookeeper-3.4.5/bin/zkServer.sh status" >> /root/logs/start-bdp.log
echo "$(date)======node001的HDFS状态========" >> /root/logs/start-bdp.log
jps >> /root/logs/start-bdp.log
echo "$(date)======node002的HDFS的状态为========" >> /root/logs/start-bdp.log
ssh root@node002 "jps" >> /root/logs/start-bdp.log
echo "$(date)======node003的HDFS状态为========" >> /root/logs/start-bdp.log
ssh root@node003 "jps" >> /root/logs/start-bdp.log
移动到根节点创建存放日志的目录:mkdir logs
执行脚本:sh start-bdp.sh
查看日志:cat logs/start-bdp.log
日志如下:
Thu Sep 15 11:49:48 CST 2022======启动node001的zookeeper========
Starting zookeeper ... STARTED
Thu Sep 15 11:49:49 CST 2022======启动node002的zookeeper========
Starting zookeeper ... STARTED
Thu Sep 15 11:49:50 CST 2022======启动node003的zookeeper========
Starting zookeeper ... STARTED
======启动hdfs完全分布式集群========
Starting namenodes on [node001]
Last login: Thu Sep 15 11:46:48 CST 2022 on pts/0
Starting datanodes
Last login: Thu Sep 15 11:49:53 CST 2022 on pts/0
Starting secondary namenodes [node002]
Last login: Thu Sep 15 11:49:56 CST 2022 on pts/0
Starting resourcemanager
Last login: Thu Sep 15 11:50:03 CST 2022 on pts/0
Starting nodemanagers
Last login: Thu Sep 15 11:50:10 CST 2022 on pts/0
Thu Sep 15 11:50:21 CST 2022-->启动hdfs完全分布式集群完成
======当前各个节点状态为========
Thu Sep 15 11:50:21 CST 2022======node001的zookeeper状态为========
Mode: follower
Thu Sep 15 11:50:21 CST 2022======node002的zookeeper的状态为========
Mode: leader
Thu Sep 15 11:50:22 CST 2022======node003的zookeeper状态为========
Mode: follower
Thu Sep 15 11:50:22 CST 2022======node001的HDFS状态========
16160 NameNode
15937 QuorumPeerMain
16854 NodeManager
17222 Jps
16711 ResourceManager
16317 DataNode
Thu Sep 15 11:50:23 CST 2022======node002的HDFS的状态为========
8933 QuorumPeerMain
9222 NodeManager
9020 DataNode
9133 SecondaryNameNode
9375 Jps
Thu Sep 15 11:50:23 CST 2022======node003的HDFS状态为========
8195 NodeManager
7993 QuorumPeerMain
8073 DataNode
8348 Jps
解决思路(日志edit+快照fsimage)
- 查看目录:cd /var/bdp/hadoop/full/dfs/name/current/
- 显示文件:ls
解决方案
dfs.namenode.checkpoint.period #每隔多久做一次checkpoint,默认3600s
dfs.namenode.checkpoint.txns #每隔多少次操作做一次checkpoint,默认100万次
dfs.namenode.checkpoint.check.period #每隔多久检查一次操作次数,默认60s
1.强行杀死NameNode节点
kill -9 进程号
2.清空namenode下name中的fsimage和edits文件
rm -rf /var/bdp/hadoop/full/dfs/name/current/*
3.secondarynamenode下的name中的fsimage和edits复制到namenode对应文件夹中
scp -r root@node002:/var/bdp/hadoop/full/dfs/namesecondary/current/* /var/bdp/hadoop/full/dfs/name/current
4.启动namenode
hadoop-daemon.sh start namenode
在hadoop-env.sh中配置
distance(/D1/R1/H1,/D1/R1/H1)=0 相同的 datanode
distance(/D1/R1/H1,/D1/R1/H3)=2 同一 rack 下的不同 datanode
distance(/D1/R1/H1,/D1/R2/H4)=4 同一 IDC 下的不同 datanode
distance(/D1/R1/H1,/D2/R3/H7)=6 不同 IDC 下的 datanode
写数据就是将客户端上的数据上传到HDFS
1.客户端向HDFS发送写数据请求
创建目录:hdfs dfs -mkdir -p /user/dfstest
上传文件(随便上传一个大文件方便测试):hdfs dfs -put test.rar /user/dfstest
2. filesystem通过rpc调用namenode的create方法
3.如果DFS接收到成功的状态,会创建一个FSDataOutputStream的对象给客户端使用
4.客户端要向nn询问第一个Block存放的位置
NN通过机架感知策略 (node1 node 2 node8)
5.需要将客户端和DN节点创建连接
pipeline(管道)
客户端和node1 创建连接 socket
node1和 node2 创建连接 socket
node2 和 Node8 创建连接 socket
6.客户端按照文件块切分数据,但是按照packet发送数据
默认一个packet大小为64K,Block128M为2048个packet
7.客户端通过pipeline管道开始使用FDSOutputStream对象将数据输出
1. 客户端首先将一个 packet 发送给 node1, 同时给予 node1 一个 ack 状态
2. node1接受数据后会将数据继续传递给 node2, 同时给予 node2 一个 ack 状态
3. node2接受数据后会将数据继续传递给 node8, 同时给予 node8 一个 ack 状态
4. node8将这个 packet 接受完成后,会响应这个 ack 给 node2 为 true
5. node2会响应给 node1 , 同理 node1 响应给客户端
8. 客户端接收到成功的状态 , 就认为某个 packet 发送成功了,直到当前块所有的 packet 都发送完成
9. 如果客户端接收到最后一个 pakcet 的成功状态 , 说明当前 block 传输完成,管道就会被撤销
10. 客户端会将这个消息传递给 NN , NN 确认传输完成
1. NN会将 block 的信息记录到 Entry, 客户端会继续向 NN 询问第二个块的存储位置 , 依次类推
2. block1 (node1 node2 node8)
3. block2 (node1 node8 node9)
4. ....
5. blockn(node1 node7 node9)
11. 当所有的 block 传输完成后, NN 在 Entry 中存储所有的 File 与 Block 与 DN 的映射关系关闭
FsDataOutPutStream
1.客户端首先从自己的硬盘中以流的形式将自己的数据读取到缓存中
2.然后将缓存(buffer)中的数据以chunk(512B)和checksum(4B)的方式放入到packet(64k)
3.当packet满的时候添加到dataqueue
4.datastreamer开始从dataqueue队列上读取一个packet,通过FDSDataOPS发送到Poepleline
在取出的时候,也会将 packet 加入到 ackQueue, 典型的生产者消费者模式
5. 客户端发送一个 Packet 数据包以后开始接收 ack ,会有一个用来接收 ack 的 ResponseProcessor 进程,如果收到成功的 ack
如果某一个 packet 的 ack 为 true, 那么就从 ackqueue 删除掉这个 packet
如果某一个 packet 的 ack 为 false, 将 ackqueue 中所有的 packet 重新挂载到 发送队列 , 重新发送
单 NameNode 的架构存在的问题:当集群中数据增长到一定规模后,NameNode 进程占用的内存可能会达到成百上千 GB(调大 NameNode 的 JVM 堆内存已无可能),此时,NameNode 成了集群的性能瓶颈。
为了提高 HDFS 的水平扩展能力,提出了Federation(联邦,联盟)机制。
Federation 是 NameNode 的 Federation,也就是会有多个 NameNode,而多个 NameNode 也就意味着有多个 namespac(命名空间),不同于 HA 模式下 Active 和 Standby 有各自的命名空间,联邦环境下的多 NameNode 共享同一个 namespace。
来看一下命名空间在 HDFS 架构中的位置:
现有的 HDFS 可以简单分为 数据管理 和 数据存储 2层:
所有关于存储数据的信息和管理,都是由 NameNode 负责;
而真实数据的存储则是在各个 DataNode 下完成。
这些被同一个 NameNode 所管理的数据都在同一个 namespace 下,一个 namespace 对应一个Block Pool(所有数据块的集合)。
再强调一遍:HDFS Federation 是用来解决 NameNode 内存瓶颈问题的横向扩展方案。
Federation 意味着在集群中将会有多个 NameNode,这些 NameNode 相互独立且不需要协调,它们只需要管理自己所属的数据块即可。
分布式的 DataNode 作为公共的数据块存储设备,被所有的 NameNode 共用:每个 DataNode 都要向集群中所有的 NameNode 注册,且周期性地向所有 NameNode 发送心跳和块报告,并执行所有 NameNode 下发的命令。
Federation 架构中,DataNode上 会有多个 Block Pool 下,在 DataNode 的 datadir 目录下能看到以 BP-xx.xx.xx.xx
开头的目录。
从上图可以看出来:
多个 NameNode 共用一个集群里的所有存储资源,每个 NameNode 都可以单独对外提供服务;
每个 NameNode 都会定义一个 Block Pool,有单独的 id,每个 DataNode 都为所有 Block Pool 提供存储。
DataNode 会按照存储池 id 向其对应的 NameNode 汇报块信息,同时,DataNode 会向所有 NameNode 汇报本地存储可用资源情况。
HDFS Federation 并没有完全解决单点故障问题。
虽然集群中有多个 NameNode(namespace),但是从单个 NameNode(namespace)看,仍然存在单点故障:
如果某个 NameNode 服务发生故障,其管理的文件便不能被访问。
Federation 架构中每个NameNode 同样配有一个 Secondary NameNode,用于协助 NameNode 管理元数据信息(FSImage 和 EditLog)。
所以超大规模的集群,一般都会采用 HA + Federation 的部署方案,也就是每个联合的 NameNode 都是 HA 的,这样就解决了 NameNode 的单点故障问题 和 横向扩容问题。
注:这里搭建HA与上文搭建完全分布式集群不是串行而是并行,故其所有配置文件应重新编写,不能套用完全分布式集群的配置文件。即:从头再来
将hadoop-3.1.2.tar.gz安装包重新解压覆盖原先文件即可。注意:操作之前记得拍摄快照。
tar -zxvf hadoop-3.1.2.tar.gz -C /opt/
节点\角色 | ZK | NN | DN | JN | ZKFC |
node001 | √ | √ | √ | √ | |
node002 | √ | √ | √ | √ | √ |
node003 |
√ | √ | √ |
hadoop-env.sh
终端输入:vim /opt/hadoop-3.1.2/etc/hadoop/hadoop-env.sh
末行添加:
export JAVA_HOME=/usr/java/jdk1.8.0_231-amd64
export HDFS_NAMENODE_USER=root
export HDFS_DATANODE_USER=root
export HDFS_ZKFC_USER=root
export HDFS_JOURNALNODE_USER=root
export HDFS_SECONDARYNAMENODE_USER=root
export YARN_RESOURCEMANAGER_USER=root
export YARN_NODEMANAGER_USER=root
core-site.xml
终端输入:vim /opt/hadoop-3.1.2/etc/hadoop/core-site.xml
添加:
fs.defaultFS
hdfs://bdp
hadoop.tmp.dir
/var/bdp/hadoop/ha
fs.trash.interval
1440
ha.zookeeper.quorum
node001:2181,node002:2181,node003:2181
hadoop.http.staticuser.user
root
hdfs-site.xml
终端输入:vim /opt/hadoop-3.1.2/etc/hadoop/hdfs-site.xml
添加:
dfs.nameservices
bdp
dfs.ha.namenodes.bdp
nn1,nn2
dfs.namenode.rpc-address.bdp.nn1
node001:8020
dfs.namenode.rpc-address.bdp.nn2
node002:8020
dfs.namenode.http-address.bdp.nn1
node001:9870
dfs.namenode.http-address.bdp.nn2
node002:9870
dfs.namenode.shared.edits.dir
qjournal://node001:8485;node002:8485;node003:8485/cluster
dfs.journalnode.edits.dir
/var/bdp/hadoop/qjm
dfs.client.failover.proxy.provider.bdp
org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider
dfs.ha.fencing.methods
sshfence
shell(true)
dfs.ha.fencing.ssh.private-key-files
/root/.ssh/id_rsa
dfs.ha.fencing.ssh.private-key-files
/root/.ssh/id_rsa
dfs.ha.automatic-failover.enabled
true
workers
终端输入:vim /opt/hadoop-3.1.2/etc/hadoop/workers
删除:localhost
添加:
node001
node002
node003
分发
将修改好的配置文件发送到其他节点(时间较长)
传到node002:scp -r /opt/hadoop-3.1.2/ node002:/opt/
传到node003:scp -r /opt/hadoop-3.1.2/ node003:/opt/
启动zookeeper,三台都需要启动
三台机器终端输入:zkServer.sh start
启动JN(journalnode),三台都需启动
hadoop-daemon.sh start journalnode
格式化,在一台NN上执行(这里选择node001)
#格式化
hdfs namenode -format
#启动当前NN
hadoop-daemon.sh start namenode
执行同步,没有格式化的NN上执行,在另外一台namenode上面执行(这里选择node002)
hdfs namenode -bootstrapStandby
格式化ZK(在node001上执行)
hdfs zkfc -formatZK
启动hdfs集群(在node001上执行)
start-dfs.sh
到此HA集群搭建完成!
有两个静态工厂方法来获取FileSystem实例文件系统。
常用的是第二个和第四个
使用的是IDEA+Maven来进行测试
Maven的pom.xml文件如下:
4.0.0
com.libing
hdfa
1.0-SNAPSHOT
8
8
org.apache.hadoop
hadoop-common
2.8.1
org.apache.hadoop
hadoop-client
2.8.1
org.apache.hadoop
hadoop-hdfs
2.8.1
org.apache.hadoop
hadoop-mapreduce-client-core
2.8.1
org.apache.hadoop
hadoop-auth
2.8.1
log4j
log4j
1.2.17
commons-logging
commons-logging
1.2
com.google.guava
guava
19.0
commons-collections
commons-collections
3.2.2
commons-cli
commons-cli
1.2
commons-lang
commons-lang
2.6
commons-configuration
commons-configuration
1.9
org.apache.avro
avro
1.7.7
commons-io
commons-io
2.5
上传文件到HA集群
package com.libing.hdfs;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import java.net.URI;
/**
* @author liar
* @version 1.0
* @date 2022/9/17 21:26
*/
public class UploadTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
//构建Configuration对象,读取并解析相关配置文件
Configuration conf = new Configuration();
/**
* 这些都是HA集群中配置文件的信息
*/
//设置相关属性
conf.set("fs.defaultFS", "hdfs://bdp");
conf.set("dfs.nameservices", "bdp");
conf.set("dfs.ha.namenodes.bdp", "nn1,nn2");
conf.set("dfs.namenode.rpc-address.bdp.nn1", "192.168.1.101:8020");
conf.set("dfs.namenode.rpc-address.bdp.nn2", "192.168.1.102:8020");
conf.set("dfs.client.failover.proxy.provider.bdp",
"org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider");
try {
//获取特定文件系统实例fs
FileSystem fs = FileSystem.get(new URI("hdfs://bdp"), conf,"root");
//创建/user/hdfs/test文件目录
boolean b=fs.mkdirs(new Path("/user/hdfs/test"));
if (b){
//将本地目录中的文件上传到集群中
//通过文件系统实例fs进行文件操作
fs.copyFromLocalFile(new Path("D:\\test\\test.txt"), new Path("/user/hdfs/test/test-1.txt"));
}else {
System.out.println("创建文件夹失败");
}
fs.close();
} catch (Exception e) {
System.out.println(e);
}
}
}
下载集群中文件
package com.libing.hdfs;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import java.net.URI;
/**
* @author liar
* @version 1.0
* @date 2022/9/17 21:36
*/
public class DownloadTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
Configuration conf = new Configuration();
conf.set("fs.defaultFS", "hdfs://bdp");
conf.set("dfs.nameservices", "bdp");
conf.set("dfs.ha.namenodes.bdp", "nn1,nn2");
conf.set("dfs.namenode.rpc-address.bdp.nn1", "192.168.1.101:8020");
conf.set("dfs.namenode.rpc-address.bdp.nn2", "192.168.1.102:8020");
conf.set("dfs.client.failover.proxy.provider.bdp",
"org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider");
//这之上的代码基本不变
try {
FileSystem fs = FileSystem.get(new URI("hdfs://bdp"), conf,"root");
//基本上 代码的变化在这里,主要为对集群中文件的增删改查
fs.copyToLocalFile(new Path("/user/hdfs/test/test-1.txt"),new Path("D:\\test\\test-local.txt"));
fs.close();
} catch (Exception e) {
System.out.println(e);
}
}
}
这里浅谈一下这个.crc文件的由来:
CRC数据校验文件
简单来说他就是做校验工作的,相当于小区保安,你不是业主就不让你进去是一个道理。
在右侧边栏打开big data tools
点击左上角+号,选择HDFS
本文较长,如果你能坚持看完,也能发现作者的用心。
如果文章有什么出错或者你对文章有何建议或意见都可以通过我的邮箱联系到我:
Hadoop-HDFS
Hadoop集群完全分布式的搭建