HDFS基本介绍
概述
1、HDFS(Hadoop Distribute File System)是Hadoop提供的一套分布式文件存储系统 【很多大数据框架的底层都是利用hdfs来存数据】
2、HDFS是Doug根据Google的论文(GFS)来仿照实现的
特点
1、支持存储超大文件 - 切块、【大】
2、快速的应对和检测故障 - 心跳 【块】
3、流式访问 - 在读写数据的时候是以流的形式来提供 【榴】
4、能够在相对廉价的机器上进行横向扩展 【莲】
5、不建议存储大量小文件(因为每一个文件都会占用元数据的空间,如果存在大量的元数据,会导致查询变慢)
6、HDFS是为了高吞吐而设计的,无法做到低延时的访问
7、一次写入多次读取,不允许修改,但允许在尾部追加。(简化的一致性模型)
8、不支持事务(hdfs的每一次写操作会分配一个事务id,但是这个事务只是用来记录每一次操作的,和数据库的事务不是一个东西,没有ACID这种说法,大部分大数据框架都不支持事务,因为对于大量数据来说,允许一部分数据错误,不需要因为部分数据而导致整个数据回滚)
不精确的条件下,允许千分之三的数据产生误差,100PB的数据不会由于128M的数据错误而产生回滚。
HDFS结构
单机存储的问题
文件太大,单机无法存储;
备份耗时太多
HDFS基本结构
先上一张架构图
1、HDFS中基本架构是由一个NameNode+多个DataNode来组成
2、在hdfs中存储数据的时候,会对文件进行切块(一整块无法存储),切块之后会将不同的数据块(Block)放到不同的节点上
3、在HDFS中,默认会对每一个Block进行备份,备份称之为副本(replicas)。在HDFS中,连同原来的Block构成3个副本
4、HDFS仿照Linux设计了一套文件存储系统,所以和Linux一样,是以/为根路径,每一个文件都存在权限问题
Block数据块
1、Block是HDFS存储数据的基本单位,Block会落地到DataNode的磁盘上
2、每一个Block的大小默认不超过128M,假设一个文件是1GB,那么这个文件会被切成8个Block。这个Block的大小可以通过dfs.blocksize属性来设置,单位是字节。配置文件的位置: /home/software/hadoop-2.7.1/etc/hadoop/hdfs-site.xml
3、如果文件大小不足128M,那么这个文件是多大所对应的Block就是多大。例如一个文件是20M,那么这个文件对应的Block大小就是20M;如果文件是150M,那么这个文件对应了2个Block:128M+22M
4、每一个Block都有自己的BlockID
5、切块的意义:
能够存储超大文件
能够快速备份(小的备份比较快)
NameNode
1、NameNode负责管理DataNode和记录元数据
2、元数据:描述数据的数据
3、元数据的主要包含
文件在HDFS上的位置
文件的block块大小
文件的block块数量
文件对应的blockId
blockid和数据节点的映射关系
文件的大小
文件的权限
上传文件的用户及用户组
副本数量
4、NameNode将元数据维系在什么地方?
将元数据维系在内存以及磁盘当中。
内存中是为了读写块,磁盘当中是为了崩溃恢复。
5、磁盘上元数据的存储目录是hadoop.tmp.dir配置的路径,如果不配置默认放在/tmp目录下
元数据位置:
hadoop.tmp.dir/dfs/name/current/ 其中的fsimage就是元数据
6、和元数据相关的两个文件 edit-,fsimage-
edits:记录写操作的文件
fsimage:保存元数据的文件。磁盘上的元数据和内存中的元数据一般是不一致的,中间缺少的数据通过edits中记录的操作日志来进行补充。
7、edits和fsimage是什么配合工作的
元数据维护在内存中和磁盘中,如果是读请求的话直接访问内存中的元数据;如果是写请求的话,需要先写入edits_inprogress文件中,写入成功之后再去修改内存中的元数据。修改成功以后会给客户端返回一个ACK表示成功。这个过程还不会设计到fsimage的修改。当满足edits文件的滚动条件的时候,会将edit_inprogress文件和fsimage文件合并,使得fsimage中缺少的数据补充回来。在这个过程之中,会将接受的新的请求写入到新的edits_inprogress文件中,之前的那个文件改名为edits_00000xx的样子。
注意,edits中不记录元数据,只是记录写操作,不回去修改fsimage,这些都是为了提升速度。如果在修改元数据之后去修改数据节点失败,将会重新操作,反正元数据都已经有了。
8、如果是读请求的话,直接查询内存中元数据,并不会涉及到其中的edit文件和fsimage文件
9、之前提到满足指定条件会触发edit滚动,从而合并fsimage和edit文件,指定条件是什么?
- 空间:edits文件占用空间达到64M时会粗发滚动(文件大小可以通过fs.checkpoint.size 设置)
- 时间:距离上一次更新fsimage的时间已经过去了3600s(可以通过fs.checkpoint.period设置)
- 重启:HDFS和namenode重启会导致日志滚动
- 强制:hadoop dfsadmin -rollEdits
10、Namenode是通过什么来知道DataNode还存活的?
心跳机制,DN会定期给NN发送心跳信息,NN收到了DN发来的心跳信息就知道DN还是存活的了。
11、DN定时(默认3s,这个值可以通过dfs.heartbeat.interval来修改)给NN发送心跳信息。
12、心跳机制是通过RPC实现的,dn去调用heartbeat方法
13、如果NN操作10min没有收到来自dn的心跳信息时,NN就认为这个DN丢失了(lost,不一定是宕机了,也许是网络问题),那么NN会将这个节点上面的副本在备份到其他的节点上面去
14、DN发送给NN的心跳信息包括哪些信息?
- clusterid:dn给nn发的心跳中包括集群id。当HDFS搭建好之后,对NameNode进行格式化(hadoop namenode -format),格式化的时候自动计算产生一个clusterid。并且每次格式化都会重新计算要给clusterid;HDFS集群启动以后,nn会把这个clusterid发给dd,告诉dn它属于哪一个集群。nn在收到dn发过来的心跳的时候也会先检查这个clusterid是不是本集群id,防止误接收。
- 当前的节点状态(dn节点是有状态的,包括服役,退役,预服役和预退役),在不同的状态之下,nn都会采取不同的措施进行管理。
- 返回给nn当前的dn上的blockid信息
15、安全模式:当NameNode重新启动的时候,NameNode自动触发edits_inprogress的滚动和fsimage文件的更新。当fsimage文件更新完成之后,NameNode会将fsimage文件中的内容读取出来加载到内存中。这个时候等待datanode发过来的心跳信息。心跳之后,对这个心跳信息进行校验(校验Block的数量,校验Block的大小等,看一下和元数据记录的是不是一致的,比如我记录了5个blockid,你只返回给我4个id,那就是有问题的,说明在nn宕机期间数据被修改过),如果校验失败,则尝试恢复数据,恢复完成之后再次试图校验,这个过程称之为安全模式。校验成功以后会自动退出安全模式。
16、安全模式下,集群只对外提供查询读服务,不提供写服务。
17、在Hadoop重启的时候,自动进入安全模式。如果进入安全模式,所需要做的事儿就是等待。如果在合理的时间内没有退出安全模式,则说明数据产生了不可恢复的丢失==(有人为改动,数据已经永久丢失无法恢复)==,可以强制退出安全模式:hadoop dfsadmin -safemode leave
18、如果开启了机架感知,那么在伪分布式环境下,副本数必须是1,因为只有一个节点,配置多个副本数的话是无法满足机架感知策略的。
副本放置策略
1、第一个副本
如果实在集群内上传的话,谁上传,第一个副本就放在谁的身上
如果是在集群外上传的话,会选择一个比较空闲的节点来进行存放(block少的)
2、第二个副本
- Hadoop2.7之前:第二个副本是放在和第一个副本不同机架的节点上
- Hadoop2.7开始:第二个副本是放在和第一个副本相同机架的节点上
3、 第三个副本:
- Hadoop2.7之前:第三个副本是放在和第二个副本相同机架的节点上
- Hadoop2.7开始:第三个副本是放在和第二个副本不同机架的节点上
4、更多副本:选择相对空闲的节点放入
机架感知策略
1、HDFS中所谓的机架指的并不是物理机架而是逻辑机架,这个逻辑机架本质上就是一个映射
2、在实际过程中,可以通过Shell/Python脚本来指定机架;实际上就是指定一个Map,在这个Map中,键是节点的主机名或者IP,值表示机架
3、可以将不同物理机架上的节点配置在同一个逻辑机架上,但是实际过程中为了方便管理,往往是将同一个物理机架上的节点配置在相同的逻辑机架上
默认情况下,机架感知是关闭的。在hadoop-site.xml文件中配置参数可以开启机架感知
<property>
<name>topology.script.file.name</name>
<value>/path/to/RackAware.py</value>
</property
参数的值指向一个脚本文件,脚本文件中配置的是一个Map,脚本信息如下:
#!/usr/bin/python
#-*-coding:UTF-8 -*-
import sys
rack = {"hadoopnode-176.tj":"rack1",
"hadoopnode-178.tj":"rack1",
"hadoopnode-179.tj":"rack1",
"hadoopnode-180.tj":"rack1",
"hadoopnode-186.tj":"rack2",
"hadoopnode-187.tj":"rack2",
"hadoopnode-188.tj":"rack2",
"hadoopnode-190.tj":"rack2",
"192.168.1.15":"rack1",
"192.168.1.17":"rack1",
"192.168.1.18":"rack1",
"192.168.1.19":"rack1",
"192.168.1.25":"rack2",
"192.168.1.26":"rack2",
"192.168.1.27":"rack2",
"192.168.1.29":"rack2",
}
if __name__=="__main__":
print "/" + rack.get(sys.argv[1],"rack0")
如果namenode启动成功,会输出下列信息
2011-12-21 14:28:44,495 INFO org.apache.hadoop.net.NetworkTopology: Adding a new node: /rack1/192.168.1.15:50010
机架感知执行逻辑
Namenode启动时,会判断该配置选项是否为空,如果非空,则表示已经用机架感知的配置,此时namenode会根据配置寻找该脚本,并在接收到每一个datanode的heartbeat时,将该datanode的ip地址作为参数传给该脚本运行,并将得到的输出作为该datanode所属的机架,保存到内存的一个map中。
SecondlaryNameNode
1、SecondaryNameNode不是NameNode的备份,仅仅是辅助NameNode进行edits_inprogress文件的滚动和fsimage文件的更新
2、如果存在SecondaryNameNode,那么edits_inprogress文件的滚动过程是发生在SecondaryNameNode;如果没有SecondaryNameNode,那么edits_inprogress文件的滚动就发生在NameNode中
3、到目前为止,HDFS的完全分布式只支持:1个NameNode+1个SecondaryNameNode+多个DataNode结构【1+1+n】或者是双NameNode+多个DataNode结构(2+N,HA结构)。因为在HDFS集群中,NameNode是一个核心节点,如果NameNode只有一个,容易出现单点故障(避免单点故障),所以NameNode必须存在一个备份节点(NameNode做到高可用),实际过程通常考虑使用的双NameNode+多个DataNode结构。
dataNode
1、DataNode的职责是用于存储Block
2、存储Block的位置由hadoop.tmp.dir属性来决定
3、DataNode会定时向NameNode发送心跳信息
4、DataNode的节点状态:预服役、服役、预退役、退役
block存储位置:
/home/software/hadoop-2.7.1/tmp/dfs/data/current/BP-847087703-127.0.0.1-1583885089512/current/finalized/subdir0/subdir0
同一个block存储了两个文件,分别是:
blk_1073741825 blk_1073741825_1001.meta(meta文件是对block文件进行校验的一个文件)
查看DataNode的节点状态
DataNode节点提供的web访问页面:
http://10.42.149.244:50075/
SNN提供的web页面
http://10.42.149.244:50090/
回收站机制
1、在HDFS中,回收站机制默认是不开启的,也就意味着删除文件的命令立即生效不可撤销
2、开启回收站,需要在core-site.xml中添加配置:
<!-- 单位是min,表示放入回收站的内容会在1440min之后删除 -->
<property>
<name>fs.trash.interval</name>
<value>1440</value>
</property>
删除后的文件在哪里?可以通过hadoop fs -lsr /查看
/user/root/.Trash/Current
如何恢复被删除的数据
hadoop fs -mv /user/root/.Trash/Current/park/2.txt /park/
DFS目录
1、dfs目录是在执行过格式化之后才会出现
2、启动hadoop集群后,dfs除了name目录外,还会新增两个新的目录,分别是data和namesecondary
- name:NameNode的存储位置
- data:DataNode的存储位置
- namesecondary:SecondaryNameNode的存储位置
3、在上面的3个文件夹中进入一层,都有一个in_use.lock文件,这个文件只是用来标识,标识单签节点的对应进程已经启动,防止重复启动。
4、在HDFS中,将每一次写操作看成一个事务【不是数据库的按个事务,hadoop不提供事务】,为每一个事务分配一个递增的事务id,简称txid。
5、刚刚格式化完的name目录里面没有edits文件,启动hdfs后,会生成一个edit_inprogress文件,并且在HDFS第一次启动的时候,启动1min以后会自动进行一次日志滚动以及fsimage更新。之后就是按照指定的时间间隔进行滚动。
6、在edits中,开始写一个edits以及结束写一个edits都看成是一个写操作,都会分配一个事务ID,所以每一个edits文件的开头都是OP_START_LOG_SEGMENT,每一个edits文件的结尾都是OP_END_LOG_SEGMENT ,所以这就是为什么,在启动的1min以内我们什么也没有干,但是生成的第一个edits文件记录的事务号是1到2两个事务;然后下一个事务变成了3;而且当我们上传一个文件的时候,会产生6个事务,如果在发生滚动的话,一共会产生8个事务,从3到10;
查看edits日志文件的内容:
hdfs oev -i edits_00000003-0000010 -o edits.xml
7、上传一个文件可以拆分成几个事务
- 开头和结尾是OP_START_LOG_SEGMENT以及OP_END_LOG_SEGMENT
- OP_ADD:在元数据中添加一个文件名.COPYING
并且overwrite是true,说明此时文件是可以修改的
- OP_ALLOCATE_BLOCK_ID:分配BlockID ,给上传的block给一个id
- OP_SET_GENSTAMP_V2:分配时间戳编号
- OP_ADD_BLOCK:向Block中写入数据
- OP_CLOSE:写完数据关流
此时,overwrite变为false,说明文件上传完之后就不能改了 - OP_RENAME_OLD:重命名 ,把之前的那个_COPYING_去掉
8、文件上传完毕之后就不允许修改了
9、fsimage_XXX.md5对fsimag_XXX进行校验。产生fsiamge文件的时候,自动计算产生一个md5文件。如果手动更改了fsimage文件中的内容,在加载时候校验就不通过
10、Seen_txid 记录当前的事务id
11、VERSION文件中的重要内容:
- clusterID:集群编号
- storageType:节点类型 ,分namenode,datanode等
- blockpoolID:块池编号
块池编号一般和联邦有关系。
当前的HDFS可以采取的结构:
1个NN,1个SNN,多个DN
2个NN,多个DN
但不管采取哪种方式,都只有1个NameNode对集群进行管理。另外一个负责暂时备份。
所以这个NameNode就为成为瓶颈。
可以利用多个NN实现对集群的管理,每一个NN值负责管理其中的一部分元数据。而怎么判断我这几个nn是一起的呢?所以规定,HDFS 联邦中,要求所有的子NameNode的块池ID需要一致。