技术细节
1.HDFS在存储数据的时候会将数据进行切换。
2.HDFS中两类主要节点:NameNode和DataNode。
3.在HDFS中,会对每一个块进行备份,这些备份称之为副本(replication)。默认的副本数量为3。
Block
1.表示数据块,HDFS中数据存储的基本形式也是Block。
2.每Hadoop2.X中,每一个Block默认是128M。可以通过dfs.blocksize调节Block的大小,单位默认是字节。
3.如果一个文件本身不到一个Block的大小,那么这个文件会作为一个Block进行存储,在存储的时候,这个文件本身是多大那么就占用多大的空间。例如一个文件只有10M,那么这个文件对应的Block也就只有10M。
4.切块的意义:
a.切块是为了能够存储一些超大文件。
b.为了快速进行备份保证副本数量。
5.在切块的时候,并不是不同的块就一定放在不同的节点上。
6.HDF会对每一个块分配一个递增的编号。-BlockID。
NameNode
1.NameNode在HDFS中负责管理DataNode以及存储元数据(metadata)
2.元数据-是对上传的文件的描述信息:
a.文件的存储路径
b.文件的权限
c.记录文件大小以及Block的大小
d.Block和DataNode的映射关系
e.记录每一个文件的副本的数量
3.元数据在NameNode中存储在内存以及磁盘中
4.元数据存储在内存中的目的:快速操作
5.元数据在磁盘中的目的:崩溃恢复。
6.元数据在磁盘中的存储位置由hadoop.tmp.dir属性来决定
7.元数据在磁盘上的存储和fsimage和edits文件有关
edits文件记录的是HDFS的写操作
fsimage文件记录的是元数据-fsimage中的元数据和内存中的元数据不是实时的。-fsimage中的元数据往往会落后于内存中的元数据。
8.当NameNode接收到写操作的时候,先将写操作记录到edits_inprogress,如果记录成功,则将该操作更新到内存中修改内存中的元数据。更新完内存之后就会给客户端返回一个元数据修改成功的信号。
9.fsimage在更新的时候,会先将edits_inprogress滚动成edis_XXXX-XXXX,然后再将滚动出来的edits文件中的数据转化成命令执行到fsimage中。生成一个新的edits_inprogress。
10.fsimage的更新条件:
a.时间角度:当距离上一次的更新过去了指定的时间(默认是3600s,即1h)之后,就会将edits中的操作更新到fsimage中。这个时间可以通过fs.chechpoint.period进行配置。
b.空间角度:当edits文件到达指定大小(默认是64m)之后,也会触发更新。这个大小可以在fs.checkpoint.size。
c.强行更新:hadoop dfsadmin -rollEdits
d.重启更新:当NameNode重新启动的时候,也会触发更新。
11.NameNode负责管理DataNode。通过心跳机制来管理DataNode-DataNode会定时向NameNode发送心跳信息。
12.DataNode每隔3秒(可以通过dfs.heartbeat.interval配置)向NameNode发送一次心跳信息。实际开发中会将这个时间调大一点。
13.NameNode如果在指定时间(默认是10分钟)内没有收到DataNode的心跳,那么NameNode就会认为这个DataNode已经lost。那么NameNode就会将这个DataNode上的数据就会在其他DataNode上来备份一次保证整个集群中的副本数量。
14.DataNode通过RPC请求发送信息
15.心跳信息主要包含:
a.当前DataNode的状态-(服役,预服役,预退役,退役)(HDFS的黑名单(预退役)和白名单(预服役)机制)
b.当前DataNode中的Block信息--就是BlockID组成的队列
16.当HDFS集群重启的时候。NameNode先将edits中的操作更新到fsimage中,将fsimage中的元数据加载到内存中。等待DateNode的心跳,如果这个过程中有的DataNode的心跳没有收到,需要进行备份;如果收到了DataNode的心跳,校验这个DataNode上的Block信息。同时NameNode保证整个集群中的副本数量。这个过程称之为安全模式(safe mode)。如果所有的校验都通过,NameNode会自动退出安全模式。如果校验失败,那么NameNode会试图恢复数据并且重新校验。
17.如果在不合理的时间内,HDFS一直没有退出安全模式,那就说明数据产生丢失。强行退出安全模式:hadoop dfsadmin -safemode leave
18.也正是因为安全模式的存在,所以如果是伪分布式模式,副本只能配置1个,因为如果副本数量>1,会导致HDFS一致处于安全模式而不能退出。
19.在Hadoop2.0的伪分布式中只允许存在一个NameNode,但是在Hadoop2.0的完全分布式中默认也只有1个NameNode。而实际开发中,允许完全分布式中存在2个NameNode形成NameNode的HA(high availiable)。
20.NameNode是HDFS中的效率瓶颈-(联邦HDFS)
副本放置策略
1.第一个副本:如果第一个副本是从集群内部上传,那么哪个DataNode上传就将数据放在哪个DataNode上。如果第一个副本是从集群外部上传,那么NameNode就会选取相对空闲的节点存储。
2.第二个副本:在Hadoop2.7之前,第二个副本是放在和第一个副本不同机架的节点上。从2.7开始,第二个副本是放在和第一个副本相同机架的节点上
3.第三个副本:在Hadoop2.7之前,第三个副本会放在和第二个副本相同机架的节点上,从2.7开始,第三个副本是放在和第二个副本不同机架的节点上。
4.更多副本:散落在相对空闲的节点上。
机架感知策略
所谓的机架本质上是一个映射-逻辑机架-将主机名或者是IP映射到指定的机架上。
可以将不同物理机架上节点映射到同一个逻辑机架上。
实际开发中,往往是将同一个或者几个物理机架上的节点映射到同一个逻辑机架上。
DataNode
负责存储数据,并且数据是以Block形式存储。
DataNode将Block存储在dfs/data/...下
DataNode会定时向NameNode发送心跳。
SecondaryNameNode
并不是NameNode的备份(只能起到一况分的备份,不能实现热备)辅助NameNode进行edits文件和fsimage文件的合并更新。
实际开发中,如果没有设置SecondaryNameNode,更新只能NameNode自己更新。
实际开发中,一般不设置SecondaryNameNode。而是设置两个NameNode(顶替SecondaryNamenode的位置)。
回收站机制
在HDFS中,回收站默认是不开启的。
需要配置core-site.xml中fs.trash.interval属性,默认时间单位是min。
vim core-site.xml
<!--默认单位是min,表示被删除的文件在回收站中存活1天,1天之内如果没有还原,则删除-->
<property>
<name>fs.trash.interval</name>
<value>1440</value>
</property>
dfs目录
由hadoop.tmp.dir属性来决定存储位置
dfs目录中包含:
data,name,namesecondary。注意,在分布式环境下,这三个目录应该是不在一个节点上。
dfs目录在NameNode被格式化的时候出现。
当NameNode启动之后,这个name目录 下就出现一个in_use.lock文件,这个文件标记当前节点已经启动NameNode,作用是为了防止这个节点二次启动NameNode。
在HDFS中,会对每一次写操作来分配一个编号,这个编号称之为事务id-txid。
在HDFS中,第一次启动之后,1min之后自动进行一次edits和fsimage的更新。
每一个edits文件的开头都是OP_START_LOG_SEGMENT,结尾都是OP_END_SEGMENT(转换文件:hdfs ove -i inputfile -o outputfile)
上传操作在edits中拆解:
添加:OP_ADD
分配块ID:OP_ALLOCATE_BLOCK_ID
给产生的时间戳分配一个编号:OP_SET_GENSTAME_V2
向块中添加数据:OP_ADD_BLOCK
关流:OP_CLOSE
重命名:OP_RENAME_OLD
文件上传之后不能修改。
每一个fsimage文件个.md5文件是为了防止人为对fsimage文件进行校验防止文件被改动。
VERSION文件
clusterID:集群编号。在NameNode被格式化的时候,会自动计算产生一个clusterID,并且在HDFS启动之后,会将clusterID发送给每一个DataNode.DataNode的每一次心跳都需要拾这个clusterID,NameNode在收到DataNode的信息之后会先校验clusterID是否一致。NameNode每次格式化都会重新计算一个clusterID,但是DataNode只接收一次
storageType:节点类型
blockpoolID:块池ID(块池在联邦HDFS中使用)
流程
读流程(下载)
1.客户端发起RPC请求到NameNode
2.NameNode在收到请求之后,会进行校验,例 如文件是否存在等。
3.校验成功后,将这个文件所对应的Block的存储节点放入一个队列中,返回给客户端。
4.客户端收到队列之后,从队列中取出第一个块对应的地址,从这些地址中来选取一个较近(网络拓扑)的节点地址来连接来读取节点。
5.读取完一个Block之后,校验Block(每一个Block都对应了一个.meta),如果校验失败 ,则DataNode就会认为这个Block产生损坏。客户端会通知NameNode,然后DataNode会重新选取地址重新读取:读取完之后继续读取下一个Block。
6.如果客户端读完这一批的地址,向NameNode要下一批的地址。
7.全部读取完成之后,客户端就会支通知NameNode关闭文件(关流)。
写流程(上传)
1.客户端发起RPC请求到NameNode
2.NameNode收到请求之后,进行校验,例如:a.校验是否有权限操作对应路径,b.校验指定路径下是否有同名文件
3.如果校验成功,则NameNode会在元数据中先记录一个_COPYING文件,然后记录成功过之后会给客户端一个响应,这个响应中应该包含BlockSize
4.客户端会在收到响应之后,计算文件的切块数量,将文件切块。
5.客户端会再给NameNode发送信息要第一个块的存储地址。
6.NameNode收到请求之后,会给Block分配BlockID,等待DataNode的心跳,选择相对空闲的DataNode放入队列中发给客户端。
7.客户端收到队列之后,从中选择一个较近的节点来写入这个块的第一个副本。这个副本所在的DataNode通过pipeline(管道,实际上基于NIO实现的)将副本写入其它的DataNode上保证副本的数量,所有的副本写完之后会给客户端返回一个ACK信号表示所有副本都写完。
8.客户端再写下一个Block。
9.当客户端写完所有的Block之后,通过NameNode关闭文件(关流)。此时文件就不可改动。
10.NameNode将_COPYING重命名。
删流程
1.客户端发起RPC请求到NameNode
2.NameNode收到请求之后,先将这个删除操作记录到edits文件中,然后就更新内存,给客户端返回一个ack信号表示删除成功。(此时这个文件依然存储在HDFS上)
3.DataNode给NameNode发送心跳的时候,NameNode就会发现DataNode上出现了元数据中未存储的数据。NameNode会认为这个数据是被删除的数据,那么就会给DataNode一个心跳响应,命令DataNode删除掉对应的数据。DataNode在收到响应之后才会删除掉对应的Block。
高并发:并发和线程量有关。
高吞吐:吞吐和数据量有关。
一般而言,高吞吐一般是高并发的,高并发不一定是高吞吐的。
特点
1.能够存储超大文件-切块
2.能够快速应对和检测故障-心跳
3.简化的一致性模型-一次写入多次读取。从Hadoop2.0开始,HDFS允许追加写入。
4.能够在廉价的机器上进行搭建和横向扩展。
5.做不到低延迟的响应。
6.不建议存储大量的小文件。
7.不支持事务。