设计思路
-
- 分而治之:分块存储
- 冗余备份:副本
优点
-
- 可构建在廉价机器上:横向扩展
- 高容错性:多个副本
- 适合批处理:计算移动而非数据移动
- 流式访问:一次写入多次读取,不允许修改只能追加,保证数据一致性
核心设计
-
心跳机制(heartbeat)
- master启动时会启动一个IPC服务,等待slave的连接
- slave启动时会主动连接master的IPC服务,并且默认每隔3秒连接一次master,这种机制形象的被称为心跳
- slave通过心跳向master汇报信息,master通过心跳监控slave并发送指令
- NameNode 通过心跳得知 Datanode 的状态 ,ResourceManager 通过心跳得知 NodeManager 的状态
- 当master在连续的一定时间(默认630秒)未接受到slave的汇报则认为改节点已挂掉
<property>
property><name>heartbeat.recheck.interval</name>
<name>heartbeat.recheck.interval</name><value>5000</value>
<value>5000</value></property>
property><property>
property><name>dfs.heartbeat.interval</name>
<name>dfs.heartbeat.interval</name><value>3</value>
<value>3</value></property>
property>
-
副本存放策略
- 将文件分块存储,每一个数据块保存多个副本并分布于不同节点
- 默认3个副本
- 第一个副本放于和client相同的节点
- 第二个副本放于和第一个副本不同机架的节点
- 第三个副本放于和第二个副本相同机架的不同节点
//修改副本数
<property>
property><name>dfs.replication</name>
<name>dfs.replication</name><value>1</value>
<value>1</value></property>
property>
-
负载均衡
- Hadoop的HDFS集群非常容易出现机器与机器之间磁盘利用率不均衡的情况
- 例如:当集群内新增、删除节点,或者某个节点机器内硬盘存储达到饱和值都会导致负载不均衡
- 进行数据的负载均衡调整,必须要满足如下原则:
- 数据平衡不能导致数据块减少,数据块备份丢失
- 管理员可以中止数据平衡进程
- 每次移动的数据量以及占用的网络资源,必须是可控的
- 数据均衡过程,不能影响namenode的正常工作
- 数据负载均衡的原理
- 数据均衡服务(Rebalancing Server)首先要求 NameNode 生成 DataNode 数据分布分析报告,获取每个DataNode磁盘使用情况
- Rebalancing Server汇总需要移动的数据分布情况,计算具体数据块迁移路线图,确保网络内最短路径
- 开始数据块迁移任务,Proxy Source Data Node复制一块需要移动数据块
-
将复制的数据块复制到目标DataNode上
- 删除原始数据块
- 目标DataNode向Proxy Source Data Node确认该数据块迁移完成
- Proxy Source Data Node向Rebalancing Server确认本次数据块迁移完成。然后继续执行这个过程,直至集群达到数据均衡标准
- 调节数据负载均衡
- 命令(默认阈值10%)
- bin/start-balancer.sh –threshold 5
- 但HDFS默认受带宽限制(默认1M/s),均衡数据移动很慢,配置修改带宽
<property>
property><name>dfs.balance.bandwidthPerSec</name>
name>dfs.balance.bandwidthPerSec</name><value>10485760</value>
value>10485760</value>
- 命令(默认阈值10%)
- Hadoop的HDFS集群非常容易出现机器与机器之间磁盘利用率不均衡的情况
-
安全模式
- namenode的三种状态:Active/Standby/safemode
- 进入安全模式的情景
- namenode刚启动,从 fsimage 中加载元数据时,DataNode向namenode发送位置信息。当数据恢复到阈值时自动退出安全模式
- 数据丢失率达到一定比例(默认0.1%)
- 在启动一个刚刚格式化的HDFS时系统不会进入安全模式,因为没有数据块
NameNode的工作机制
-
作用
- 负责client的请求的响应
- 维护目录树结构(元数据的管理):比如命名空间信息,块信息等
-
元数据管理(内存中和磁盘中各有一份完整的元数据)
- WAL(write chead log):预写日志系统,在使用WAL的系统中,所有修改在提交前先写入log文件
- 元数据文件
- fsimage镜像文件,是元数据的一个持久化的检查点,包含hdfs文件系统的所有目录和元数据信息,但不包含文件块的位置信息,文件块的位置信息只存储在内存中间断的更新
- ediets文件,存放的是hdfs文件系统中所有的更改操作
- 元数据的存储机制
- 内存中有一份完整的元数据(内存 metadata)
- 磁盘有一个“准完整”的元数据镜像(fsimage)文件(在 namenode 的工作目录中)
- 用于衔接内存 metadata 和持久化元数据镜像 fsimage 之间的操作日志(edits 文件)
- 当客户端对 hdfs 中的文件进行新增或者修改操作,操作记录首先被记入 edits 日志 文件中,当客户端操作成功后,相应的元数据会更新到内存 metadata 中
- 元数据的checkpoint
- 每隔一段时间会有secondarynamenode将namenode上积累的edits文件和一个最新的fsimage下载到本地,并加载到内存进行合并,这个过程称为cheakpoint
- 具体流程
- client对文件的操作设计到元数据的更新,就会写到edits日志中
- 随着元数据的操作记录日志增多,secondary NameNode 也会定期的去请求NameNode是否需要checkpoint
- 如果得到应答,namenode停止使用当前edits文件,将操作记录到一个新的edits文件中。
- secondary namenode 从namenode获取edits文件,下载到本地。并将fsimage文件和edits文件一并加载到内存中
- secondary namenode将fsimage和获取的edits文件逐一合并生成一个新的fsimage文件,并将新的fsimage文件发送给namenode
- nomenode接收到该fsimage文件后替换掉旧的fsimage文件,并更新fsimage文件中记录检查点的执行时间
//#检查触发条件是否满足的频率,60 秒
dfs.namenode.checkpoint.check.period=60
.namenode.checkpoint.check.period=60//最大重试次数
dfs.namenode.checkpoint.max-retries=3
.namenode.checkpoint.max-retries=3//触发条件
//两次 checkpoint 之间的时间间隔 3600 秒
dfs.namenode.checkpoint.period=3600
.namenode.checkpoint.period=3600//两次 checkpoint 之间最大的操作记录数
dfs.namenode.checkpoint.txns=1000000
.namenode.checkpoint.txns=1000000
DataNode
-
作用
- 存储管理真实的文件块
- 定期通过心跳向namenode汇报block信息
Secandary NameNode
-
作用
- 备份namenode的元数据信息
- 减轻namenode的压力
HDFS读流程
-
- client向namenode发送请求
- namenode返回文件的block列表(拷贝了block地址以数据流的形式一并返回)
- client就近选择datanode读取block
- 读完当前block后,关闭当前DataNode的连接。
- 然后进行checksum验证,如果读取出现错误,client通知namenode,然后从下一个拥有该block的DataNode读取寻找下一个block读取的最佳DataNode
- 如此往复直到文件读取结束
- 释放资源
HDFS的写流程
-
- client向远程的namenode发送RPC写请求
- namenode进行一系列检查,比如检查要创建的文件是否存在,创建者是否有权限等等,若通过检查,会将操作直接写入edits文件,并返回写出流对象
- 客户端将文件切分成多个packets,并在内部以数据队列"data queue"形式管理这些packets,向namenode申请blocks,获取用来存储replicas的合适的DataNode列表
- 开始以pipeline形式将packet写入所有的replicas中,客户端将packet以流的形式写入第一个DataNode,该DataNode把这个packet存储后再传给pipeline中的下一个DataNode,直到最后一个datanode
- 最后一个datanode成功存储后返回一个ack packet确认队列,通过pipeline传递给client,在客户端的开发库内部维护着"ack queue",成功收到datanode返回的ack packet后会以“data queue”移除对应的packet
- 传输过程中,若某个datanode出现故障,那么当前的pipeline会被关闭。出现故障的datanode会从当前的pipeline中移除,然后继续从剩余的block对应的datanode中以pipeline形式传输,同时namenode会分配一个新的datanode保持replicas设定的数量
- 完成数据写入,关闭流
- 只要写入了dfs.replication.min的数量,写操作就算成功了,这个块会在集群中进行异步复制,直到达到目标副本数