这是我参与「第四届青训营 」笔记创作活动的第8天的笔记。
主要记录 HDFS 的原理,已经一些自己的理解## 1. 简介
HDFS 是一个分布式文件系统。
有一种对 Hadoop 生态体系的理解是「计算 + 存储」,主要分为三层:
- 应用层:Mapreduce、Spark
- 调度层:YARN
- 存储层:HDFS
其中存储层即 HDFS 被认为是整个 Hadoop 生态体系的底座。
比起单机文件系统,分布式文件系统是单机文件系统的延申,概念术语是相同的,比如目录、文件、目录树等。分布式系统有以下几个特点:
- 大容量:更多机器组成,更多存储介质。
- 高可靠:多个数据副本,提高容错能力。比如在多台机器上存储相同的内容,其中某一个挂掉了也不会导致数据丢失
- 低成本:不需要高端硬件来扩容,
HDFS 的功能特性:
- 分布式:多台机器共同维护一个文件系统,但是没有完整的 POSIX 文件系统语义
- 容错:自动处理、规避多种错误
- 高可用:一主多备实现元数据高可用,数据多副本实现用户数据高可用
- 高吞吐:Client 直接从 DataNode 读取用户数据,服务端支持 Client 并发读写
- 高扩展:可以扩展集群中机器数量,可达 10w 数量级以上
- 廉价:只需要通用硬件,不需要像单机堆叠昂贵的硬件
2. 架构原理
2.1 架构组件
HDFS 的组件主要有 3(4)个
-
Client:读写数据的一端
-
NameNode:维护元数据的节点,接受 Client 的读写请求,并响应
- 维护目录树
- 维护文件和数据块的关系
- 维护文件 Block 存放节点信息
- 分配新文件存放节点
-
DataNode:实际存储数据的节点
-
数据块存取
-
心跳汇报
把存放在本地的数据块列表发送给 NameNode,以及让 NameNode 确定节点状态
-
副本复制
-
2.2 读写数据流程
写数据,个人理解可以分为两个阶段:请求写数据阶段,写数据阶段
请求写数据节点,只有简单的两步:
- Client 向 NameNode 发出写数据请求,包括请求上传路径,文件名等
- NameNode 根据请求的目录是否存在,路径是否合法的,响应是否可以上传
sequenceDiagram
Client ->> NameNode: 请求上传文件
NameNode -->> Client: 响应是否可上传
写数据阶段,对于每个文件 Bolck 的流程都是一致的。在写数据之前,Client 会把完整的大文件切分成大小一定的 Block 的,DataNode 维护的不是一个完整的文件,而是一个个的 Block。
sequenceDiagram
Client ->> NameNode: 请求上传一个 Bolck
NameNode -->> Client: 返回Block上传的节点列表[DN1, DN2, DN3]
Client ->> DN1: 上传 Block
DN1 ->> DN2: 上传 Block
DN2 ->> DN3: 上传 Block
DN3 -->> DN2: ACK
DN2 -->> DN1: ACK
DN1 -->> Client: ACK
Client ->> NameNode: 告知上传完成
读数据比较简单,可以用一个阶段概括,简单来说就是向 NameNode 请求读取一个文件,NameNode 返回文件的元数据包括 Block 的位置信息,Client 可以根据这些信息,并发地向 DataNode 请求 Block,最后把 Block 合并成完整的文件
sequenceDiagram
Client ->> NameNode: 请求读取文件
NameNode --> Client: 返回文件的元数据列表[DN1,DN2,DN3]
Client ->> DN1: 请求Bolck
Client ->> DN2: 请求Block
Client ->> DN3: 请求Block
DN1 --> Client: 返回Block
DN2 --> Client: 返回Block
DN3 --> Client: 返回Block
3. 关键设计
3.1 分布式存储系统基本概念
-
容错能力
能够处理大部分异常场景,如服务器宕机、网络异常、磁盘故障、网络超时等
-
一致性模型
多个数据副本的内容要保证内容是一致的
-
可扩展性
横向扩张 scale-out 能力
-
节点体系
主从模式或对等模式,都是为了实现高可用
-
数据放置
数据是多个副本存放时,需要考虑数据存放的策略。
-
单机存储引擎
有时是需要数据持久化,单机引擎需要解决的是根据系统特点,如何高效地存取硬盘数据
3.2 Namenode 目录树维护
-
fsimage
文件系统目录树,完整存放在内存中。定时存放到硬盘上,修改是只会修改内存中的目录树。相当于是一个文件系统的快照。
-
EditLog
目录树的修改日志,client 更新目录树需要持久化 EditLog 后才能表示更新成功。EditLog 可存放在本地文件系统,也可存放在专用系统上。
NameNode HA 方案一个关键点就是如何实现 EditLog 共享
目录树保存了每个文件的 id,NameNode 维护了每个 Block 所在的节点信息,但这些位置信息并不保存在 fsimage 中,而是 DataNode 主动汇报给 NameNode 动态维护的位置信息。
3.3 数据块(Block)
块在 HDFS 中维护一份真实数据 以及一份 meta数据,两个文件。
-
数据块的硬盘存放,持久化
- 文件在 NameNode 已分割成 block
- DataNode 以 Block 为单位对数据进行存取
-
启动扫盘
- DataNode 需要知道本机存放了那些 Block
- 启动时把本机硬盘上的数据块列表加载在内存中
数据放置策略:
- 新数据存放到那个节点
- 数据均衡需要怎么合理搬迁数据
- 多个副本怎么防止合理
3.4 HDFS 写异常处理
-
Lease Recovery
这里需要先提到一个概念,租约:Client 要修改一个文件时,需要通过 NameNode 上锁,这个锁就是租约(Lease)
一种写异常的情况是:文件写了一半,Client 自己挂了
可能产生的问题:
- 副本不一致
- Lease 无法释放
解决方案是:Lease Recovery
- 副本不一致:比较每个副本的长度,如果长度不一致,选择最小的长度,返回给 NameNode
- Lease 无法释放:设置一个超时时间,如果 Client 没有及时续约,就把原来的 Client 踢掉
-
Pipeline Recovery
文件写入过程中,DataNode 挂了
异常时机:
- 创建连接时
- 数据传输时
- complete 阶段
解决方法:Pipeline Recovery。主要是 Pipeline 的重新构建
-
Client 读异常
读取文件的过程,DataNode 异常挂了
解决方法:节点 Failover 。从其他节点读
另一种情况是 DataNode 没挂但是读的慢,解决方法是也做切换,从其他节点读
3.5 旁路系统
异步解决一些可能会堆积的问题,简化系统的设计:
- Balancer:均衡 DataNode 的容量。通过一个后台程序,对 DataNode 做自动的负载均衡
- Mover:确保副本放置符合策略要求。
旁路系统是一种设计思想,可以在开发中简化系统设计,通过一些异步的操作来解决一些可能会因为系统小问题堆积导致系统运行不下去的情况。不管是在大数据领域中还是其他开发,都是一种很好的思路