HDFS 概述

1. 什么是HDFS

1.1. HDFS产生背景

随着数据量越来越大,在一个操作系统存不下所有的数据,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,迫切需要一种系统来管理多台机器上的文件,这就是分布式文件管理系统。HDFS只是分布式文件管理系统中的一种。

1.2. HDFS的定义

HDFS (Hadoop Distributed File System),它是一个文件系统,用于存储文件,通过目录树来定位文件;其次,它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色。

HDFS的使用场景:适合一次写入,多次读出的场景,且不支持文件的修改。适合用来做数据分析,并不适合用来做网盘应用

1.3. HDFS特点

HDFS以流式数据访问模式来存储超大文件,运行于商用硬件集群上。

  • 支持超大文件 “超大文件”在这里指具有几百MB、几百GB甚至几百TB大小的文件。目前已经有存储PB级数据的Hadoop集群了
  • 实现流式数据访问 HDFS的构建思路是这样的:一次写入、多次读取是>最高效的访问模式。数据集通常由数据源生成或从数据源复制而来,接着长时间在此数据集上进行各种分析。每次分析都将涉及该数据集的大部分数据甚至全部,因此读取整个数据集的时间延迟比读取第一条记录的时间延迟更重要。
  • 兼容廉价的商用硬件 Hadoop并不需要运行在昂贵且髙可靠的硬件上。它是设计运行在商用硬件(在各种零售店都能买到的普通硬件)的集群上的,因此至少对于庞大的集群来说,节点故障的几率还是非常髙的。HDFS遇到上述故障时,被设计成能够继续运行且不让用户察觉到明显的中断。
  • 支持简单的文件模型 Hadoop对文件进行了简化,牺牲了一定的性能,但是获得了批量处理的特性,能快速处理批量数据集,只允许追加,不允许修改。
  • 强大的跨平台兼容性 Hadoop是基于Java开发的,具有很好的跨平台特性

1.3.1. HDFS优点:

  • 高容错性

    • 数据自动保存多个副本
    • 副本丢失后,自动恢复

  • 适合批处理
    • 移动计算而非数据
    • 数据位置暴露给计算框架
  • 适合大数据处理
    • 数据规模:GB、TB、甚至PB级
    • 文件规模:百万规模以上的文件数量
  • 可构建在廉价机器上
    • 通过多副本提高可靠性
    • 提供了容错和恢复机制

1.3.2. HDFS缺点

  • 不适合低延迟数据访问
    • 比如毫秒级的数据存储(刚存完就能访问),低延迟与高吞吐率
  • 无法高效存取小文件
    • 每存储一个文件,至少要消耗NameNode节点150字节的内存。小文件数量多,会非常占用NameNode大量内存
    • 小文件存储的寻道时间超过读取时间,违反了HDFS的设计目标
  • 不支持并发写入、文件随机修改

    • 一个文件只能有一个写者。例如用户A在上传ss.txt时,用户B不能同时上传ss.txt

    • 仅支持数据追加append,不支持文件的随机修改

2. HDFS架构

2.1. HDFS数据单元:数据块

HDFS中的文件在物理上以block形式存储。一个block在磁盘上对应两个文件,一个是数据本身,一个是块的元数据(包含数据块长度、校验和、时间戳)

注意HDFS中有两种元数据:

  • 数据块元数据:存放在DataNode上,包含数据块长度、校验和、时间戳
  • 文件元数据:存放在NameNode上,包含文件名、文件目录结构、文件的块副本数、文件的时间戳、文件权限、文件的数据块列表以及各个块所在DataNode等信息

2.1.1. 块大小

块大小可通过dfs.blocksize来配置

  • Hadoop1.0中,块大小默认为64M

  • Hadoop2.0中,块大小默认为128M。例如:200MB的文件要分为2块,分为128M + 72M

2.1.2. 为什么Hadoop2的块大小选择128M

  • 假设寻址时间约为10ms,即HDFS查找到目标block起始位置的时间为10ms
  • 经过研究,寻址时间为传输时间的1%时,为最佳状态。因此,传输时间=10ms/0.01=1000ms=1s
  • 目前机械磁盘的传输速率普遍约为100MB/S。1秒内可以写数据100MB,近似128MB,所以块大小就选择了128M。

如果使用SSD,其传输速率远大于100MB/S,完全可以设置块大小为256M甚至更大。

