hdfs - yaokun123/php-wiki GitHub Wiki

HDFS - Hadoop Distributed File System

  • 运行于通用硬件上的分布式文件系统,高吞吐,高可靠

角色分析

1.1、NameNode(NN) - 管理文件系统的命名空间

1、文件和目录的元数据(运行时,元数据放内存)
 - 文件的block副本个数
 - 修改和访问的时间
 - 访问权限
 - block大小以及组成文件的block信息列表

2、以两种方式在NameNode本地进行持久化
 - 命名空间镜像文件(fsimage)和编辑日志(edits log)

3、fsimage文件不记录每个block所在的DataNode信息,这些信息在每次系统启动的时候从DataNode重建。之后DataNode会周期性地通过心跳包向NameNode报告block信息。DataNode向NameNode注册的时候NameNode请求DataNode发送block列表信息。

4、一个运行的NameNode如下的目录结构,该目录结构在第一次格式化的时候创建
 - 备份数据in_use.lock文件用于NameNode锁定存储目录。这样就防止其他同时运行的NameNode实例使用相同的存储目录。
 - edits表示edits log日志文件
 - fsimage表示文件系统元数据镜像文件
 - NameNode在checkpoint之前首先要切换新的edits log文件,在切换时更新seen_txid的值。上次合并fsimage和editslog之后的第一个操作编号
 - VERSION文件是一个Java的属性文件

1.2、SecondaryNameNode

1、存在意义
 - edits log会随着对文件系统的操作而无限制地增长,这对正在运行的NameNode而言没有任何影响,如果NameNode重启,则需要很长的时间执行edits log的记录以更新fsimage(元数据镜像文件)。在此期间,整个系统不可用。
 - 在系统启动期间,NameNode合并fsimage+edits log
 - 解决方案就是运行SecondaryNameNode,它的作用就是为NameNode内存中的文件系统元数据生成检查点(checkpoint)

2、工作流程
 - secondarynamenode请求namenode生成新的edits log文件并向其中写日志。NameNode会在所有的存储目录中更新seen_txid文件
 - SecondaryNameNode通过HTTP GET的方式从NameNode下载fsimage和edits文件到本地。
 - SecondaryNameNode将fsimage加载到自己的内存,并根据edits log更新内存中的fsimage信息,然后将更新完毕之后的fsimage写到磁盘上
 - SecondaryNameNode通过HTTP PUT将新的fsimage文件发送到NameNode,NameNode将该文件保存为.ckpt的临时文件备用
 - NameNode重命名该临时文件并准备使用。此时NameNode拥有一个新的fsimage文件和一个新的很小的edits log文件

3、检查点创建时机
 - 默认情况下,SecondaryNameNode每个小时进行一次checkpoint合并由dfs.namenode.checkpoint.period设置,单位秒 默认3600s 1小时合并一次
 - 在不足一小时的情况下,如果edits log存储的事务达到了1000000个也进行一次
 - 事务数量检查默认每分钟进行一次,由dfs.namenode.checkpoint.check.period设置,单位秒。

1.3、DataNode

1、HDFS块数据存储于blk_前缀的文件中,包含了被存储文件原始字节数据的一部分
2、每个block文件都有一个.meta后缀的元数据文件关联。该文件包含了一个版本和类型信息的头部,后接该block中每个部分的校验和
3、每个block属于一个block池,每个block池有自己的存储目录,该目录名称就是该池子的ID(跟NameNode的VERSION文件中记录的block池ID一样)
4、

一、存储模型

1、文件线性按字节切割成块(block),分散存储在集群节点中。具有offset,id
2、单一文件Block大小一致,文件与文件可以不一致
3、同一个文件除最后一个block,其他block大小一致
4、block的大小依据硬件的I/O特性调整
5、block被分散存放在集群的节点中,具有location
6、Block具有副本(replication),没有主从概念,副本不能出现在同一个节点
7、副本是满足可靠性和性能的关键
8、文件上传可以指定block大小和副本数,上传后只能修改副本数
9、只支持一次写入多次读取。同一时刻只有一个写入者。对同一个文件,一个时刻只有一个写入者
10、支持追加数据

二、架构设计

1、HDFS是一个主从(Master/Slaves)架构
2、由一个NameNode和一些DataNode组成
3、面向文件包含:文件数据(data)和文件元数据(metadata)
4、NameNode负责存储和管理文件元数据,并维护了一个层次型的文件目录树
5、DataNode负责存储文件数据(block块),并提供block的读写
6、DataNode与NameNode维持心跳,并汇报自己持有的block信息
7、Client和NameNode交互文件元数据和DataNode交互文件block数据

