在现代的企业环境中,单机容量往往无法存储大量数据,需要跨机器存储。统一管理分布在集群上的文件系统称为分布式文件系统。
HDFS,是Hadoop Distributed File System的简称,是Hadoop抽象文件系统的一种实现。Hadoop抽象文件系统可以与本地系统、Amazon S3等文件系统集成。HDFS的文件分布在集群机器上,同时提供副本进行容错及可靠性保证。
简单的一致性模型:HDFS应用需要一个“一次写入多次读取”的文件访问模型。一个文件经过创建、写入和关闭之后就不需要改变。这一假设简化了数据一致性问题,并且使高吞吐量的数据访问成为可能
可参考《使用docker安装hadoop2.7.7》或者《hadoop集群环境搭建》
HDFS是一个主从体系结构,它由四部分组成,分别是HDFS Client、NameNode、DataNode以及Seconary NameNode.
block的拆分使得单个文件大小可以大于整个磁盘的容量,构成文件的Block可以分布在整个集群
如果块设置过大?
如果块设置过小
Packet是Client端向Dataode,或者DataNode的PipLine之间传输数据的基本单位,默认64kB.
Chunk是最小的Hadoop中最小的单位,是Client向DataNode或DataNode的PipLne之间进行数据校验的基本单位,默认512Byte,因为用作校验(自己校验自己),故每个chunk需要带有4Byte的校验位。
所以世纪每个chunk写入packet的大小为526Byte,真实数据与校验值数据的比值为128:1。
NameNode主要是用来保存HDFS的元数据信息,比如命名空间信息,块信息等等。当它运行的时候,这些信息是存在内存中的。但是这些信息也可以持久化到磁盘上:
# 文件系统命名空间的唯一标识符,是在NameNode首次格式化时创建的。
namespaceID=1342387246
# 在HDFS集群上作为一个整体赋予的唯一标识符
clusterID=CID-01b5c398-959c-4ea8-aae6-1e0d9bd8b142
# 标记了NameNode存储系统的创建时间。刚格式化的存储系统,值为0,但升级后,该值会更新到新的时间戳
cTime=0
# 该存储目录包含的时NameNode的数据结构
storageType=NAME_NODE
# 数据块池的唯一标识符,数据块池中包含了由一个NameNode管理的命名空间中的所有文件
blockpoolID=BP-526805057-127.0.0.1-1411980876842
# 这是一个负整数,描述HDFS持久性数据结构(也称布局)的版本,但是该版本号与Hadoop发布包的版本号无关。只要布局变更,版本号将会递减,此时HDFS也要升级。否则,新版本的NameNode(或DataNode)就无法正常工作。
layoutVersion=-57
在NameNode重启时,edits才会合并到fsimage文件中,从而得到一个文件系统的最新快照。但是在生产环境集群中的NameNode是很少重启的,这意味者当NameNode运行来很长时间后,edits文件会变的很大。在这种情况下就会出现下面这些问题:
因此为了克服这个问题,我们需要一个易于管理的机制来帮助我们减小edits文件的大小和得到一个最新的fsimage文件,这样也会减小在NameNode上的压力。而Secondary NameNode就是为了帮助解决上述问题提出的,它的职责是合并NameNode的edits到fsimage文件中。如图所示:
NameNode这很重要,如果发生故障怎么办?Hadoop2.0+可以通过NameNode HA解决单点故障的问题。
- 一个 NameNode 有单点问题,如果再提供一个 NameNode 作为备份,不是能解决问题?这便是主备模式的思想。
- 继续这个思路,光有备份的 NameNode 够吗?我们知道 NameNode 上存储的是 HDFS 上所有的元数据信息,因此最关键的问题在于 NameNode 挂了一个,备份的要及时顶上,这就意味着我们要把所有的元数据都同步到备份节点。好,接下来我们考虑如何同步呢?
- 每次 HDFS 写入一个文件,都要同步写 NameNode 和其备份节点吗?如果备份节点挂了就会写失败?显然不能这样,只能是异步来同步元数据。
- 如果 NameNode 刚好宕机却没有将元数据异步写入到备份节点呢?那这部分信息岂不是丢失了?这个问题就自然要引入第三方的存储了,在 HA 方案中叫做“共享存储”。每次写文件时,需要将日志同步写入共享存储,这个步骤成功才能认定写文件成功。然后备份节点定期从共享存储同步日志,以便进行主备切换。
可以看出,这里的核心是共享存储的实现,这些年有很多的 NameNode 共享存储方案,比如 Linux HA, VMware FT, shared NAS+NFS, BookKeeper, QJM/Quorum Journal Manager, BackupNode 等等,目前社区已经把由 Clouderea 公司实现的基于 **QJM(Quorum Journal Manager)**的方案合并到 HDFS 的 trunk 之中并且作为默认的共享存储实现。
基于 QJM 的共享存储系统主要用于保存 EditLog,并不保存 FSImage 文件。FSImage 文件还是在 NameNode 的本地磁盘上。QJM 共享存储的基本思想来自于 Paxos 算法,采用多个称为 JournalNode 的节点组成的 JournalNode 集群来存储 EditLog。每个 JournalNode 保存同样的 EditLog 副本。每次 NameNode 写 EditLog 的时候,除了向本地磁盘写入 EditLog 之外,也会并行地向 JournalNode 集群之中的每一个 JournalNode 发送写请求,只要大多数 (majority) 的 JournalNode 节点返回成功就认为向 JournalNode 集群写入 EditLog 成功。如果有 2N+1 台 JournalNode,那么根据大多数的原则,最多可以容忍有 N 台 JournalNode 节点挂掉。
HDFS HA是热备份,提供高可用性,但是无法解决可扩展性、系统性能和隔离性。HDFS Federation就是使得HDFS支持多个命名空间,并且允许在HDFS中同时存在多个Name Node。
在HDFS中,我们真实的数据是由DataNode来负责来存储的,但是数据具体被存储到了哪个DataNode节点等元数据信息则是由我们的NameNode来存储的。
DataNode的关键文件和目录如下所示:
从上图可以看出,dataNode的文件结构主要由blk_前缀文件、BP-random integer-NameNode-IP address-creation time和VERSION构成。
BP-random integer-NameNode-IP address-creation time :
rbw :是“replica being written”的意思,该目录用于存储用户当前正在写入的数据。
blk_前缀文件 : HDFS中的文件块,存储的是原始文件内容。
meta文件: 块的元数据信息,每一个块有一个相关联的.meta文件,一个文件块由存储的原始文件字节组成。
VERSION:记录块的基本信息
# 相对于DataNode来说是唯一的,用于在NameNode处标识DataNode
storageID=DS-c478e76c-fe1b-44c8-ba45-4e4d6d26654
# 是系统生成或手动指定的集群ID
clusterID=CID-01b5c398-959c-4ea8-aae6-1e0d9bd8b142
# 表示DataNode存储时间的创建时间
cTime=0
# 表示DataNode的ID号
datanodeUuid=75ffabf0-813c-4798-9a91-e7b1a26ee6f1
# 将这个目录标志位DataNode数据存储目录
storageType=DATA_NODE
# 是一个负整数,保存了HDFS的持续化在硬盘上的数据结构的格式版本号。
layoutVersion=-57
可以通过hdfs fsck
命令来查看一文件的块分部,及检测块的好坏。可参考
《HDFS中的fsck命令(检查数据块是否健康) 》
Hadoop在2.6.0版本中引入了一个新特性异构存储.异构存储可以根据各个存储介质读写特性的不同发挥各自的优势
HDFS的异构存储主要支持 RAM_DISK,SSD,DISK,ARCHIVE
hdfs不会自动识别磁盘,在配置属性dfs.datanode.data.dir中进行本地对应存储目录的设置
<property>
<name>dfs.datanode.data.dirname>
<value>[DISK]file:///grid/dn/disk, [SSD]file:///grid/dn/ssdvalue>
property>
对应命令
- 查看所有策略: hdfs storagepolicies -listPolicies
- 查看yoyo文件的策略: hdfs storagepolicies -getStoragePolicy -path /hdfs/yoyo
- 设置yoyo文件的策略: storagepolicies -setStoragePolicy -path /hdfs/yoyo -policy ALL_SSD
setStoragePolicy的不会立即生效策略,要通过hdfs mover
进行目录扫描,可参考《HDFS异构存储实战》
通常来说,HDFS整体的副本冗余策略,是默认保存3个副本的策略。大型 HDFS 实例通常分布运行在由许多机架组成的集群中,一个机房中有很多机架,一个机架上有多个服务器,不同机架的机器通信需要经过交换机,受带宽等因素的影响,需要更高的网络通信成本。
如果有更多的副本,则随机选择机架,每个机架的副本数量有个上限值,计算方式通常是:(replicas - 1) / racks + 2
这样放置的好处:
从单个文件看来,考虑带宽似乎没有多大意义,但是对于大规模数据的情况下,请求并发量大时,网络是非常重要的一个因素,特别是对于写请求,这里要了解 HDFS 写的流程。因为写副本的过程类似于流水线
假设副本三和副本一放置在一个机架上,那么就会产生两次不同机架间的写操作。而目前的情况是副本二和副本三在同一个机架,机架间的写操作只会发生在副本一到副本二之间,副本二和副本三的写操作是在同一个机架,节省了网络流量。
为了最大的减少带宽和延迟,HDFS 读取文件采用就近原则,如果与客户端在同一机架上的 DataNode 上存有副本,则直接读取该副本。如果 HDFS 是跨数据中心的,则优先选择同一数据中心的副本。
《hdfs 中chunk_HDFS读写流程》
《为什么HDFS文件块(block)大小设定为128M》
《Hadoop的HDFS中的namenode和secondarynamenode的内容总结》
《HDFS NameNode 高可用实现》
《HDFS(3):Hadoop优化与发展》
《hadoop基本原理架构讲解(HDFS部分)》
《大数据入门:HDFS数据副本存放策略》