总结:HDFS块大小设置主要取决于磁盘传输速率

2.1.3. 为什么数据块不能设置太小?

HDFS块设置太小,会增加硬盘寻址时间(硬盘寻道时间)。

块设置太小,会导致块数量非常多,只到其中一个数据块花费的时间自然就更长。这违反了HDFS的设计原则。

HDFS块设置太小,会增加Namenode内存消耗

对于HDFS,他只有一个Namenode节点,他的内存相对于Datanode来说,是极其有限的。然而,namenode需要在其内存FSImage文件中中记录在Datanode中的数据块信息,假如数据块大小设置过少,而需要维护的数据块信息就会过多,那Namenode的内存可能就会伤不起了

2.1.4. 为什么数据块不能设置太大?

Map崩溃问题

系统需要重新启动,启动过程需要重新加载数据,数据块越大,数据加载时间越长,系统恢复过程越长

监管时间问题

主节点监管其他节点的情况,每个节点会周期性的把完成的工作和状态的更新报告回来。如果一个节点保持沉默超过一个预设的时间间隔,主节点记录下这个节点状态为死亡,并把分配给这个节点的数据发到别的节点。对于这个“预设的时间间隔”,这是从数据块的角度大概估算的。假如是对于64MB的数据块,我可以假设你10分钟之内无论如何也能解决了吧,超过10分钟也没反应,那就是死了。可对于640MB或是1G以上的数据,我应该要估算个多长的时间内?估算的时间短了,那就误判死亡了,分分钟更坏的情况是所有节点都会被判死亡。估算的时间长了,那等待的时间就过长了。所以对于过大的数据块,这个“预设的时间间隔”不好估算

MapReduce问题分解问题

数据块过大会导致MapReduce就一两个任务执行完全牺牲了MapReduce的并行度,发挥不了分布式并行处理的效果。

约束Map输出

在MapReduce框架里,Map之后的数据是要经过排序才执行Reduce操作的。想想归并排序算法的思想,对小文件进行排序,然后将小文件归并成大文件的思想。如果数据块很大,排序就变慢了。

2.1.5. 数据块副本数

每个块有多个副本,存储在不同的DataNode上。副本数默认为3

2.1.6. 数据块副本存放策略

假设数据块有三个副本:

  • 第一个副本:放置在Client本地机架的节点上(就近原则);如果Client是集群外提交,则随机挑选一台磁盘不太满、CPU不太忙的节点

  • 第二个副本:放置在与第一个副本不同的机架的节点上。因为同一个机架一般使用同一个电源,电源挂掉则整个机架的服务器都挂掉。所以要放在另一个机架的节点上。

  • 第三个副本:与第二个副本相同机架的其他节点上,随机节点。因为前2个副本已经分别存放在位于两个不同机架的节点上,安全性已经得到一定的保证。同一个机架的节点一般连接同一个高速交换机,所以现在把第3个副本放到与第2个副本相同的机架上,还保证了数据的快速传输。

如果有更多的其它副本:则挑选随机节点

2.1.7. 数据块损坏(corruption)处理

情况1:client读取数据时

  • 客户端请求DataNode读取数据块,DataNode读取block时,会计算该block的checksum
  • 如果计算得到的checksum,与block创建时的值不一样,说明block已经损坏
  • client得知该block已经损坏,会读取其它DataNode上的副本块
  • 下一次DataNode向NameNode发送块列表报告时,NameNode得知该数据块已经损坏,会复制该block的副本,达到预设的副本数

情况2:DataNode会自动在其文件创建后三周验证其checksum,处理同上。

2.1.8. 验证每个数据块有两个文件

dfs/data/ 是HDFS数据的存储路径。可以看到每个数据块有两份文件,一个是数据本身,一个是元数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ tree /usr/local/hadoop/tmp/dfs/data/
/usr/local/hadoop/tmp/dfs/data/
├── current
│   ├── BP-798495748-192.168.57.100-1550512504378
│   │   ├── current
│   │   │   ├── dfsUsed
│   │   │   ├── finalized
│   │   │   │   └── subdir0
│   │   │   │   └── subdir0
│   │   │   │   ├── blk_1073741825 # 数据文件
│   │   │   │   ├── blk_1073741825_1003.meta # 元数据文件
│   │   │   │   ├── blk_1073741826
│   │   │   │   ├── blk_1073741826_1004.meta
│   │   │   │   ├── blk_1073741827
│   │   │   │   └── blk_1073741827_1005.meta
│   │   │   ├── rbw
│   │   │   └── VERSION
│   │   ├── dncp_block_verification.log.curr
│   │   ├── dncp_block_verification.log.prev
│   │   └── tmp
│   └── VERSION
└── in_use.lock