三、角色功能

NameNode
1、完全基于内存存储文件元数据、目录结构、文件block的映射
2、需要持久化方案保证数据可靠性
3、提供副本放置策略

DataNode
1、基于本地磁盘存储block(文件的形式)
2、并保存block的校验和数据保证block的可靠性
3、与NameNode保持心跳,汇报block列表状态

SecondaryNameNode(SNN)
1、在非Ha模式下,SNN一般是独立的节点,周期完成对NN的EditLog向FsImage合并,减少EditLog大小,减少NN启动时间
2、根据配置文件设置的时间间隔fs.checkpoint.period  默认3600秒
3、根据配置文件设置edits log大小 fs.checkpoint.size 规定edits文件的最大值默认是64MB

四、元数据持久化

1、任何对文件系统元数据产生修改的操作,Namenode都会使用一种称为EditLog的事务日志记录下来
2、使用FsImage存储内存所有的元数据状态
3、使用本地磁盘保存EditLog和FsImage
4、EditLog具有完整性,数据丢失少,但恢复速度慢,并有体积膨胀风险
5、FsImage具有恢复速度快,体积与内存数据相当,但不能实时保存,数据丢失多
6、NameNode使用了FsImage+EditLog整合的方案:
        滚动将增量的EditLog更新到FsImage,以保证更近时点的FsImage和更小的EditLog体积

五、安全模式

Namenode存元数据:文件属性 / 每个块存在哪个DN上
属性:path  /a/b/c.txt  32G  root:root  rwxrwxrwx
块位置:	blk01 1 2
	blk02 4 6
在持久化的时候:文件属性会持久化,但是文件的每一个块不会持久化。恢复的时候,NN会丢失块的位置信息。DN 会和 NN 建立心跳,汇报块信息~!!!!

1、HDFS搭建时会格式化,格式化操作会产生一个空的FsImage
2、当Namenode启动时,它从硬盘中读取Editlog和FsImage
3、将所有Editlog中的事务作用在内存中的FsImage上
4、并将这个新版本的FsImage从内存中保存到本地磁盘上
5、然后删除旧的Editlog,因为这个旧的Editlog的事务都已经作用在FsImage上了

1、Namenode启动后会进入一个称为安全模式的特殊状态。
2、处于安全模式的Namenode是不会进行数据块的复制的。
3、Namenode从所有的 Datanode接收心跳信号和块状态报告。
4、每当Namenode检测确认某个数据块的副本数目达到这个最小值,那么该数据块就会被认为是副本安全(safely replicated)的。
5、在一定百分比(这个参数可配置)的数据块被Namenode检测确认是安全之后(加上一个额外的30秒等待时间),Namenode将退出安全模式状态。
6、接下来它会确定还有哪些数据块的副本没有达到指定数目,并将这些数据块复制到其他Datanode上。

六、副本放置策略

1、第一个副本:放置在上传文件的DN;如果是集群外提交,则随机挑选一台磁盘不太满,CPU不太忙的节点。
2、第二个副本:放置在于第一个副本不同的 机架的节点上
3、第三个副本:与第二个副本相同机架的节点
4、更多副本:随机节点

七、读写流程

写流程:
1、Client和NameNode连接创建文件元数据
2、NameNode判定元数据是否有效
3、NameNode触发副本放置策略,返回一个有序的DataNode列表
4、Client和DataNode建立Pipeline连接
5、Client将块切分成packet(64KB),并使用chunk(512B)+chucksum(4B)填充
6、Client将packet放入发送队列dataqueue中,并向第一个DataNode发送
7、第一个DataNode收到packet后本地保存并发送给第二个DataNode
8、第二个DataNode收到packet后本地保存并发送给第三个DataNode
9、这一个过程中,上游节点同时发送下一个packet
10、生活中类比工厂的流水线:结论:流式其实也是变种的并行计算
11、Hdfs使用这种传输方式,副本数对于client是透明的
12、当block传输完成,DataNode们各自向NameNode汇报,同时client继续传输下一个block
13、所以,client的传输和block的汇报也是并行的

读流程:
1、为了降低整体的带宽消耗和读取延时,HDFS会尽量让读取程序读取离它最近的副本。
2、如果在读取程序的同一个机架上有一个副本,那么就读取该副本。
3、如果一个HDFS集群跨越多个数据中心,那么客户端也将首先读本地数据中心的副本。
4、语义:下载一个文件:
    Client和NameNode交互文件元数据获取fileBlockLocation
    NameNode会按距离策略排序返回
    Client尝试下载block并校验数据完整性
