hdfs介绍
一般会说,hdfs是一个分布式的文件存储框架,提供文件的流式访问。由于使用分布式的结构,hdfs可支持非常超大的文件存储,流式存储可使得文件读取的吞吐最大化,hdfs在硬件上使用商用硬件,设计上通过一定的冗余来防范硬件的故障。在分布式环境中,hdfs还能提供数据就近访问能力,在提倡移动计算的框架中,能提高数据处理作业效率。
由于设计上是追求数据存取的高吞吐能力,hdfs不适于以下环境:
- 追求低延迟访问
- 大量小文件
- 数据更新
对于上述场景的数据存储,HBase或许可供选择,hdfs将数据以文件形式组织,给予了数据存储极大的可变性。对于结构化的数据存储,hdfs支持的Hive上层框架。
hdfs存储
hdfs存储结构
与磁盘管理相同,hdfs也使用数据块来存储文件,但hdfs的数据块远比磁盘块大得多(默认为64MB),也不要求小于一个块容量的文件独占一个数据块。这样就可以快速在分布式环境中进行寻址,但是也不宜设置过大,在分布式计算框架中,计算节点的输入是块为最小单元的,块分配过大会限制计算框架的并发能力,同时容易读入比较多不需要的数据。
块的抽象,结合分布式环境,可以方便的将数据分散到不同的存储或计算节点,因而hdfs可以支持相当庞大的数据存储,具备优越的扩展能力。基于块的抽象,也可以很容易进行数据备份,计算节点分配。
hdfs集群架构
hdfs中所有存储硬件均是集群中的节点node,除少量的节点用于存储元信息(NameNode等),其余全部用于存储文件数据(DataNode),这也是常见的管理-工作者模式。
NameNode
NameNode在内存中维护着集群内的文件系统命名空间,访问者从NameNode获得文件的块映射。NameNode对于集群的作用不可谓不重要,NameNode数据丢失意味着整个集群的不可用。
hdfs使用两种方式来保障NameNode数据:
- 保存NameNode的命名空间镜像文件和数据编辑日志到节点本地磁盘和远程备份地址,镜像文件和数据编辑日志能在节点重启的时候在内存中重建命名空间;
- 增加NameNode辅助节点,辅助节点会定期合并编辑日志来生成命名空间镜像文件,从而压缩合并日志,并把镜像文件同步回NameNode。由于节点间同步会有延迟,辅助节点中的数据总会滞后于NameNode,一般又会将辅助节点用作备用节点,在NameNode失效后,从远程备份中恢复内存数据,替换NameNode。
辅助节点压缩编辑日志的过程为:
- 请求NameNode节点切换编辑日志文件,使用新的编辑日志记录数据;
- 从NameNode节点获取镜像文件及被替换下来的编辑日志文件;
- 将镜像文件装载入磁盘,逐行执行编辑日志,完成后生成新的镜像文件;
- 将镜像文件发回NameNode,替换其镜像文件。
NameNode可能不止一个,单一NameNode所能管理的命名空间毕竟还是会受硬件内存限制,在2.x版本以后,可以增加NameNode进行集群扩展,每个NameNode管理文件系统命名空间的一部分。
DataNode
如名字所揭示的,DataNode用于保存文件块数据,hdfs在集群中部署时,默认会产生三份冗余存储。对于数据块的存取,客户端是与DataNode直接交互进行的。
hdfs存取过程
数据读取
客户端对文件数据的访问,包含块寻址和数据流读取两个过程,前者主要与NameNode交互,后者则访问DataNode,由于文件会包含多个块,这个过程会重复多次。
1 |
|
过程(暂且忽略Hadoop对文件系统的抽象):
- client访问NameNode,确定文件起始块的位置,打开数据流;
- 对于文件的每一个数据块,NameNode返回保存此数据块副本的DataNode地址列表,列表会按照节点与客户端的拓扑距离排序;
- client按顺序优先打开最近的DataNode连接,读取数据直到块末端,当与DataNode通讯故障时,则打开这个块的另一个较临近的DataNode读取数据。
- 当需要读取下个一个数据块时,client会询问NameNode获得后继数据块的位置,重复2、3过程直至读到文件末尾,然后关闭数据流通道。
节点间的拓扑结构反映这数据流动的速度,Hadoop对于节点间的距离衡量,采用了一个比较简单的方法:把集群网络看作一棵树,节点间的距离是他们到最近共同祖先的距离总和,按照进程、节点、机架、IDC设定树的层次,设定
- 同一节点上进程间距离为0
- 同一机架上的节点间的距离为2
- 同一IDC上节点间的距离为4
- 不同IDC上节点间的距离为6
数据写入
客户端写入数据,包含文件记录创建、块创建、数据写入过程,也需要同NameNode及DataNode进行多次交互。
1 |
|
过程:
- client访问NameNode在文件系统命名空间中创建一个文件记录,打开数据流写入;
- client使用此数据流进行数据写入,写入的数据会被数据流分成一个个数据包,组装成数据队列,经DataStreamer处理。
- DataStreamer根据需要请求NameNode分配存储数据副本的DataNode,并将返回的DataNode组织成管线,DataStreamer将数据包流式的传入管线的第一个DataNode,该DataNode存储数据包并将数据包一次递交给后续DataNode中。
为了保证数据包准确存储,数据流保存着一个确认队列,管线中所有的DataNode已存储数据包后,此数据包才会从确认队列中删除。
存储利用率
由于hdfs可用于存储体量庞大的数据文件,考虑到存储的利用效率,可能会使用一些压缩算法,但是无论采用何种压缩算法,都必须尽量不破坏数据块的完整性。一般来说有以下几类算法或策略:
- 使用容器文件格式(顺序文件、RCFile、Avro数据文件),搭配一种快速压缩算法如LZO、LZ4、Snappy;
- 使用支持分片的压缩算法如bzip2;
- 将文件分片后分别压缩;
- 不压缩
效率上,从上到下,效率从高到低。