2.2. HDFS命名空间管理

HDFS的命名空间包含目录、文件和数据块

HDFS使用的是传统的分级文件体系,因此,用户可以像使用普通文件系统一样,创建、删除目录和文件,在目录间转移文件,重命名文件等。

注意:只能在文件中追加信息,但是不能修改文件内容。

2.3. NameNode(NN)

NameNode是整个HDFS的管家

  • 管理整个HDFS的名称空间(也称元数据metadata)
  • 处理客户端的读写请求。管理客户端对HDFS的访问。客户端读写数据实际是自己到DataNode上操作的,但是要先与NameNode交互,得到元数据信息(数据在哪些DataNode上)。NameNode会根据全局情况做出决定,客户端读取数据时,NameNode尽量让客户端读取最近的副本
  • 配置副本策略,决定数据块副本存放在哪些DataNode上。
  • 周期性从每个DataNode接收心跳信号和块状态报告(BlockReport)。块状态报告包含了该DataNode上所有的数据块列表信息。

NameNode保存了两个核心的数据结构,即FsImage(保存HDFS元数据)和edits(保存HDFS操作日志)

  • FsImage用于维护文件系统树以及文件树中所有的文件和文件夹的元数据-
  • edits中记录了所有针对文件的创建、删除、重命名等操作

2.3.1. FsImage和edits

元数据在NameNode内存中有一份,同时还要写到磁盘上,文件名为FsImage

FsImage文件包含文件系统中所有目录和文件inode的序列化形式。每个inode是一个文件或目录的元数据的内部表示,并包含此类信息:文件的复制等级、修改和访问时间、访问权限、块大小以及组成文件的块。对于目录,则存储修改时间、权限和配额元数据。

FsImage文件没有记录块存储在哪个数据节点。而是由名称节点把这些映射保留在内存中,当数据节点加入HDFS集群时,数据节点会把自己所包含的块列表告知给名称节点,直接加载到NameNode的内存中,此后会定期执行这种告知操作,以确保名称节点的块映射是最新的。

元数据发生改变时,不会立即同步到FsImage文件,而是在edits记录元数据的操作日志。经过一段时间后,再由SecondaryNameNode将edits中的内容合并到FsImage中

2.3.2. 为什么元数据FsImage在内存中有一份,在磁盘中也要有一份?

首先,我们做个假设,如果元数据直接存储在NameNode节点的磁盘中,因为经常需要进行随机访问,还有响应客户请求,必然是效率过低。因此,元数据需要存放在内存中。但如果只存在内存中,一旦断电,元数据丢失,整个集群就无法工作了。因此产生在磁盘中备份元数据的FsImage。

2.3.3. 为什么要有Edits操作日志

当在内存中的元数据更新时,如果同时更新FsImage,就会导致效率过低,但如果不更新,就会存在一致性问题,一旦NameNode节点断电,就会产生数据丢失。因此,引入Edits文件(只进行追加操作,效率很高)。每当元数据有更新或者添加元数据时,修改内存中的元数据并追加到Edits中。这样,一旦NameNode节点断电,可以通过FsImage和Edits的合并,合成元数据。

2.3.4. NameNode需要格式化

NameNode一开始需要格式化,目的是生成FsImage

1
hdfs namenode -format

2.4. DataNode(DN)

  • 存储块数据、及其数据长度、校验和、时间戳
  • 负责执行数据块读写操作
  • DataNode启动后向NameNode注册,通过后,周期性(1小时)向NameNode上报块列表信息,以保证集群的可靠性
  • 每3秒一次向NameNode发送心跳,心跳返回结果带有NameNode给DataNode命令(如复制块数据到另一台机器,或删除某个数据块)。如果NameNode超过10分钟没有收到某个DataNode的心心跳,则标记该DataNode不可用,之后NameNode都不会再向该DataNode传输任何数据,除非该DataNode启动后向NameNode重新注册

2.4.1. 数据完整性

