1. HDFS NameNode
**作用是接受客户端的读写服务,在内存中保存文件元数据信息**
NameNode在内存中保存的metadata包括:
(1)文件所属ownership和权限permission,文件名等
(2)文件包含哪些块block
(3)每个块保存在哪个DataNode上(在集群启动时由DataNode上报)
metadata不仅在内存中有,还会将上面前两点保存在磁盘上,文件名为fsimage。为了可用性考虑在磁盘上备份元数据,一般在nfs上,如果元数据完全丢失了,整个集群的数据等于报废。
而block位置信息不会保存,若关机则丢失。NameNode在启动时将fsimage加载到内存中。
磁盘中还会保存edits文件,用于记录对metadata的操作,即记录文件增删操作。不是立即对fsimage操作,而是在特定时刻由secondry NameNode帮助合并fsimage和edits,生产新的fsimage。
大概100w文件会占用1GB内存
2. Secondary NameNode
**不是NameNode的备份(但可以做备份),主要工作是帮助NameNode定期合并edits,减少NameNode的启动时间和CPU、io压力**
Secondary NameNode可以视为NameNode的元数据冷备,建议Secondary NameNode放在不同于NameNode的机器上
合并时机根据两个配置参数决定
设置的时间间隔fs.checkpoint.period,默认3600s
设置的edits最大体积 fs.checkpoint.size,默认64MB
3. DataNode
**存储数据,默认副本3个,Hadoop2.6.4版本之后默认块大小128MB**
集群启动时DataNode会向NameNode汇报block信息。
以块列表的形式存储块位置信息。
每3s向NameNode发送心跳包,如果NameNode 10min没有收到心跳包,则会认为该DataNode lost了。NameNode会寻找其他相对空闲的DataNode拷贝缺失副本。
一个block里面只可能有一个文件,即使该文件不到128MB,在逻辑上依然占用一个块,但是在磁盘上占用实际大小,不会填充到128MB。
HDFS中的块设置的这么大是为了最小化寻址开销,将磁盘传输数据的时间作为首要时延。
4. HDFS读过程
客户端请求NameNode获取文件的获取文件起始块的位置。对于每一个块,namenode返回存储该块的所有datanode地址,并按距离客户端远近排序。通过对数据流反复调用read方法,可以将数据传输到客户端。到达块的末端时,寻找下一个最合适的DataNode传输。
客户端还会验证从DataNode传送过来的数据校验和。如果发现一个损坏的块,那么客户端将会再尝试从别的DataNode读取数据块,向NameNode报告这个信息,NameNode也会更新保存的文件信息。
由客户端并发读取DataNode,这种设计的好处是,可以使HDFS扩展到更大规模的客户端并行处理,这是因为数据的流动是在所有DataNode之间分散进行的。同时NameNode的压力也变小了,使得NameNode只用提供请求块所在的位置信息就行。
5. HDFS写过程
客户端请求NameNode新建文件,namenode在命名空间中确保该文件不存在并且该用户有在路径下写文件的权限。namenode会切分文件并挑选一系列最适合存储的DataNode,这一组DataNode构成一个管线。客户端将数据包传给第一个DataNode,第一个DataNode传给带二个DataNode,以此类推。然后反向传输确认回执,直到管线中所有DataNode都确认成功写入,才会回复成功代码。
客户端仅仅只写一个副本,DataNode自行复制其他副本。这样的优点是快。
6. HDFS安全模式
NameNode启动的时候,会进入安全模式,此时hdfs对外部客户端是只读的。
安全模式期间,NameNode将磁盘上的edits和fsimage加载到内存,执行edits上的各种操作,完成后将生成最新的fsimage文件和一个空edits。
同时,NameNode会收集DataNode的块信息汇报,一个block达到了最小副本数以上时,会被认为是安全的。当一定比例的数据块(可设置)是安全的,结束安全模式。当检测到某些块不足最小副本数,会自行复制。
7. HDFS HA(High Avaliable)
Hadoop2.0比1.0的改进:
(1)解决NameNode单点故障问题。HA,如果主NameNode出现问题,切换到备用NN
(2)引入YARN
(3)使HDFS支持MapReduce之外的计算引擎
(4)解决内存受限问题。联邦HDFS,每个NameNode分管不同namespace,多NameNode合作,相互之间独立,共享所有DataNode。现在可OZONE替代hdfs。
Hadoop2.0 HA架构角色
(1)主、备NameNode。同一时间只有一个主NameNode,可以有多个备NameNode。主备NameNode服务起在不同机器上。
(2)DataNode。同一时间向所有主备NameNode汇报block信息,但只接受主NameNode的命令。
(3)Journal node。主NameNode在Journal node集群上实时维护edits和fsimage,每一次编辑必须写入多数Journal node。主备切换时备用NameNode从Journal node读取文件,恢复元数据。同一时间QJN仅允许一个Namenode写入日志。
(4)Failover controller。负责主备NameNode切换,对活跃NameNode进行心跳检查,确定是否真的失效了,也有active/standby之分,一个Failover controller对应一个NameNode。
(5)Zookeeper。选举活跃NameNode。active NameNode挂了之后,Failover controller向zookeeper竞争锁,竞争方法是投票,胜选NameNode当选为active。必须为奇数个。
(6)client。请求zookeeper获取主NameNode地址。
8. NameNode的目录结构
${dfs.namenode.name.dir}/
——————current
—————————————VERSION
—————————————edits_0000000000000000000001-00000000000000000000019
—————————————edits_inprogress_0000000000000000000020
—————————————fsimage_000000000000000000000
—————————————fsimage_000000000000000000000.md5
—————————————fsimage_000000000000000000019
—————————————fsimage_000000000000000000019.md5
—————————————seen_tx1d
———————in_use.lock
VERSION是一个Java属性文件,包含正在运行的hdfs版本信息。如果HDFS持久性数据结构变更,HDFS则需要升级,否则HDFS无法正常工作。
in_use.lock是一个锁文件,namenode使用该文件为存储目录加锁,避免其他namenode实例同时使用。
edits是编辑日志。文件系统客户端执行写操作时,会被记录到编辑日志中。namenode在内存中维护文系统的元数据,当编辑日志被修改时,内存中的元数据信息也被同步更新。edits在逻辑上是单个文件,但在磁盘上体现为多个文件,每个文件是一个segment。任意时刻只有一个文件处于可写状态,即是名字中带inprogress的那个。每个事务完成后,在向客户端发送成功代码前,都要更新edits文件。当namenode向多个目录写数据时,只有所有写操作成功并更新到edits中时才会返回成功。
fsimage是文件系统映像。每个fsimage是文件系统元数据的一个完整的永久检查点。因为fsimage是一个大型文件,不会频繁更新,只是在和edits合并时更新。合并操作由secondary namenode完成,因此secondary namenode也需要大内存。
9. DataNode目录结构
DataNode的存储目录是在初始阶段自动创建的,不需要额外格式化。
${dfs.datanode.data.dir}/
———current
————BP-526805057-127.0.0.1-1411808
—————————current
—————————VERSION
—————————finalized
—————————————blk_1073741825
—————————————blk_1073741825.meta
—————————————blk_1073741826
—————————————blk_1073741826.meta
——————————rbw
————VERSION
———in_use.lock
HDFS数据块存储在以blk为前缀的文件中,文件名包含了该文件块的原始字节数。每个块有一个相关联的带.meta后缀的元数据文件,元数据文件包括版本信息、类型信息和该数据块的校验和。
10. HDFS的数据完整性
HDFS会对写入的所有数据计算校验和,并在读取数据时验证校验和。HDFS使用的是CRC-32C计算校验和,只占4个字节,存储校验和的额外开销小于1%。
写文件时,客户端计算校验和,并随数据文件一起发送给DataNode管线,管线中的最后一个DataNode负责验证校验和。如果校验到错误,客户端会收到一个IOException异常。
读文件时,客户端会验证DataNode发来的block校验和,如果成功验证,会将结果告知该DataNode。每个DataNode均持久保存一个校验和日志,收到客户端的成功反馈,DataNode就会更新日志中的最新校验时间。
客户端在读取数据库时若检测到错误,首先向namenode报告已损坏的数据块和相应的DataNode,namenode随即将该DataNode的数据块复本标记为已损坏,这个DataNode将不再接受读取损坏数据块的请求。之后,namenode会将损坏数据块的一个复本复制到另一个datanode上,恢复复本因子。此后,择时删除损坏数据块。
11. HDFS序列化
序列化(serialization)是指将结构化对象转化为二进制字节流以便在网络上传输或写到磁盘中进行永久存储的过程。反序列化(deserialization)则是将字节流恢复成对象的逆过程。
序列化用于分布式数据处理的两个方面:进程间通信和磁盘永久存储。在Hadoop中,集群中多节点上的进程间通信使用RPC协议。RPC协议将消息序列化成二进制流后发送到远程节点,远程节点将二进制流反序列化为初始消息。Hadoop使用的是自定义的序列化格式writable,存放于org.apache.hadoop.io包中。大部分writable类都是对应Java类型的扩展,如int对应intwritable,double对应doublewritable,text对应string。