O(1)—常数阶
O(N)—线性阶
O(logN)—对数阶
O(n^2)—平方阶
O(nlogn)—线性对数阶
O(1)(logn)(n)(nlogn)(n2)(n3)(2^n)(n!)(n^n)
时间复杂度去估算算法优劣的时候注重的是算法的潜力
有100条数据的时候算法a比算法b快
有10000条数据的时候算法b比算法a快
算法b的时间复杂对更优
默认以升序排列(小–>大)
冒泡
从位置0开始,当前位置数字和后面位置的数字进行比较
如果前面的大于后面,数据交换
将位置向后移动一位,重复第一个过程,直到最后一个
重复刚才的过程
时间复杂度O=n^2
选择
假设第一个数字就是最大数字,记录他的索引
然后和后面的数字进行比较,如果后面的数字大于最大数字,重新记录新数字的索引
直到最后一个数字,然后将最大数字索引与最后一个数字进行交换
时间复杂度 O=n^2
插入
假设原始数列是有序的
每次向数列中插入一个数字,从右向左依次比较,找到合适的位置
数列重新变为有序数列
在向数列插入一个数字
时间复杂度 O=n^2
谢尔
将数据递归分组,首先分为 长度/2组
然后将第一个数字与1+zu进行插入排序,经过第一次在整体排序后,小的数字很快会被移动
到前面
重新将数据分组,原来组/2
小的数字很快就会被移动到前面
时间复杂度O=n^1.3
快速
三种(挖坑法 左右法 前后法)
操作:选择一个数字作为参照物(基准数字)5
思想:然后和另一个的进行比较,如果是右边的小于5就交换,5左面的大于5就交换
整体排序之后,5的位置是正确的,左右两个是无序
将左右两个都当做一个新序列进行排序基准数
时间复杂度O=n*log2n
归并
让两个有序队列进行比较,然后每个队列依次取出1个数字比较,然后小的数字被去除
分割
依次将数列二等分,二等分之后的子序列继续二等分
直到每个子序列只有一个数字,停止分割
合并
按照分割的顺序进行合并
堆
一种基于树的排序算法
二分查找树
任意节点
最多有两个子节点
左面的节点都小于父节点
右面的节点都大于父节点
计数
一种很巧妙的排序算法
比较特殊的排序算法,只针对特殊数据的排序
将对应的数据让数组的索引对应值+1
最后遍历数组,索引对应的值是几就打印几
桶
将数字按照范围进行分割
然后对分割后的数据进行排序(继续分割)
将来数据分桶要特别注意数据倾斜的问题
基数
基数排序是按照地位先排序,然后手机,在按照高位排序,然后再收集,依次类推,直到最高位
有1T数据,这些数据中心有两行数据是重复的,如果找出重复行
方案1
从硬盘读取数据,按照首字母放回硬盘,首字母相同的肯定在同一个的区域
依次类推,如果到最后一个文件中,有两个相同的字符串,那么就是相同的字符串
优点:
分拆开
缺点:
长度不等的时候,有可能中途的时候已经有相同字符串了,但是不能找出
方案2
读取数据按照长度分桶
然后空桶或者只有一个数据的桶就排除掉
缺点:
如果长度相差不大,桶数量会急剧减少,导致每个桶数量过多
方案3
我们一定要把相同的两条记录放入到同一个桶中
需要选用一种相同均匀的分拆数据的方式,要求数据散列的非常完美:
采用Hash算法对每一行数据计算Hash值
相同的数据Hash值一定相同,但是Hash值相同字符串不一定相同
根据文件的大小,计算文件的数量,然后让Hash对数量取余
将余数相同的数据存放到同一个文件中
查重的时候只需要将一个文件读到内存中即可
如何用1G内存的电脑对1T的数据进行排序
方案1
设置一个阈值(500M),按行读取数据,如果读取数据量超过500M就产生一个新文件
大略算一下一共切分成2048个文件
现在的情况是:
文件内部和文件外部全部无序
使用归并算法对每个文件进行排序,让文件内部有序
然后使用归并让多个文件合并到一起
方案2
按照字母组合建立桶,桶的序号就是前2个字母的组合(52*52)
然后将数据依次放入到桶中
桶与桶之间有序,桶内无序
我们只需要将桶内的数据排序好,然后将桶链接到一起数据有序
Hadoop Common 基础型功能
Hadoop Distributed File System 负责存放数据
Hadoop YARN 负责资源的调配
Hadoop MapReduce 大数据的计算框架
Hadoop Ozone 数据存放到仓库
Hadoop Submarine 机器学习引擎
FS File System
文件系统是基于硬盘之上的一个文件管理的工具
我们用户操作文件系统可以和硬盘进行解耦
DFS Distributed File System:
分布式文件系统
将我们的数据存放在多台电脑上存储
分布式文件系统有很多,
HDFS是mapreduce计算的基础
文件存放在一个磁盘上效率肯定是低的
读取效率低
如果文件特别大会超出单机的存储范围
字节数组
文件在磁盘真实存储文件的抽象概念
数组可以进行拆分和组装,源文件不会受到影响
切分数据
对字节数组进行切分
拼接数据
按照数组的偏移量将数据连接到一起,将字节数组链接到一起
偏移量
当前数据在数组中的相对位置,你可以理解为 下标
数组都有对应的索引(下标),可以快速的定位数据
数据存储的原理:
不管文件的的大小,所有的文件都是由字节数组构成
如果我们要切分文件,就是将一个字节数组分成多份
我们将切分后的数据拼接到一起,数据可以继续使用
我们需要根据数据的偏移量将他们重新拼接到一起
拆分的数据块需要等大
数据计算的时候简化问题的复杂度
进行分布式算法设计的时候,数据不统一,算法很难设计
数据拉取的时候时间相对一致
通过偏移量就知道这个块的位置
相同文件,分成的数据块大小应该相等
数据块 Block
数据被切分后的一个整体称之为块
在H1默认大小为64M,在H2及其以后默认大小为128M
同一个文件中,每个数据块大小要一致除了最后一个节点外
不同文件中,块的大小可以不一致
文件大小不同可以设置不同的块的数量
真实情况下,会根据文件大小和集群节点的数量综合考虑块的大小
数据块的个数 =Ceil( 文件大小 / 每个块的大小)
注意事项
HDFS中一旦文件被存储,数据不允许被修改
修改会影响偏移量
修改会导致数据倾斜
修改数据会导致蝴蝶效益
但是可以被追加,但是不推荐
追加设置需要手动打开
一般HDFS存储的都是历史数据。所以 将来Hadoop的mr都用来进行离线数据的处理
块的大小一旦文件上传之后就不允许被修改
128m -512M
如果数据文件的切割点128M整好是一个单词的中间部分,切分数据如何保证数据的完整性?
肯定要对存储数据做备份
备份的数据肯定不能存放在一个节点上
使用数据的时候可以就近获取数据
所以备份的数量要小于等于节点的数量
每个数据块会有3个副本,相同副本是不会存放在同一个节点上
副本的数量可以变更
可能近期的数据被分析的可能性跟大,副本数可以多设置几个
后期数据很少被分析,可以减少副本数
需要专门给节点进行分工
存储 DataNode
记录 NameNode
日志 secondaryNameNode
优点
a)高容错性
i.保存多个副本,且提供容错机制。
ii.副本丢失或宕机自动恢复。默认存3份。
b)运行在廉价的机器上(商用机)
i.通过副本提高可靠性
ii.提供了容错和恢复机制
c)适合批处理
i.移动计算而非数据
ii.数据位置暴露给计算框架。NameNode上有位置
d)适合大数据的处理
i.TB,甚至PB级数据
ii.百万规模以上的文件数量
iii.10K+节点规模
e)流式数据访问
i.一次写入,多次读取,高吞吐量,所以可以同时处理大量数据
缺点
a)不擅长低延迟数据访问
比如毫秒级
b)不擅长小文件的分区
i.占用NameNode大量内存
ii.磁盘寻道时间超过读取时间
c)不擅长并发写入,文件随机修改
i.一个文件只能有一个写入者
ii.仅支持append,也就是添加(有组件实现删等)
[root@node001 ~]# cd /opt
[root@node001 opt]# rz(上传hadoop-3.1.2.tar.gz)
[root@node001 opt]# tar -zxf hadoop-3.1.2.tar.gz
[root@node001 opt]# rm -rf hadoop-3.1.2.tar.gz
[root@node001 opt]# cd hadoop-3.1.2/etc/hadoop/
[root@node001 hadoop]# vim 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
[root@node001 hadoop]# vim core-site.xml
fs.defaultFS</name>
hdfs://node001:9000</value>
</property>
hadoop.tmp.dir</name>
/var/bdp/hadoop/full</value>
</property>
配置免密,不然会报权限错误
cp ~/.ssh/id_rsa.pub authorized_keys
cat ./id_rsa.pub >> ./authorized_keys # 或者加入授权
vim /etc/ssh/sshd_config
PermitRootLogin yes(去掉#)
PasswordAuthentication yes(去掉#)
systemctl restart sshd(重启)
vim /etc/hosts(修改域名对应关系192.168.111.101 node001)
[root@node001]# zkServer.sh start
[root@node001]# zkServer.sh status
[root@node001]# jps
[root@node001 hadoop]# vim hdfs-site.xml
dfs.namenode.secondary.http-address</name>
node002:50090</value>
</property>
dfs.namenode.secondary.https-address</name>
node002:50091</value>
</property>
dfs.replication</name>
2</value>
</property>
[root@node001 hadoop]# vim workers
(删除localhost)
node001
node002
node003
[root@node001 hadoop]# cd /opt
[root@node001 opt]# scp -r hadoop-3.1.2 192.168.111.102:/opt/
[root@node001 opt]# scp -r hadoop-3.1.2 192.168.111.103:/opt/
[root@node001 opt]# yum install -y ntp(三台都安装)
[root@node002 opt]# ntpdate cn.ntp.org.cn(三台时间同步)
[root@node001 logs]# vim /etc/profile
export HADOOP_HOME=/opt/hadoop-3.1.2
export PATH=$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$PATH
[root@node001 logs]# scp /etc/profile node002:/etc/
[root@node001 logs]# scp /etc/profile 192.168.111.103:/etc/
[root@node001 logs]# source /etc/profile
[root@node001 logs]# ssh root@node002 "source /etc/profile"
[root@node001 logs]# ssh root@node003 "source /etc/profile"
[root@node01 opt]# hdfs namenode -format(格式化NameNode)
[root@node01 opt]# start-dfs.sh(leader下运行)
[root@node001 logs]# jps
http://192.168.111.101:9870
http://192.168.111.102:50090
[root@node001 ~]# cd /opt/
[root@node001 opt]# cd hadoop-3.1.2
[root@node001 hadoop-3.1.2]# cd logs
[root@node001 logs]# hadoop fs -mkdir /bdp
[root@node001 logs]# hadoop fs -touch /bdp/2023-03-24.txt
[root@node001 logs]# hdfs dfs -mkdir /bdp/tmp
[root@node001 logs]# hdfs dfs -mkdir /bdp/tmp/2023-03-25.txt
[root@node001 logs]# hadoop fs -ls /bdp
Found 2 items
-rw-r--r-- 2 root supergroup 0 2023-03-25 01:47 /bdp/2023-03-24.txt
drwxr-xr-x - root supergroup 0 2023-03-25 01:50 /bdp/tmp
[root@node001 logs]# hdfs dfs -ls /bdp
Found 2 items
-rw-r--r-- 2 root supergroup 0 2023-03-25 01:47 /bdp/2023-03-24.txt
drwxr-xr-x - root supergroup 0 2023-03-25 01:50 /bdp/tmp
[root@node001 logs]# stop-dfs.sh (关闭集群)
[root@node001 logs]# jps
[root@node001 logs]# zkServer.sh stop(关闭zookeeper)
[root@node001 logs]# zkServer.sh status(查看zookeeper状态)
[root@node001 logs]# poweroff (关机)
[root@node001 ~]# cd /opt
[root@node001 ~]# vim start-bdp.sh(编写启动脚本)
#!/bin/bash
echo "$(date)======启动node001的zookeeper======" >> /root/logs/start-bdp.log
zkServer.sh start >> /root/logs/start-bdp.log
echo "======启动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 "======启动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 "$(date)======查看node001的zookeeper状态======" >> /root/logs/start-bdp.log
zkServer.sh status >> /root/logs/start-bdp.log
echo "======查看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 "======查看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 "" >> /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 "======启动hdfs集群======" >> /root/logs/start-bdp.log
start-dfs.sh >> /root/logs/start-bdp.log
echo "$(date)======查看node001的jps状态======" >> /root/logs/start-bdp.lo >> /root/logs/start-bdp.log
jps >> /root/logs/start-bdp.log
echo "======查看node002的jps状态======" >> /root/logs/start-bdp.log
ssh root@node002 "jps" >> /root/logs/start-bdp.log
echo "======查看node003的jps状态======" >> /root/logs/start-bdp.log
ssh root@node003 "jps" >> /root/logs/start-bdp.log
echo "$(date)=============启动完成=============" >> /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 "" >> /root/logs/start-bdp.log
echo "" >> /root/logs/start-bdp.log
echo "" >> /root/logs/start-bdp.log
[root@node001 ~]# sh start-bdp.sh (目录和文件没有创建)
start-bdp.sh: line 2: /root/logs/start-bdp.log: No such file or directory
[root@node001 ~]# mkdir logs(创建文件夹)
[root@node001 ~]# touch logs/start-bdp.log (创建脚本日志文件)
[root@node001 ~]# sh start-bdp.sh(启动脚本文件)
[root@node001 ~]# cat logs/start-bdp.log(查看启动日志)
[root@node001 ~]# vim checkCluster.sh(制作每台都运行命令的脚本)
#!/bin/bash
echo "=============================="
$1 $2 $3 $4
echo "=============================="
ssh root@node002 "$1 $2 $3 $4"
echo "=============================="
ssh root@node003 "$1 $2 $3 $4"
[root@node001 ~]# sh checkCluster.sh jps(查看jps)
[root@node001 ~]# sh checkCluster.sh zkServer.sh status(查看每台zookeeper状态,$代表变量,每一个代表一个变量)
bash: zkServer.sh: command not found
[root@node001 ~]# sh checkCluster.sh /opt/zookeeper-3.4.5/bin/zkServer.sh status
stat:元数据信息-->描述文件的属性
元数据
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数
文件数据:真实存在于文件中的数据
接受客户端的读写服务
NameNode存放文件与Block的映射关系
NameNode会记录Block与DataNode的映射关系,但是不会持久化
保存文件的元数据信息
文件的归属
文件的权限
文件的大小时间
Block信息,但是block的位置信息不会持久化,需要每次开启集群的时候DN上报
收集Block的信息
系统启动时
NN关机的时候是不会存储任意的Block与DN的映射信息
DN启动的时候,会将自己节点上存储的Block信息汇报给NN
NN接受请求之后重新生成映射关系
Block--DN3
如果某个数据块的副本数小于设置数,那么NN会将这个副本拷贝到其他节点
集群运行中
NN与DN保持心跳机制,三秒钟发送一次
如果客户端需要读取或者上传数据的时候,NN可以知道DN的健康情况
可以让客户端读取存活的DN节点
如果DN超过三秒没有心跳,就认为DN出现异常
- 不会让新的数据读写到DataNode
- 客户访问的时候不提供异常结点的地址
如果DN超过10分钟+30秒没有心跳,那么NN会将当前DN存储的数据转存到其他节点
超时时长的计算公式为:timeout = 2 * heartbeat.recheck.interval + 10 * dfs.heartbeat.interval。
而默认的heartbeat.recheck.interval 大小为5分钟,dfs.heartbeat.interval默认为3秒
[root@node001 ~]# vim /opt/hadoop-3.1.2/etc/hadoop/hdfs-site.xml(粘贴,修改心跳机制)
Determines datanode heartbeat interval in seconds.</description>
dfs.heartbeat.interval</name>
3</value>
</property>
heartbeat.recheck.interval</name>
300000</value>
</property>
NameNode为了效率,将所有的操作都在内存中完成
NameNode不会和磁盘进行任何的数据交换
问题:
数据的持久化
数据保存在内存中,掉电易失
小文件太多,占用内存太大
存放的是文件的数据信息和验证文件完整性的校验信息
数据会存放在硬盘上
1m=1条元数据 1G=1条元数据
NameNode非常排斥存储小文件,一般小文件在存储之前需要进行压缩
汇报
启动时
汇报之前先验证Block文件是否被损坏
向NN汇报当前DN上block的信息
运行中
向NN保持心跳机制
客户可以向DN读写数据,
当客户端读写数据的时候,首先去NN查询file与block与dn的映射
然后客户端直接与dn建立连接,然后读写数据
日志机制
做任何操作之前先记录日志
当NN下次启动的时候,只需要重新按照以前的日志“重做”一遍即可
缺点
edits文件大小不可控,随着时间的发展,集群启动的时间会越来越长
有可能日志中存在大量的无效日志
优点
绝对不会丢失数据
拍摄快照
我们可以将内存中的数据写出到硬盘上(序列化)
启动时还可以将硬盘上的数据写回到内存中(反序列化)
缺点
关机时间过长
如果是异常关机,数据还在内存中,没法写入到硬盘
如果写出频率过高,导致内存使用效率低(stop the world) JVM
优点
启动时间较短
解决思路(日志edits+快照fsimage)
让日志大小可控
定时快照保存
解决方案
当我们启动一个集群的时候,会产生四个文件
edits_0000000000000000001(日志文件)
fsimage_00000000000000000(快照文件)
seen_txid(完整性校验规则)
VERSION(版本)
我们每次操作都会记录日志 -->edits_inprogress-000000001(当前已经正在执行的操作的日志信息,这些日志信息还没有被合并到镜像中)
随和时间的推移,日志文件会越来越大,当达到阈值的时候(64M 或 3600秒)
dfs.namenode.checkpoint.period 每隔多久做一次checkpoint ,默认3600s
dfs.namenode.checkpoint.txns 每隔多少操作次数做一次checkpoint,默认1000000次
dfs.namenode.checkpoint.check.period 每个多久检查一次操作次数,默认60s
会生成新的日志文件 edits_inprogress-000000001 -->edits_0000001
创建新的日志文件 edits_inprogress-0000000016
[root@node001 current]# jps
19959 Jps
8332 NameNode
8412 DataNode
7806 QuorumPeerMain
[root@node001 current]# kill -9 8332(杀死Namenode进程)
[root@node001 current]# jps
20006 Jps
8412 DataNode
7806 QuorumPeerMain
[root@node001 ~]# sh checkCluster.sh ls /var/bdp/hadoop/full/dfs/name/current/
edits_0000000000000000001-0000000000000000002 edits_inprogress_0000000000000000018
edits_0000000000000000003-0000000000000000003 fsimage_0000000000000000015
edits_0000000000000000004-0000000000000000009 fsimage_0000000000000000015.md5
edits_0000000000000000010-0000000000000000011 fsimage_0000000000000000017
edits_0000000000000000012-0000000000000000013 fsimage_0000000000000000017.md5
edits_0000000000000000014-0000000000000000015 seen_txid
edits_0000000000000000016-0000000000000000017 VERSION
[root@node001 ~]# rm -rf /var/bdp/hadoop/full/dfs/name/current/*(删除NameNode所有信息)
[root@node001 ~]# scp node002:/var/bdp/hadoop/full/dfs/namesecondary/current/* /var/bdp/hadoop/full/dfs/name/current/(从SecondaryNameNode上面拷贝过来)
[root@node001 ~]# ls /var/bdp/hadoop/full/dfs/name/current/
edits_0000000000000000001-0000000000000000002
......
[root@node001 ~]# hadoop-daemon.sh start namenode(启动namenode)
[root@node002 ~]# jps
28754 Jps
13683 QuorumPeerMain
13843 SecondaryNameNode
13764 DataNode
[root@node002 ~]# cd /var/bdp/hadoop/full/dfs/namesecondary/current
[root@node002 current]# pwd
/var/bdp/hadoop/full/dfs/namesecondary/current
集群启动时的状态,处于安全模式的状态下,只向客户端提供文件的只读视
图,不接受对命名空间的修改;同时NameNode节点也不会进行数据块的复制或者删除,
节点距离:两个节点到达最近的共同祖先的距离总和
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
机架感知(rack awareness)是为了保证副本在集群的安全性
我们需要将副本放在不同的DN节点上,节点需要可靠性、可用性、带宽消耗
a. 第一个副本在Client所处的节点上。如果客户端在集群外,随机选一个
b. 第二个副本在另一个机架的随机一个节点
c. 第三个副本在第二个副本所在机架的随机节点
d.第N个副本,与前面节点不重复的其他节点
副本节点选择策略原因
a. 第一个节点优先选择本地,考虑的是节点距离最近,上传速度最快
b. 第二个节点选择与第一个节点不同机架考虑的是数据安全问题
c. 第三个节点与第二个节点相同机架考虑的是效率问题,同一个机架传输效率高
1. 客户端向HDFS发送写数据请求
hdfs dfs -put tomcat.tar.gz /yjx/
2. filesystem通过rpc调用namenode的create方法
nn首先检查是否有足够的空间权限等条件创建这个文件,或者这个路径是否已经存在
有:NN会针对这个文件创建一个空的Entry对象,并返回成功状态给DFS
没有:直接抛出对应的异常,给予客户端错误提示信息
3. DFS如果接收到成功状态,会创建一个对象 FSDataOutputStream的对象给客户端使用
4. 客户端需要向NN询问第一个Block存放的位置
NN通过机架感知策略 (node1 node 2 node8)
5. 需要将客户端和DN节点创建连接
pipeline(管道)
客户端和node1创建连接 socket
node1和node2创建连接 socket
node2 和Node8创建连接 socket
6. 客户端将文件按照块block切分数据,但是按照packet发送数据
默认一个packet大小为64K,Block128M为2048个packet
7. 客户端通过pipeline管道开始使用FSDataOutputStream对象将数据输出
客户端首先将一个packet发送给node1,同时给予node1一个ack状态
node1接受数据后会将数据继续传递给node2,同时给予node2一个ack状态
node2接受数据后会将数据继续传递给node8,同时给予node8一个ack状态
node8将这个packet接受完成后,会响应这个ack给node2为true
node2会响应给node1 ,同理node1响应给客户端
8. 客户端接收到成功的状态,就认为某个packet发送成功了,直到当前块所有的packet都发送完成
9. 如果客户端接收到最后一个pakcet的成功状态,说明当前block传输完成
10. 客户端会将这个消息传递给NN,NN确认传输完成
NN会将block的信息记录到Entry,客户端会继续向NN询问第二个块的存储位置,依次类推
block1 (node1 node2 node8)
block2 (node1 node8 node9)
....
blockn(node1 node7 node9)
12. 当最后一个Block传输完成,管道就会被撤销
13. 当所有的block传输完成后,NN在Entry中存储所有的File与Block与DN的映射关系
14. 关闭FsDataOutPutStream
[root@node001 ~]# hadoop fs -put zookeeper.out /bdp/(上传zookeeper.out到集群/bdp/目录下)
[root@node001 ~]# hadoop fs -ls /bdp(查看集群/bdp目录下的文件)
[root@node001 ~]# hdfs dfs -ls -h -r /bdp(查看集群/bdp目录下的文件)
[root@node001 ~]# cat /opt/hadoop-3.1.2/etc/hadoop/hadoop-env.sh(配置权限用户为root)
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
首先客户端发送请求到DFS,请求读文件
/tomcat.tar.gz
DFS去NN查找这个文件的信息(权限,文件是否存在)
如果文件不存在,抛出指定的错误
如果文件存在,返回成功状态
DFS创建FSDataInputStream对象,客户端通过这个对象读取数据
客户端获取文件第一个Block信息,返回DN1 DN2 DN8
客户端直接就近原则选择DN1对应的数据即可
依次类推读取其他块的信息,直到最后一个块,将Block合并成一个文件
关闭FSDataInputStrea
单点故障:每个群集只有一个NameNode,NameNode存在单点故障(SPOF)。
NameNode启动和重新启动(意外事件例如机器崩溃)之前将不可用
计划内的维护事件,例如NameNode计算机上的软件或硬件升级,将导致群集停机时间的延长。
水平扩展
将来服务器启动的时候,启动速度慢
namenode随着业务的增多,内存占用也会越来越多
如果namenode内存占满,将无法继续提供服务
业务隔离性差
存储:有可能我们需要存储不同部门的数据
计算:有可能存在不同业务的计算流程
项目后期namenode的吞吐量将会是集群的瓶颈
客户端所有的请求都会先访问NameNode
Hadoop2.x
NameNode节点的高可用
HA--high availability
NameNode业余的水平扩展
Federation
hadoop2.x启用了主备节点切换模式(1主1备)
当主节点出现异常的时候,集群直接将备用节点切换成主节点
要求备用节点马上就要工作
主备节点内存几乎同步
有独立的线程对主备节点进行监控健康状态
需要有一定的选举机制,帮助我们确定主从关系
我们需要实时存储日志的中间件
Active NameNode 的功能和原理的NN的功能是一样的
接受客户端请求,查询数据块DN信息
存储数据的元数据信息
数据文件:Block:DN的映射关系
工作
启动时:接受DN的block汇报
运行时:和DN保持心跳(3s,10m30s)
存储介质
完全基于内存
优点:数据处理效率高
缺点:数据的持久化(日志edits+快照fsimage)
Standby NameNode:NN的备用节点
他和主节点做同样的工作,但是它不会发出任何指令
存储:数据的元数据信息
数据文件:Block:DN的映射关系
它的内存数据和主节点内存数据几乎是一致的
工作:
启动时:
接受DN的block汇报
运行时:
和DN保持心跳(3s,10m30s)
存储介质
完全基于内存
优点:数据处理效率高
缺点:数据的持久化
合并日志文件和镜像
当搭建好集群的时候,格式化主备节点的时候,ANN和SNN都会会默认创建
fsimage_000000000000000
当我们操作HDFS的时候ANN会产生日志信息
edits_inprogress_0000000000001
主节点会将日志文件中新增的数据同步到JournalNode集群上
所以只需要snn有操作的日志信息,就可以合并fsImage与edits信息,理论上是一直在合并数据
fsimage -->初始化创建
edits-->从JournalNode集群上定时同步
只要同步到edits文件,就开始于fsimage合并
当达到阈值的时候,直接拍摄快照即可
SNN将合并好的Fsimage发送给ANN,ANN验证无误后,存放到自己的目录中
存储
文件的Block数据
介质
硬盘
启动时:
同时向两个NN汇报Block信息
运行中
同时和两个NN节点保持心跳机制
Quorum JournalNode Manager 共享存储系统,NameNode通过共享存储系统实现日志数据同
步。
JournalNode是一个独立的小集群,它的实现原理和Zookeeper的一致( Paxos)
ANN产生日志文件的时候,就会同时发送到 JournalNode的集群中每个节点上
JournalNode不要求所有的jn节点都接收到日志,只要有半数以上的(n/2+1)节点接受收到日
志,那么本条日志就生效
SNN每间隔一段时间就去QJM上面取回最新的日志
SNN上的日志有可能不是最新的
HA集群的状态正确至关重要,一次只能有一个NameNode处于活动状态。
JournalNode只允许单个NameNode成为作者。在故障转移期间,将变为活动状态的NameNode
将承担写入JournalNodes的角色,这将有效地防止另一个NameNode继续处于活动状态,从而使
新的Active节点可以安全地进行故障转移。
Failover Controller(故障转移控制器)
对 NameNode 的主备切换进行总体控制,能及时检测到 NameNode 的健康状况
在主 NameNode 故障时借助 Zookeeper 实现自动的主备选举和切换
为了防止因为NN的GC失败导致心跳受影响,ZKFC作为一个deamon进程从NN分离出来
启动时:
当集群启动时,主备节点的概念是很模糊的
当ZKFC只检查到一个节点是健康状态,直接将其设置为主节点
当zkfc检查到两个NN节点是的健康状态,发起投票机制
选出一个主节点,一个备用节点,并修改主备节点的状态
运行时:
由 ZKFailoverController、HealthMonitor 和 ActiveStandbyElector 这 3 个组件来协同实现
主备切换
ZKFailoverController启动的时候会创建 HealthMonitor 和 ActiveStandbyElector 这两个主要的内部组件
HealthMonitor 主要负责检测 NameNode 的健康状态
ActiveStandbyElector 主要负责完成自动的主备选举,内部封装了 Zookeeper 的处理逻辑
主备节点正常切换
NameNode 在选举成功后,ActiveStandbyElector会在 zk 上创建一个
ActiveStandbyElectorLock 临时节点,而没有选举成功的备 NameNode 中的
ActiveStandbyElector会监控这个节点
如果 Active NameNode 对应的 HealthMonitor 检测到 NameNode 的状态异常时,
ZKFailoverController 会主动删除当前在 Zookeeper 上建立的临时节点
ActiveStandbyElectorLock
如果是 Active NameNode 的机器整个宕掉的话,那么跟zookeeper连接的客户端线程也挂
了,会话结束,那么根据 Zookeepe的临时节点特性,ActiveStandbyElectorLock 节点会自动被
删除,从而也会自动进行一次主备切换
处于 Standby 状态的 NameNode 的 ActiveStandbyElector 注册的监听器就会收到这个节点
的 NodeDeleted 事件,并创建 ActiveStandbyElectorLock 临时节点,本来处于 Standby 状
态的 NameNode 就选举为Active NameNode 并随后开始切换为 Active 状态。
为主备切换控制器提供主备选举支持。
辅助投票
和ZKFC保持心跳机制,确定ZKFC的存活
定义:实际运行过程中很有可能出现两个namenode同时服务于整个集群的情况,这种情况称之为脑裂。
原因
脑裂通常发生在主从namenode切换时,由于ActiveNameNode的网络延迟、设备故障等问
题,另一个NameNode会认为活跃的NameNode成为失效状态,此时StandbyNameNode会
转换成活跃状态,此时集群中将会出现两个活跃的namenode。因此,可能出现的因素有网
络延迟、心跳故障、设备故障等。
脑裂场景
NameNode 可能会出现这种情况,NameNode 在垃圾回收(GC)时,可能会在长时间内整个系统无响应
zkfc客户端也就无法向 zk 写入心跳信息,这样的话可能会导致临时节点掉线,备 NameNode会切换到 Active 状态
这种情况可能会导致整个集群会有同时有两个Active NameNode
脑裂问题的解决方案是隔离(Fencing)
1.第三方共享存储:任一时刻,只有一个 NN 可以写入;
2.DataNode:需要保证只有一个 NN 发出与管理数据副本有关的命令;
3.Client需要保证同一时刻只有一个 NN 能够对 Client 的请求发出正确的响应。
(a) 每个NN改变状态的时候,向DN发送自己的状态和一个序列号。
(b) DN在运行过程中维护此序列号,当failover时,新的NN在返回DN心跳时会返回自己
的active状态和一个更大的序列号。DN接收到这个返回是认为该NN为新的active。
(c) 如果这时原来的active(比如GC)恢复,返回给DN的心跳信息包含active状态和原来的序列号,这时DN就会拒绝这个NN的命令。
解决方案XQ
- ActiveStandbyElector为了实现 fencing,当NN成为ANN之后创建Zookeeper临时节点
ActiveStandbyElectorLock,创建ActiveBreadCrumb 的持久节点,这个节点里面保存了这个Active NameNode的地址信息(node-01)
- Active NameNode的 ActiveStandbyElector在正常的状态下关闭 Zookeeper Session的时候,会一起删除这个持久节点
但如果ActiveStandbyElector在异常的状态下关闭,那么由于/hadoopha/${dfs.nameservices}/ActiveBreadCrumb 是持久节点,
会一直保留下来,后面当另一个NameNode 选主成功之后,会注意到上一个 Active NameNode 遗留下来的这个节点,从而
会回调 ZKFailoverController的方法对旧的 Active NameNode 进行 fencing。
- 首先尝试调用这个旧 Active NameNode 的 HAServiceProtocol RPC
接口的transitionToStandby 方法,看能不能把它转换为 Standby 状态;
- 如果 transitionToStandby 方法调用失败,那么就执行 Hadoop 配置文件之中预定义的隔离措施。
- 1) sshfence:通过 SSH 登录到目标机器上,执行命令 fuser 将对应的进程杀死
- 2) shellfence:执行一个用户自定义的 shell 脚本来将对应的进程隔离
- 在成功地执行完成 fencing 之后,选主成功的 ActiveStandbyElector 才会回调
ZKFailoverController 的 becomeActive 方法将对应的 NameNode 转换为 Active 状态,开始对外提供服务。
- 新的主创建临时节点ActiveStandbyElectorLock,创建持久化节点ActiveBreadCrumb ,并将 自己的主机地址Node02赋值给初始化节点
HDFS Federation就是使得HDFS支持多个命名空间,并且允许在HDFS中同时存在多个NameNode
Namespace(命名空间)的限制
NameNode所能存储的对象(文件+块)数目受到NameNode所在JVM的heap size的限制。
50G的heap能够存储20亿(200million)个对象,这20亿个对象支持4000个DataNode,12PB的存储
DataNode从4T增长到36T,集群的尺寸增长到8000个DataNode。存储的需求从12PB增长到大于100PB。
性能的瓶颈
整个HDFS文件系统的吞吐量受限于单个Namenode的吞吐量
隔离问题
HDFS上的一个实验程序就很有可能影响整个HDFS上运行的程序
集群的可用性
Namenode的宕机无疑会导致整个集群不可用。
Namespace和Block Management的紧密耦合
纵向扩展目前的Namenode不可行
将Namenode的Heap空间扩大到512GB启动花费的时间太长
Namenode在Full GC时,如果发生错误将会导致整个集群宕机
块池Block Pool
Block pool(块池)就是属于单个命名空间的一组block(块)管理区域
每一个datanode为所有的block pool存储
Datanode是一个物理概念,而block pool是一个重新将block划分的逻辑概念
一个Namenode失效不会影响其下的datanode为其他Namenode的服务
datanode与Namenode建立联系并开始会话后自动建立Block pool
Namespace Volume(命名空间卷)
一个Namespace和它的Block Pool合在一起称作Namespace Volume
Namespace Volume是一个独立完整的管理单元。当一个Namenode/Namespace被删除,与之相对应的Block Pool也也被删除。
通过多个namenode/namespace把元数据的存储和管理分散到多个节点中
降低单个NN节点数据压力,计算压力
namenode/namespace可以通过增加机器来进行水平扩展
可以让更多的节点参与到运算
namespace命名空间,通过这种方式确定要处理数据的路径
我们可以通过namenode和namespace组合使用
所有的nn共享dn
但是每一个namespace会单独管理自己的块
会创建一个管理块的机制:blocks pool
[root@node001 ~]# rz(上传hadoop-3.1.2.tar.gz)
[root@node001 ~]# tar -zxf hadoop-3.1.2.tar.gz -C /opt(解压到指定目录)
[root@node001 ~]# rm -rf hadoop-3.1.2.tar.gz
[root@node001 ~]# 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 YARN_RESOURCEMANAGER_USER=root
export YARN_NODEMANAGER_USER=root
[root@node001 opt]# vim /opt/hadoop-3.1.2/etc/hadoop/core-site.xml
fs.defaultFS</name>
hdfs://bdp</value>
</property>
hadoop.tmp.dir</name>
/var/bdp/hadoop/ha</value>
</property>
hadoop.http.staticuser.user</name>
root</value>
</property>
ha.zookeeper.quorum</name>
node001:2181,node002:2181,node003:2181</value>
</property>
[root@node001 ~]# vim /opt/hadoop-3.1.2/etc/hadoop/hdfs-site.xml
dfs.nameservices</name>
bdp</value>
</property>
dfs.ha.namenodes.bdp</name>
nn1,nn2</value>
</property>
dfs.namenode.rpc-address.bdp.nn1</name>
node001:8020</value>
</property>
dfs.namenode.rpc-address.bdp.nn2</name>
node002:8020</value>
</property>
dfs.namenode.http-address.bdp.nn1</name>
node001:9870</value>
</property>
dfs.namenode.http-address.bdp.nn2</name>
node002:9870</value>
</property>
dfs.namenode.shared.edits.dir</name>
qjournal://node001:8485;node002:8485;node003:8485/bdp</value>
</property>
dfs.journalnode.edits.dir</name>
/var/bdp/hadoop/ha/qjm</value>
</property>
dfs.client.failover.proxy.provider.bdp</name>
org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>
dfs.ha.fencing.methods</name>
sshfence</value>
shell(true)</value>
</property>
dfs.ha.fencing.ssh.private-key-files</name>
/root/.ssh/id_rsa</value>
</property>
dfs.ha.automatic-failover.enabled</name>
true</value>
</property>
dfs.replication</name>
2</value>
</property>
[root@node001 ~]# vim /opt/hadoop-3.1.2/etc/hadoop/workers
node001
node002
node003
[root@node001 ~]# scp -r /opt/hadoop-3.1.2 root@node002:/opt/ (hadoop-3.1.2传到node002的/opt目录下)
[root@node001 ~]# scp -r /opt/hadoop-3.1.2 root@node003:/opt/ (hadoop-3.1.2传到node003的/opt目录下)
理解[root@node02 ~]# scp -r root@node001:/opt/hadoop-3.1.2 /opt/(node001上hadoop-3.1.2传到当前主机 /opt目录下)
[root@node03 ~]# scp -r root@node001:/opt/hadoop-3.1.2 /opt/(node001上hadoop-3.1.2传到当前主机 /opt目录下)
[root@node001 ~]# vim /etc/profile
export HADOOP_HOME=/opt/hadoop-3.1.2
export PATH=$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$PATH
[root@node001 ~]# scp /etc/profile root@node002:/etc/profile
[root@node001 ~]# scp /etc/profile root@node003:/etc/profile
[root@node001 ~]# source /etc/profile (打开所有会话执行或者)
[root@node001 ~]# ssh node002 "source /etc/profile"
[root@node001 ~]# ssh node003 "source /etc/profile"
[root@node001 ~]# zkServer.sh start (打开所有会话执行)
[root@node001 ~]# zkServer.sh status (打开所有会话执行)
[root@node001 ~]# hdfs --daemon start journalnode (打开所有会话执行,启动journalnode)
[root@node001 ~]# hdfs namenode -format(格式化namenode)
[root@node001 ~]# hdfs --daemon start namenode(启动namnode)
[root@node002 ~]# hdfs namenode -bootstrapStandby
[root@node001 ~]# hdfs zkfc -formatZK (格式化)
[root@node001 ~]# start-dfs.sh
http://node001:9870
http://node002:9870
[root@node001 ~]# hadoop fs -mkdir /bdp(集群中创建文件夹bdp)
[root@node001 ~]# hadoop fs -touch /bdp/2023-03-30.txt (集群bdp目录下创建文件)
[root@node001 ~]# rz(上传压缩包 winutils-master.zip)
[root@node001 ~]# hdfs dfs -mkdir /bdp/tmp(在bdp目录下创建文件夹tmp)
[root@node001 ~]# hdfs dfs -put winutils-master.zip /bdp/tmp/(将压缩包winutils-master.zip放到tmp目录下)
[root@node001 ~]# hdfs dfs -D dfs.blocksize=1048576 -put inutils-master.zip /bdp/ (将压缩包放到bdp目录下,并且设置块的大小为1M,默认为128M)
[root@node001 ~]# stop-dfs.sh(停止集群)
[root@node001 ~]# zkServer.sh stop (停止zookeeper)
[root@node001 ~]# poweroff(关机)
[root@node001 ~]# jps
6801 Jps
[root@node001 ~]# date(三台linux时间必须一样,否则需要进行时间同步)
[root@node001 ~]# zkServer.sh start (启动zookeeper)
[root@node001 ~]# start-dfs.sh (启动集群)
[root@node001 ~]# jps
6848 QuorumPeerMain
7618 DFSZKFailoverController
9095 DataNode
8122 NameNode
9468 Jps
7453 JournalNode
[root@node001 ~]# kill -9 8122
[root@node001 ~]# jps (网页发现node001无法访问)
6848 QuorumPeerMain
7618 DFSZKFailoverController
9095 DataNode
9527 Jps
7453 JournalNode
[root@node001 ~]# hdfs --daemon start namenode (启动namenode)
stop-dfs.sh 停止Hadoop HDFS守护进程NameNode、SecondaryNameNode和DataNode
stop-all.sh 停止所有的Hadoop守护进程
sbin/hadoop-daemons.sh start namenode 单独启动NameNode守护进程
sbin/hadoop-daemons.sh stop namenode 单独停止NameNode守护进程
sbin/hadoop-daemons.sh start datanode 单独启动DataNode守护进程
sbin/hadoop-daemons.sh stop datanode 单独停止DataNode守护进程
sbin/hadoop-daemons.sh start secondarynamenode 单独启动SecondaryNameNode守护进程
sbin/hadoop-daemons.sh stop secondarynamenode 单独停止SecondaryNameNode守护进程
sbin/start-yarn.sh 启动ResourceManager、NodeManager
sbin/stop-yarn.sh 停止ResourceManager、NodeManager
sbin/yarn-daemon.sh start resourcemanager 单独启动ResourceManager
sbin/yarn-daemons.sh start nodemanager 单独启动NodeManager
sbin/yarn-daemon.sh stop resourcemanager 单独停止ResourceManager
sbin/yarn-daemons.sh stopnodemanager 单独停止NodeManager
sbin/mr-jobhistory-daemon.sh start historyserver 手动启动jobhistory
sbin/mr-jobhistory-daemon.sh stop historyserver 手动停止jobhistory
shutdown -h now
简介
HDFS默认情况下,Block的备份系数是3,一个原始数据块和其他2个副本。
其中2个副本所需要的存储开销各站100%,这样使得200%的存储开销
正常操作中很少访问具有低IO活动的冷数据集的副本,但是仍然消耗与原始数据集相同的资源量。
EC技术
EC(擦除编码)和HDFS的整合可以保持与提供存储效率相同的容错。
HDFS:一个副本系数为3,要复制文件的6个块,需要消耗6*3=18个块的磁盘空间
EC:6个数据块,3个奇偶校验块
擦除编码需要在执行远程读取时,对数据重建带来额外的开销,因此他通常用于存储不太频繁访问的数据
在Hadoop3中允许用户运行多个备用的NameNode。
例如,通过配置三个NameNode(1个Active NameNode和2个Standby NameNode)和5个JournalNodes节点
集群可以容忍2个NameNode节点故障。
早些时候,多个Hadoop服务的默认端口位于Linux端口范围以内。
因此,具有临时范围冲突端口已经被移除该范围
单个数据节点配置多个数据磁盘,在正常写入操作期间,数据被均匀的划分,因此,磁盘被均匀填充。
在维护磁盘时,添加或者替换磁盘会导致DataNode节点存储出现偏移
这种情况在早期的HDFS文件系统中,是没有被处理的。
Hadoop3通过新的内部DataNode平衡功能来处理这种情况,这是通过hdfs diskbalancer CLI来进
行调用的。执行之后,DataNode会进行均衡处理
JDK:
Hadoop3中,最低版本要求是JDK8,所以低于JDK8的版本需要对JDK进行升级,方可安装使用Hadoop3
Yarn:
提供YARN的时间轴服务V.2,以便用户和开发人员可以对其进行测试,并提供反馈意见
优化Hadoop Shell脚本
重构Hadoop Client Jar包
支持随机Container
MapReduce任务级本地优化
支持文件系统连接器
window系统的环境变量配置
解压hadoop-3.1.2.tar.gz,将解压后的文件夹存放到自己软件目录
例如:D:\soft\edit_soft\hadoop-3.1.2
解压winutils-master.zip,找到3.1.2版本复制bin目录下所有文件粘贴到D:\soft\edit_soft\hadoop-3.1.2\bin目录
D:\soft\edit_soft\hadoop-3.1.2\bin下的winutils.exe和hadoop.dll文件拷贝到 C:\Windows\System32目录下
环境变量
将Hadoop添加到环境变量
HADOOP_HOME : D:\software\hadoop-3.1.2
HADOOP_USER_NAME : root
Path : %HADOOP_HOME%\bin;%HADOOP_HOME%\sbin;
修改当前Window的hosts文件
C:\Windows\System32\drivers\etc\hosts
192.168.111.101 node001
192.168.111.102 node002
192.168.111.103 node003
拷贝Hadoop的配置文件
core-site.xml
hdfs-site.xml
[root@node001 hadoop]# sz core-site.xml hdfs-site.xml (拷贝到桌面)
<properties>
<maven.compiler.source>19maven.compiler.source>
<maven.compiler.target>19maven.compiler.target>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<hadoop.version>3.1.2hadoop.version>
<commons-io.version>2.4commons-io.version>
properties>
<dependencies>
<dependency>
<groupId>org.apache.hadoopgroupId>
<artifactId>hadoop-commonartifactId>
<version>${hadoop.version}version>
dependency>
<dependency>
<groupId>org.apache.hadoopgroupId>
<artifactId>hadoop-hdfsartifactId>
<version>${hadoop.version}version>
dependency>
<dependency>
<groupId>org.apache.hadoopgroupId>
<artifactId>hadoop-clientartifactId>
<version>${hadoop.version}version>
dependency>
<dependency>
<groupId>org.apache.hadoopgroupId>
<artifactId>hadoop-mapreduce-client-commonartifactId>
<version>${hadoop.version}version>
dependency>
<dependency>
<groupId>org.apache.hadoopgroupId>
<artifactId>hadoop-mapreduce-client-coreartifactId>
<version>${hadoop.version}version>
dependency>
<dependency>
<groupId>org.apache.hadoopgroupId>
<artifactId>hadoop-mapreduce-client-jobclientartifactId>
<version>${hadoop.version}version>
dependency>
<dependency>
<groupId>commons-iogroupId>
<artifactId>commons-ioartifactId>
<version>${commons-io.version}version>
dependency>
<dependency>
<groupId>com.janeluogroupId>
<artifactId>ikanalyzerartifactId>
<version>2012_u6version>
dependency>
dependencies>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
https://maven.apache.org/xsd/settings-1.0.0.xsd">
<mirrors>
<mirror>
<id>alimavenid>
<name>aliyun mavenname>
<url>http://maven.aliyun.com/nexus/content/groups/public/url>
<mirrorOf>centralmirrorOf>
mirror>
mirrors>
settings>
[root@node001 ~]# cd /opt/hadoop-3.1.2/etc/hadoop/
[root@node001 hadoop]# hadoop fs -ls /bdp (查看集群 /bdp目录下有那些文件)
创建类Hello01HDfs
package org.example;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.BlockLocation;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import java.io.IOException;
import java.util.Arrays;
public class Hello01HDfs {
public static void main(String[] args) throws IOException {
// pathInfo();
upload_download();
}
/**
* 文件信息
*
* @throws IOException
*/
private static void pathInfo() throws IOException {
//加载配置文件
Configuration configuration = new Configuration(true);
//获取文件系统
FileSystem fileSystem = FileSystem.get(configuration);
//创建路径的Path对象
Path path = new Path("/bdp/winutils-master.zip");//集群目录
boolean flag = fileSystem.exists(path);
System.out.println(fileSystem.getDefaultBlockSize(path) / 1024 / 1024);//m
System.out.println(fileSystem.getDefaultReplication(path));
BlockLocation[] bls = fileSystem.getFileBlockLocations(path, 0, 10);
for (BlockLocation blockLocation : bls) {
System.out.println("HelloHdfs.hello(============================1)"
);
System.out.println(blockLocation.getLength());
System.out.println(blockLocation.getOffset());
System.out.println(Arrays.toString(blockLocation.getHosts()));//[node001, node002]
System.out.println(Arrays.toString(blockLocation.getNames()));//[192.168.111.101:9866, 192.168.111.102:9866]
System.out.println(blockLocation.toString());//0,1048576,node001,node002
System.out.println("HelloHdfs.hello(============================2)");
}
}
/**
* 文件上傳和下載
*
* @throws IOException
*/
private static void upload_download() throws IOException {
//加载配置文件
Configuration configuration = new Configuration(true);
//获取文件系统
FileSystem fileSystem = FileSystem.get(configuration);
//文件上傳
// Path srcPath = new Path("D:\2023-03-31.txt");
// Path destPath = new Path("/bdp/");
// fileSystem.copyFromLocalFile(srcPath, destPath);
//文件下載
Path localPath = new Path("D:\\");
Path hdfsPath = new Path("/bdp/2023-03-30.txt");
fileSystem.copyToLocalFile(hdfsPath, localPath);
}
}
[root@node001 hadoop]# sz core-site.xml hdfs-site.xml (在集群里将xml拷贝到桌面上)
core-site.xml配置文件的作用:
用于定义系统级别的参数,如HDFS URL、Hadoop的临时目录以及用于rack-aware集群中的配置文件
的配置等,此中的参数定义会覆盖core-default.xml文件中的默认配置。
fs.defaultFS 参数的作用:
#声明namenode的地址,相当于声明hdfs文件系统。我们可以指定某个ip地址,在ha模式中我们通常指定hdfs集群的逻辑名称
hadoop.tmp.dir 参数的作用:
#声明hadoop工作目录的地址。
hadoop.http.staticuser.user 参数的作用:
#在网页界面访问数据使用的用户名。默认值是一个不真实存在的用户,此用户权限很小,不能访问不同
用户的数据。这保证了数据安全。也可以设置为hdfs和hadoop等具有较高权限的用户,但会导致能够登陆网
页界面的人能看到其它用户数据。实际设置请综合考虑。如无特殊需求。使用默认值就好.
ha.zookeeper.quorum 参数的作用:
#指定zookeeper集群的地址,让zookeeper帮我们管理hdfs集群。
hdfs-site.xml:HDFS的相关设定,如文件副本的个数、块大小及是否使用强制权限等,此中的参数定义会覆盖hdfs-default.xml文件中的默认配置.
dfs.replication:为了数据可用性及冗余的目的,HDFS会在多个节点上保存同一个数据块的多个副本,其默认为3个。
而只有一个节点的伪分布式环境中其仅用保存一个副本即可,这可以通过dfs.replication属性进行定义。它是一个软件级备份。
dfs.nameservices:指定一个逻辑名称,该名称会自动去帮我们找打真实NameNode节点,这和咱们的keepalive的VIP有点类似!这个名称咱们可以自定义
但是我们正在引用时千万别引用错了!
dfs.ha.namenodes.yinzhengjie-hdfs:看到没,上面我们定义了dfs.nameservices的名称,现在我们就用到了,
我们把定义的逻辑名称指向了各个namenode的别名
dfs.namenode.rpc-address.yinzhengjie-hdfs.namenode1:定义远程主机调用的服务器地址。
dfs.namenode.http-address.yinzhengjie-hdfs.namenode1 参数的作用:
#上面我们定义了集群的逻辑名称,也定义节点的逻辑名称,但是真正的ip地址我们始终没有指定,因此
我们这一步骤就是指定dfs.namenode.rpc-address.yinzhengjie-hdfs.namenode1对应的IP地址。
当然你写主机名称也是可以的,只不过嘛你得在/etc/hosts文件做映射或者配置DNS中有对应的A记录哟!
dfs.namenode.shared.edits.dir 参数的作用:
#配置JournalNode集群的地址。
dfs.client.failover.proxy.provider.yinzhengjie-hdfs 参数的作用:
#配置故障转移的代理类,这是HDFS客户端找到active NameNode类名的一个代理类,如果你不配置这
个项的话,那么客户端连接active namenode地址时会报错!实际上故障转移就是通过这个代理类来实现
的,我们只需要默认官网的配置即可!不需要手动修改!
dfs.ha.fencing.methods 参数的作用:
#指定ha出现故障时的隔离方法!
dfs.ha.fencing.ssh.private-key-files 参数的作用:
#指定隔离主机的私钥PATH。
dfs.journalnode.edits.dir 参数的作用:
#指定JN节点存放编辑日志的目录。
dfs.ha.automatic-failover.enabled 参数的作用:
#开启自动故障转移功能.
– dfs.name.dir
– NameNode 元数据存放位置
– 默认值:使用core-site.xml中的hadoop.tmp.dir/dfs/name
– dfs.block.size
– 对于新文件切分的大小,单位byte。默认是64M,建议是128M。每一个节点都要指定,包括客户端。
– 默认值:67108864
– dfs.data.dir
– DataNode在本地磁盘存放block的位置,可以是以逗号分隔的目录列表,DataNode循环向磁盘中写入数
据,每个DataNode可单独指定与其它DataNode不一样
– 默认值:${hadoop.tmp.dir}/dfs/data
– dfs.namenode.handler.count
– NameNode用来处理来自DataNode的RPC请求的线程数量
– 建议设置为DataNode数量的10%,一般在10~200个之间
– 如设置太小,DataNode在传输数据的时候日志中会报告“connecton refused"信息
– 在NameNode上设定
– 默认值:10
– dfs.datanode.handler.count
– DataNode用来连接NameNode的RPC请求的线程数量
– 取决于系统的繁忙程度
– 设置太小会导致性能下降甚至报错
– 在DataNode上设定
– 默认值:3
– dfs.datanode.max.xcievers
– DataNode可以同时处理的数据传输连接数
– 默认值:256
– 建议值:4096
– dfs.permissions
– 如果是true则检查权限,否则不检查(每一个人都可以存取文件)
– 于NameNode上设定
– 默认值:true
– dfs.datanode.du.reserved
– 在每个卷上面HDFS不能使用的空间大小
– 在每个DataNode上面设定
– 默认值:0
– 建议为10737418240,即10G。需要结合MapReduce场景设置。
– dfs.datanode.failed.volumes.tolerated
– DataNode可以容忍损块的磁盘数量,超过这个数量DataNode将会离线,所有在这个节点上面的block将
会被重新复制
– 默认是0,但是在有多块磁盘的时候一般会增大这个值
– dfs.replication
– 在文件被写入的时候,每一块将要被复制多少份
– 默认是3份。建议3份
– 在客户端上设定
通常也需要在DataNode上设定
– fs.default.name
– 文件系统的名字。通常是NameNode的hostname与port
– 需要在每一个需要访问集群的机器上指定,包括集群中的节点
– 例如:hdfs://:9000/
– fs.checkpoint.dir
– 以逗号分隔的文件夹列表,SecondNameNode用来存储checkpoint image文件
– 如果多于一个文件夹,那么都会被写入数据
– 需要在SecondNameNode上设定
– 默认值:${hadoop.tmp.dir}/dfs/namesecondary
– hadoop.tmp.dir
– HDFS与本地磁盘的临时文件
默认是/tmp/hadoop-${user.name}.需要在所有的节点中设定
– fs.trash.interval
– 当一个文件被删掉后,它会被放到用户目录的.Trash目录下,而不是立即删掉
– 经过此参数设置的分钟数之后,再删掉数据
– 默认是0,禁用此功能,建议1440(一天)
– io.file.buffer.size
– 设定在读写数据时的缓存大小,应该为硬件分页大小的2倍
– 默认是4096,建议为65536 ( 64K )