思考:如果电脑磁盘里面存储的数据是控制高铁信号灯的红灯信号(1)和绿灯信号(0),但是存储该数据的磁盘坏了,一直显示是绿灯,是否很危险?同理DataNode节点上的数据损坏了,却没有发现,是否也很危险,那么如何解决呢?

如下是DataNode节点保证数据完整性的方法。
1)当DataNode读取Block的时候,它会计算CheckSum。
2)如果计算后的CheckSum,与Block创建时值不一样,说明Block已经损坏。
3)Client读取其他DataNode上的Block。
4)DataNode在其文件创建后周期验证CheckSum,如图3-16所示。

2.4.2. DataNode掉线时限参数设置

需要注意的是hdfs-site.xml 配置文件中的heartbeat.recheck.interval的单位为毫秒,dfs.heartbeat.interval的单位为秒

1
2
3
4
5
6
7
8
9
10
<property>
<!-- 单位为毫秒 -->
<name>dfs.namenode.heartbeat.recheck-interval</name>
<value>300000</value>
</property>
<property>
<!-- 单位为秒 -->
<name>dfs.heartbeat.interval</name>
<value>3</value>
</property>

2.5. SecondaryNameNode(SNN/2NN)

SecondaryNameNode的作用:

  • 辅助NameNode合并fsimage和edits
  • 辅助合并fsimage和edits时,会在本地保留一份fsimage.ckpt,所以还起到元数据冷备份的作用。紧急情况下,可辅助恢复NameNode

即使SecondaryNameNode不启动,HDFS也能正常工作

2.5.1. 为什么要辅助NameNode合并fsimage和edits

假如HDFS起来之后,几个月都没有停止、重启。如果操作了很多数据,edits就会非常大,下一次NameNode重启时,读取edits要花很多时间。

此时就需要SecondaryNameNode,每隔一段时间(当然触发情况不止是这一个),就去帮助NameNode合并fsimage和edits,生成新的fsimage,再把新的fsimage复制给NameNode。

这样下一次NameNode重启时,edits就不会特别大,读取edits不用花太多时间,就加快了NameNode的启动时间。

2.5.2. SecondaryNameNode触发合并的情况

  • 情况1:根据hdfs-site.xml设置的dfs.namenode.checkpoint.period,checkpoint默认周期3600秒(1小时)

  • 情况2:根据hdfs-site.xml设置的dfs.namenode.checkpoint.txns,默认edits中的记录超过100万条,就触发checkpoint。

    那么如何知道记录达到100万条呢?根据hdfs-site.xml设置的dfs.namenode.checkpoint.check.period,每60秒检查一次,edits中的记录有多少条。

2.5.3. 合并流程

  1. 当edits文件的大小达到一个临界值(默认是64MB)或者间隔一段时间(默认是1小时)的时候checkpoint会触发SecondaryNameNode进行合并工作。

  2. 当触发一个checkpoint操作时,NameNode会生成一个新的edits即上图中的edits.new文件,之后元数据的改变都会写入edits.new文件中,而不是原来的edits文件。

  3. SecondaryNameNode会将NameNode的edits文件和FsImage下载到本地。

  4. SecondaryNameNode将本地的FsImage文件加载到内存中,然后再与edits文件进行合并生成一个新的FsImage文件即上图中的FsImage.ckpt文件。

  5. SecondaryNameNode将新生成的FsImage.ckpt文件发送到NameNode节点。

  6. NameNode结点的edits.new文件和FsImage.ckpt文件会替换掉原来的edits文件和FsImage文件,至此,刚好是一个轮回即在NameNode中又是edits和FsImage文件了。

  7. 等待下一次checkpoint触发SecondaryNameNode进行工作,一直这样循环操作。

    以上过程既实现了FsImage和EditsLog的合并。因为其间名称节点的元数据被拷贝到第二名称节点上,所以说起到冷备份的效果。

2.6. HDFS Client客户端

  • 文件切分。文件上传HDFS的时候,Client将文件切分成一个1的Block,然后进行上传;
  • 与NameNode交互,获取文件的位置信息;
  • 与DataNode交互,读取或者写入数据;
  • Client提供一些命令来管理HDFS,比如NameNode格式化;
  • Client可以通过一些命令来访问HDFS,比如对HDFS増删查改操作;

3. HDFS安全机制

3.1. HDFS副本

panchaoxin wechat
关注我的公众号
支持一下