5、语义:下载一个文件其实是获取文件的所有的block元数据,那么子集获取某些block应该成立
    Hdfs支持client给出文件的offset自定义连接哪些block的DataNode,自定义获取数据
    这个是支持计算层的分治、并行计算的核心

八、NameNode HA

editlog

1、基本原理就是用2N+1台 JournalNode 存储EditLog,每次写数据操作有>=N+1返回成功时即认为该次写成功,数据不会丢失了。
当然这个算法所能容忍的是最多有N台机器挂掉,如果多于N台挂掉,这个算法就失效了。这个原理是基于Paxos算法

2、在HA架构里面SecondaryNameNode已经不存在了,为了保持standby NN时时的与Active NN的元数据保持一致,
他们之间交互通过JournalNode进行操作同步。

3、任何修改操作在 Active NN上执行时,JournalNode进程同时也会记录修改log到至少半数以上的JN中,
这时 Standby NN 监测到JN 里面的同步log发生变化了会读取 JN 里面的修改log,然后同步到自己的目录镜像树里面

4、当发生故障时,Active的 NN 挂掉后,Standby NN 会在它成为Active NN 前,读取所有的JN里面的修改日志,
这样就能高可靠的保证与挂掉的NN的目录镜像树一致,然后无缝的接替它的职责,维护来自客户端请求,从而达到一个高可用的目的

在HA模式下,datanode需要确保同一时间有且只有一个NN能命令DN。为此:
1、每个NN改变状态的时候,向DN发送自己的状态和一个序列号。

2、DN在运行过程中维护此序列号,当故障切换时,新的NN在返回DN心跳时会返回自己的active状态和一个更大的序列号。
DN接收到这个返回则认为该NN为新的active。

3、如果这时原来的active NN恢复,返回给DN的心跳信息包含active状态和原来的序列号,这时DN就会拒绝这个NN的命令。

Failover Controller

HA模式下,会将FailoverController部署在每个NameNode的节点上,作为一个单独的进程用来监视NN的健康状态。
FailoverController主要包括三个组件:

1、HealthMonitor: 监控NameNode是否处于unavailable或unhealthy状态。当前通过RPC调用NN相应的方法完成。

2、ActiveStandbyElector: 监控NN在ZK中的状态

3、ZKFailoverController: 订阅HealthMonitor 和ActiveStandbyElector 的事件,并管理NN的状态,另外zkfc还负责解决fencing(也就是脑裂问题)
 - 健康监测:周期性的向它监控的NN发送健康探测命令,从而来确定某个NameNode是否处于健康状态,如果机器宕机,心跳失败,那么zkfc就会标记它处于一个不健康的状态
 - 会话管理:如果NN是健康的,zkfc就会在zookeeper中保持一个打开的会话,如果NameNode同时还是Active状态的,那么zkfc还会在Zookeeper中占有一个类型为短暂类型的znode,当这个NN挂掉时,这个znode将会被删除,然后备用的NN将会得到这把锁,升级为主NN,同时标记状态为Active。当宕机的NN新启动时,它会再次注册zookeper,发现已经有znode锁了,便会自动变为Standby状态,如此往复循环,保证高可靠,需要注意,目前仅仅支持最多配置2个NN
 - master选举:通过在zookeeper中维持一个短暂类型的znode,来实现抢占式的锁机制,从而判断那个NameNode为Active状态
1、一个NameNode进程处于Active状态,另1个NameNode进程处于Standby状态。Active的NameNode负责处理客户端的请求
2、Active的NameNode修改了元数据之后,会在JNs的半数以上的节点上记录这个日志。Standby状态的NameNode会监视任何对JNs上edit log的更改。
一旦edits log出现更改,Standby的NN就会根据edits log更改自己记录的元数据
3、当发生故障转移时,Standby主机会确保已经读取了JNs上所有的更改来同步它本身记录的元数据,然后由Standby状态切换为Active状态
4、为了确保在发生故障转移操作时拥有相同的数据块位置信息,DNs向所有NN发送数据块位置信息和心跳数据。
5、JNs只允许一台NameNode向JNs写edits log数据,这样就能保证不会发生“脑裂”
6、ZooKeeper Failover Controller:监控NameNode健康状态,并向Zookeeper注册NameNode。NameNode挂掉后,ZKFC为NameNode竞争锁,获得ZKFC 锁的NameNode变为active