文章目录
Hadoop
HDFS
概述
HDFS是一个分布式的文件系统,通过目录树来定位文件。
使用场景:一次写入,多次读出。(文件上传后只读不改)
优点
-
高容错性
数据会自动保存多个副本,同时当某个副本丢失后,可以自动恢复(从别的机器上复制)。
-
处理大数据
(1) 数据规模:可以处理GB、TB甚至PB级别的数据。
(2) 文件规模:可以处理百万规模以上的文件数量。
-
机器要求低
可以构建在廉价的机器上,因为存在着副本机制。
缺点
-
速度慢
-
无法高效存储大量小文件
(1)小文件会占用NameNode大量的内存来存储文件目录和块信息。
(2)寻址时间会超过读取时间
-
不支持并发写入和文件随机修改
文件只支持追加。
*组成架构
NameNode(nn)
负责管理
(1)管理HDFS名称空间
存储所有的元数据
(2)配置副本策略
每个文件的副本有几个
(3)管理数据块(Block)映射信息
即每个文件所在的位置
(4)处理客户端读写请求
DataNode
(1)存储实际的数据块
(2)执行数据块的读/写
Secondary NameNode
不是NameNode的热备份,当NameNode挂了之后,不能立刻替换Nam deNode提供服务。
(1)辅助NameNode,分担工作,会定期合并Fsimage(镜像文件)和Edits(编辑日志),然后推送给NameNode
(2)紧急情况时,可以辅助恢复NameNode,但是可能会丢失部分数据
Client
(1)文件切分
按照nn的文件块大小对文件进行切分
(2)与NameNode交互,获取文件的位置信息
(3)与DataNode交互,读取或写入数据
(4)通过命令管理HDFS,比如NameNode格式化
(5)通过命令访问HDFS,实现增删改查
文件块大小
默认文件块大小为128M(dfs.blocksize),如果存入1KB的文件,只占用1KB,剩余的空间还可以存储别的文件。
寻址时间为传输时间的1%时,为最佳状态。
Shell命令
上传
剪切 (moveFromLocal)
hadoop fs -moveFromLocal 本地路径 hdfs 路径
拷贝(moveFromLocal/put)
hadoop fs -put 本地路径 hdfs路径
hadoop fs -copyFromLocal 本地路径 hdfs路径
追加文件到文件末尾(appendToFile)
hadoop fs -appendToFile 本地路径 hdfs具体文件路径
下载
copyToLocal/get
hadoop fs -get hdfs文件路径 本地路径
HDFS内操作
-ls: 显示目录信息
hadoop fs -ls hdfs路径
-cat:显示文件内容
hadoop fs -cat 文件路径
-chgrp、-chmod、-chown:Linux文件系统中的用法一样,修改文件所属权限
hadoop fs -chmod 666 文件路径
-mkdir:创建路径
hadoop fs -mkdir 路径
-cp:从HDFS的一个路径拷贝到HDFS的另一个路径
hadoop fs -cp 文件路径 目的路径
-mv:在HDFS目录中移动文件
hadoop fs -mv 文件路径 目的路径
-tail:显示一个文件的末尾1kb的数据
hadoop fs -tail 文件路径
-rm:删除文件或文件夹
hadoop fs -rm 文件路径
-rm -r:递归删除目录及目录里面内容
hadoop fs -rm -r 文件路径
-du统计文件夹的大小信息
hadoop fs -du -s -h 路径
-setrep:设置HDFS中文件的副本数量
hadoop fs -setrep 10
**注意:**这里的副本数知识记录在NameNode里的元数据中,具体有多少副本取决于DataNode的数量
*读写流程
写入过程
- Client创建分布式文件系统,向NN发送上传请求
- NN接收到请求后,进行校验,校验成功后,发送可以上传的响应
- Client请求上传数据,让NN返回DataNode
- NN通过节点选择返回存储数据的节点
- Client创建输出流,并向DataNode节点请求建立传输通道
- DataNode应答
- Client传输数据(数据在DataNode中会直接从内存中传给下一个节点,自己再存一份,保证传输速度)
节点距离计算
到达最近共同祖先的距离和
副本存储节点选择
如果有三个副本
第一个副本在Client所处的节点上。如果客户端在集群外,随机选一个。
第二个副本在另一个机架的随机一个节点。
第三个副本在第二个副本所在机架的随机节点。
源码:
protected Node chooseTargetInOrder(int numOfReplicas, Node writer, Set<Node> excludedNodes, long blocksize, int maxNodesPerRack, List<DatanodeStorageInfo> results, boolean avoidStaleNodes, boolean newBlock, EnumMap<StorageType, Integer> storageTypes) throws NotEnoughReplicasException {
int numOfResults = results.size();
if (numOfResults == 0) {
DatanodeStorageInfo storageInfo = this.chooseLocalStorage((Node)writer, excludedNodes, blocksize, maxNodesPerRack, results, avoidStaleNodes, storageTypes, true);
writer = storageInfo != null ? storageInfo.getDatanodeDescriptor() : null;
--numOfReplicas;
if (numOfReplicas == 0) {
return (Node)writer;
}
}
DatanodeDescriptor dn0 = ((DatanodeStorageInfo)results.get(0)).getDatanodeDescriptor();
if (numOfResults <= 1) {
this.chooseRemoteRack(1, dn0, excludedNodes, blocksize, maxNodesPerRack, results, avoidStaleNodes, storageTypes);
--numOfReplicas;
if (numOfReplicas == 0) {
return (Node)writer;
}
}
if (numOfResults <= 2) {
DatanodeDescriptor dn1 = ((DatanodeStorageInfo)results.get(1)).getDatanodeDescriptor();
if (this.clusterMap.isOnSameRack(dn0, dn1)) {
this.chooseRemoteRack(1, dn0, excludedNodes, blocksize, maxNodesPerRack, results, avoidStaleNodes, storageTypes);
} else if (newBlock) {
this.chooseLocalRack(dn1, excludedNodes, blocksize, maxNodesPerRack, results, avoidStaleNodes, storageTypes);
} else {
this.chooseLocalRack((Node)writer, excludedNodes, blocksize, maxNodesPerRack, results, avoidStaleNodes, storageTypes);
}
--numOfReplicas;
if (numOfReplicas == 0) {
return (Node)writer;
}
}
this.chooseRandom(numOfReplicas, "", excludedNodes, blocksize, maxNodesPerRack, results, avoidStaleNodes, storageTypes);
return (Node)writer;
}
读取过程
- Client创建分布式文件系统并向NN请求下载文件
- NN检验权限,找到文件信息后,将元数据发送给Client
- Client通过元数据挑选DataNode(就近原则,之后考虑负载均衡再随机挑选),通过输入流读取数据(以Packet为单位)
- 客户端以Packet为单位接收,先在本地缓存,然后写入目标文件(即先读取blk_1,然后再读取blk_2,一起写入目标文件)
NameNode 和 SecondaryNameNode
NN和2NN的工作机制
关于NN的元数据存储,如果存储在内存中,可以提高计算效率,但是一旦断电数据就都丢失了,可靠性很低;如果存在磁盘中,可以提高可靠性,但是运算速度会变慢。为了解决这个问题,HDFS拥有两个文件,一个是在磁盘中备份元数据的镜像文件FsImage,一个是Edits文件。
将元数据备份在FsImage中,当产生数据变更(增删改)时,如果更新数据会降低计算速度,不更新会造成数据的不一致,所以引入Edits文件,在Edits文件中只进行操作的追加,当我们最后断电时会将Edits和Fsimage进行合并,更新Fsimage数据。
以一个例子来展示:
假设有一个元数据x=1,这时发生了数据更改要将x+10,内存会进行计算,Fsimage不动,Edits写入一条操作x+10,当断电后,两个文件会合并,清空操作,更新Fsimage来恢复数据,当开机后,内存会加载两个文件,获取信息。
但是这会产生另外一个问题,当操作很多的时候,就会导致Edits(Edits_1)越来越大,断电后合并文件的时间会很长。所以这时候就引入了SecondaryNameNode(2NN),2NN会隔一段时间向NN发送请求,询问是否需要合并文件,NN响应后,会新建一个Edits文件(Edits_2)来存储后续的操作,然后滚动Edits_1,将Edits_1和Fsimage拷贝到2NN中,2NN将两个文件加载到内存进行合并,产生新的Fsimage,随后发送给NN,并更新Fsimage。
(图片源自尚硅谷)
Edits和Fsimage
- Fsimage文件:HDFS文件系统元数据的一个永久性的检查点,其中包含HDFS文件系统的所有目录和文件inode的序列化信息。
- Edits文件:存放HDFS文件系统的所有更新操作的路径,文件系统客户端执行的所有写操作首先会被记录到Edits文件中。
- seen_txid文件保存的是一个数字,就是最后一个edits_的数字
- 每次NameNode启动的时候都会将Fsimage文件读入内存,加载Edits里面的更新操作,保证内存中的元数据信息是最新的、同步的,可以看成NameNode启动的时候就将Fsimage和Edits文件进行了合并。
检查点时间设置
通常情况下,SecondaryNameNode每隔一小时执行一次。
一分钟检查一次操作次数,当操作次数达到1百万时,SecondaryNameNode执行一次
DataNode
工作机制
- DataNode启动后会向NameNode注册
- 注册成功后,每周期(6小时)向NN上报所有块信息
- 心跳是每3秒一次,心跳返回结果带有NN给DataNode的命令
- 如果10分钟+30秒没有收到心跳,NN就认为该DataNode不可用。