11张图理解HDFS的架构设计
来源:     阅读:463
织梦模板店
发布于 2021-03-20 18:06
查看主页

HDFS 详情

HDFS 是一个适合部署在廉价机器上的,具备高度容错性的,高吞吐量的分布式文件系统。

HDFS 的设计理念

支持超大规模数据集

运行在HDFS上的应用具备很大的数据集。HDFS上的一个典型文件大小一般都在G字节至T字节。因而,HDFS被设计成支持大文件存储,能在一个集群里扩展到数百个节点,能够存储海量的数据。

比方说,某个表 100亿条数据,你还用MySQL 去存么?一台机器你的配置得多高才行,再考虑一下查询的效率。假如用了分布式存储之后,也就是说,这些数据放到N多台机器里面去存储,每个机器只存储这个100亿数据的中的一部分,比方一台机器存 500万数据,HDFS 的定位就是针对这种超大的数据集存储的。

硬件错误

HDFS可能由成百上千的服务器所构成,每个服务器上存储着文件系统的部分数据。而存储这些数据的机器出现故障的几率还是蛮高的,比方磁盘损坏,不能读写,网络故障等起因就会导致这台机器不能正常工作了。

因而错误检测和快速、自动恢复是HDFS最核心的架构目标,一旦HDFS 检测到集群中的某台机器出现问题,而后可以对故障进行恢复。

流式数据解决

运行在HDFS 上面的应用和咱们平时写的这些普通应用不同,HDFS 读写文件系统上的数据的时候,是基于一种流的概念来读的,所谓的流式解决,就是批量对文件进行读写,保证高吞吐量的文件读写,不是低推迟的文件读写。

HDFS 是应用在离线批解决场景上面的,尤其是现在的离线数据仓库,用来做数据分析的,我们现在的离线分析,都是今天凌晨去把源系统的数据抽过来放到HDFS 里头,而后解决,都是一批一批地去解决这个数据,不是来一条就计算一条。

简化的数据一致性模型

同时支持对文件的读和写,需要解决大量的并发冲突问题,想想平时大家在写代码的时候对有读,有写的集合这些加的读写锁,不加会出N多问题。 HDFS 这种大规模数据集的分布式存储,它的模型必需得去简化,它的文件只能一次写入,之后是只能去追加,不能随意修改之前的数据。

所以它的理念就是 :write-once,ready-many-times,一次写,而后屡次读,这样就没有数据读写并发冲突,以及数据如何维护一致性的问题了。

这种一次写,屡次读的模型,也能大大提升HDFS 的吞吐量。

移动计算,不要移动数据

大家想想,咱们在读取数据的时候,是从本地磁盘读取数据快,还是从网络中的其余机器上读取数据快?是不是数据越靠近这个机器,速度越快,效率越高。

所以说,在分布在多台机器上的数据,进行分布式的计算,需要让你的计算任务更靠近这些数据,而不是在集群里面通过网络四处去传输数据。

image

master-slave 模式的分布式架构

NameNode 和 DataNode

分布式系统中比较经典的架构是master-slave ,HDFS 就是采用的这种master-slave 架构,一个HDFS 集群是由一个NameNode 和多个DataNode 组成的。

NameNode 是一个进程,JVM 进程,也是一个系统,我们可以认为 NameNode 就是这个master (可以了解成一个大管家),在一个普通的HDFS 集群里面,NameNode 只有一个。它负责管理文件系统命名空间(filesystem namespace)以及用户端对文件的访问。

DataNode 也是一个进程,集群中的每台机器上都有一个DataNode 进程,它主要负责本机上的数据的存储。

文件系统命名空间 Filesystem Namespace

命名空间,怎样了解?就从我们的电脑的文件夹来说,存放的数据都是按照这种目录-> 文件的方式,目录下面可能又是下一层目录。

比方下面的我电脑上的目录结构 ,/文稿/数仓/ 这个目录下面有文件 数仓建设方法xxx.doc 和 目录 /12_资料 ,目录 /12_资料 下面有 04_大数据体系技术结构xxx.doc 这些文档。

所以说,这套文件系统的目录的层级结构和文件的对应关系,就是所谓的 Filesystem Namspace ,这套东西存放在 NameNode 。

image

block 文件块

在HDFS 集群中,一个大文件会分成N多个块进行拆分,存放在不同机器上。比方说现在有一个 1G的大文件,那么HDFS 会对他进行拆分,比方说 128M 一个,那么就差不多分成8 个文件块,而后放到不同的机器上,也就是DataNode 上,DataNode 就是负责来存储这些文件块的。

一个文件被拆分成了多少个文件块,每个文件块存在哪个DataNode 上,NameNode 都是知道的,所以说 NameNode 就是一个HDFS 集群的大管家。

当你要去读取上面那个大文件的时候,会先跟NameNode 这个大管家去讯问一下,这个文件件对应哪几个文件块,每个文件块在哪个位置,而后NameNode告诉你哪些DataNode 上,而后你即可以去对应的DataNode 去哪了。

image

文件系统的元数据持久化管理机制

Editlog 和 FsImage

NameNode 上面存放着HDFS 的,任何对文件系统元数据产生的修改操作,NameNode 都会把这一个一个的操作记录在一个叫EditsLog 的操作日志里面。

例如,在HDFS中创立一个文件,Namenode就会在Editlog中插入一条记录来表示;同样地,修改文件的副本系数也将往Editlog插入一条记录。Namenode在本地操作系统的文件系统中存储这个Editlog 。在hdfs上创立目录,hadoop fs -mkdir -p /usr/dir1,创立一个目录层级结构

而后整个文件系统组织结构,包括数据块到文件的映射、文件的属性等,都存储在一个称为FsImage的文件中,这个文件也是放在Namenode所在的本地文件系统上。

NameNode 在FsImage 文件里面存放元数据之前,会现在内存中保存一段时间,假如每次元数据出现更改就写一次文件,性能是很差的。所以说,NameNode 会每隔一段时间就会去读取磁盘的Editlog 文件出来,一律应用到内存的 fsimage 缓存里面去,而后将fsimage 重新dump 一份到磁盘里面去,而后把前面应用过的Editlog 文件清空掉。

checkpoint 操作

上面把editlog 从磁盘读取出来应用到FsImage 中,而后再把FsImage 保存到磁盘中,最后再删除Editslog 的这个操作,就叫做checkpoint ,这个 checkpoint 的时间间隔我们是可以自己去配置的,在NameNode 启动的时候,它也会先从磁盘上读取edits log 和 Fsimage 在内存中构造一份缓存数据出来。

dfs.namenode.checkpoint.period:这个参数配置几秒钟执行一次checkpointdfs.namenode.checkpoint.txns:这个参数配置当edits log里有多少条数据的时候,就执行一次checkpoint复制代码
image

hadoop 1.x 时代的 SecondaryNameNode 与 BackupNode

SecondaryNameNode

Hadoop 1.x 的时代,NameNode启动的时候,是将 FsImage 读取到内存中,而后再把 EditsLog 的日志内容复原到fsimgae 中,保持内存中的元数据是最新的,而后将最新的fsimage 写入到磁盘里面去,最后清空掉 Editlog 文件。

接下来,用户端在不断的操作HDFS 集群,NameNode 的元数据会不断的进行修改,这些修改都是直接修改内存里面的FsImage 缓存,同时修改元数据的日志文件会被追加到edits log 文件里面去。

有一个问题,对元数据的修改日志会一直追加到edits log 文件里面去,假如他一直被追加,将会变得越来越大,得等到下一次 NameNode 重启,edits log 跟fsimage 合并之后才能被清空。edits log 很大的话,那么在进行合并的时候,将会花费大量的时间,可能导致NameNode 启动变得越来越慢。

所以有一个思路就是去定时合并 edits log 与 fsimage ,合并后,就写入新fsimage 到磁盘上,同时清空edits log ,这样edits log 就不会变得很大了。

所以说hdfs 还有个角色就是 Secondary NameNode ,它会部署到另外一台机器上,它就来专门干合并 edits log 和 fsimage ,每隔时间执行一次,执行的时候,告诉NameNode 别写现在这个 edits log 了,单独开一个新的 edits log 写。而后将 NameNode 的 fsimage 文件和 edits log 拉到本地来,在内存中进行合并,合并完成后,又推送给 NameNode 。

这个操作就是所谓的 checkpoint 操作,这样子一来,edits log 就不会太大 了。

image

BackupNode

BackupNode 也是在Hadoop1.x 中提供的一种机制,它的思想就是优化和替换checkpoint 那种下载edits log 和fsimage 的合并思路。

backup node 的思路就是在内存存放一份和 namenode 一样的fsimage 数据,同时接受 NameNode 发过来的 edits log 数据流,获取到edits log 数据流就往自己本地的edits log 写一条。

同时还会将这条edits log 回放到自己内存里面的 fsimage 里面去,这样内存中的fsimage 就namenode 内存中的fsimage 一毛一样了。

backup node 也会定期执行一次 checkpoint 操作,把自己本次内存中的 fsimage 写到自己磁盘中,替换掉 老的 fsimage 文件,而后清理edits log 。

一个NameNode 只能挂一个 backup node ,用 backup node的好处在于不用让namenode 自己来维护这么一份edits log 文件,不用自己写磁盘,直接就维护自己内存中的这份fsimage 就行了,而后每次接收到要一条修改 元数据的操作,就应用到自己内存中的fsimage ,同时 把edits log 数据流推送给backup node 就行了。

每次namenode 重启的时候,要用-importCheckpoint 去其余地方加载fsimage 到自己本次里面来,这个 -importCheckpoint 数据就从 backup node 里面拿。

image

以上就是Hadoop 1.x 对元数据的管理,Hadoop 2.x已经不是这么玩儿的了。

hadoop 2.x 时代的双实例HA 高可用机制

Hadoop 1.x 元数据管理的缺陷

在 Hadoop1.x 时代,NameNode 挂一个 Secondary NameNode 的方式来管理元数据会 元数据丢失和高可用问题。

高可用问题,一旦NameNode 出现故障,宕机的情况,会导致整个集群不可用。 数据丢失问题,假如NamaNode 出现磁盘损坏的情况,那么会导致肯定的数据丢失,上一次checkpoint 之后的edits log 都会丢失掉。

在Hadoop 2.x 中,处理了元数据丢失和高可用问题。

双NameNode

Hadoop 2.x 集群会启动两个NameNode ,一个是 active 状态,一个是 standby 状态,我们可以了解为主备,active 状态的是主,standby 状态的是备。用户端所有的操作都是发送到 active 状态的 NameNode ,而 standby 状态的 NameNode 则会作为 active NameNode 的热备,不停的同步 元数据。

Journal Node

standby 状态的 NameNode 并不是直接向 NameNode 去请求元数据的,还有个中间商,Journal Node ,用来存储 edits log 的,一般Journal Node 也是集群,三台起步。

NameNode 有元数据变更的时候,就会将 edits log 写入到 Journal node 集群的大多数节点里面去。比方现在Journal Node 集群是3台,大多数节点就是 3/2 + 1 = 2 ,也就是 NameNode 写入 edits log 到2台 集群,就视为写入成功了。

而后 StandbyNameNode 就会一直监控 JournalNode 里面的edits log 变更,只需有变更,就会拉取新的 edits log 到本地来,而后应用到自己的内存里面去,跟active NameNode 保持一致。

当active NameNode 挂掉之后,standby NameNode 会立马感知到,而后会确保自己从 journal node 读取到的是所有的edits log ,内存中的 fsimage 也是最新的数据,而后将自己切换为 active NameNode。

这样一来,数据丢失的问题处理了,一台机器宕机,另外一台机器立马切换成 active namenode ,继续对外提供服务,高可用问题也处理了。

ZKFC (ZKFailoverController)

那么 两台 NameNode 是如何做到在一台故障之后,另外一台自动切换的。

靠 的就是 ZKFailoverController 进程,简称 ZKFC ,每个 NameNode 都会有一个 ZKFC 进程,他们会不停的监控两个 NameNode 的状态,并且在 Zookeeper 上维护两个 NameNode 的状态。

假如说 active NameNode 挂掉了,ZKFC 里面的 HealthMonitor 会监控到,而后ZKFC 里面的 FailoverController 就会通知 NameNode 挂了,而后 FailoverController 会找一 个ActiveStandbyElector 的组件来进行重新主备选举。

ActiveStandbyElector 会基于 zk 来重新选举出来一个standby NameNode 作为 主的 NameNode。

而后 zk 会通知这个standby NameNode 上的 ZKFC 中的 ActiveStandbyElector 组件,通知FailoverController 要切换 standby 状态为 active 状态,而后 FailoverController 再去通知 NameNode 切换为 active NameNode 。

这样,就做到来主备切换,实现了HA。

image

Hadoop 2.x HA 双实例如何管理元数据

在 Hadoop 1.x 中,backup node 会定期执行一次 checkpoint 操作,把自己本次内存中的 fsimage 写到自己磁盘中,替换掉 老的 fsimage 文件,而后清理edits log 。

在 Hadoop 2.x 中,Standby NameNode 其实 跟 1.x 中的 backup node 是类似的,也会定期去执行一次 checkpoint 操作。

Standby NameNode 会运行一个叫 CheckpointerThread 的后端线程,默认1小时一次,或者者说要是有100万条 edits log 没有合并到 fsimage 里面去,那么就执行一次 checkpoint 操作。

把内存中最新的 fsimage 写到磁盘里面去,同时清空掉 edits log ,最后还会将最新的fsimage 文件推送给 active NameNode ,替换 active NameNode 老的 fsimage ,同时也清空掉 active NameNode 上老的 edits log 文件。

image

超大文件数据的分布式存储机制

假如你需要上传一个很大的文件,hdfs 用户端在提交上传命令的时候,首先 NameNode 会根据文件的大小,对文件拆分成多个 block文件块 ,2.x 默认是 128 M,1.x 是64 M。

NameNode 会规划好,每一个block 文件块存储到哪个DataNode 里面去,他会根据每个DataNode 的数据存储情况,尽可能地将数据分散,而后hdfs 用户端就会把文件块上传到各个DataNode 上面去DataNode 收到数据后, 会将这些文件块存储到不同的文件目录里面去,他会建立肯定的层级结构来存储这些文件块,不会放到一个文件夹下面去。

DataNode 在启动的时候,还会扫描自己本地的文件数据目录,向NameNode 汇报自己保持了哪些文件的文件块列表。

image

基于副本的容错机制

基于block 拆分来存储一个大文件,存储的问题倒是处理了,没啥毛病。但是还有个问题就是说假如某一台机器宕机了,比方说资源消耗过大,宕机,或者者重启啥的,那么存放在这个机器上的 block 就没法访问了,原本一个文件是分成10 个block 块的,现在一个故障了,只有9个正常地块了,那么用户端在读取的时候,你这个数据就不全了。

副本机制

那么如何处理上面集群之间的各种机器故障进行容错呢,答案是 副本机制。

HDFS 里面有一个参数叫做 replication factor,复制因子,也就是说,每一个 block ,都给你复制几份放到不同的机器上去,一个机器宕机不影响,另外的机器上有一摸一样的备份。

HDFS 在写文件的时候,默认每个block 就是3个副本,NameNode 会先挑出来3个DataNode ,每一个 DataNode 放一个 block,返回给用户端,而后用户端就向第一个DataNode 传输 block ,第一个 DataNode 写入这个block 到本地之后,这个DataNode 会向第二个DataNode 复制 block ,第二个DataNode 写入本地之后,又向第三个DataNode 复制 block。

机架感知(Rack Awareness)

在 HDFS 集群的机器与机器之间进行是要进行通信的,机器和机器可能存在不同的机架上面,同一个机架上面的机器之间进行数据传输一定是快于不同的机架上面的机器的。

一个 block ,一般默认是 3个副本,那么 NameNode 会把2个副本放到一个机架上的机器,一个副本放到另外一个机架上的机器。

同一个机架上的数据传输是非常快的,还有一点就是就算你这个机架上的所有机器宕机了,那么另外一个机架上的机器还有一份这个block,可以正常对外提供服务。

image

安全模式

在 NameNode 刚启动的时候,就会进入一个模式,叫做安全模式,safe mode,在这个模式下,hdfs集群是不会进行 block 的复制的

这个时候 NameNode 会等着从各个 DataNode 获取心跳和 block report,而后看看集群里的整体的block情况,以及每个block有几个副本,默认是要有3个副本的,假如一个block有3个副本,那么就ok了,安全了

假如肯定比例(80%)的block都是有足够的3个副本的,那么namenode就会退出安全模式。

NameNode 一直处于 safe mode状态下,就是由于没有达到肯定的比例,比方说只有50%的block是有3个副本的。

此时假如发现有某个block副本数量不够(比方只有2个副本)的,就指示 DataNode 复制足够的副本数量

联邦机制

HDFS 里面所有的文件、目录、和配置信息都是存放在NameNode 里面的,当你的HDFS 集群上万台几十万台,数据量超大,你的元数据大小可能都有几百个G,存放在一个NameNode 显著是不得行的。

为理解决这个问题,HDFS 出了一个联邦机制,也就是说,一个集群里面有多个NameNode ,每个NameNode 存储一部分的元数据,不论元数据怎样涨,都可以进行横向扩展NameNode 机器来处理,实际情况是很多公司根本就用不上这个联邦机制,没有这个体量。

在联邦机制下,每个 active NameNode存储一部分 元数据,而后每个 active NameNode 后面还挂一个 standby NameNode ,这样一来,横向扩展跟高可用的问题都处理了。

尽管 NameNode 有多个,但是DataNode 还是一套,block 还是存放在一个 DataNode 集群里面的,只是说 每个DataNode 会向所有的 NameNode 汇报自己的心跳和 block report 情况。

hdfs-11.png

image

关注我

** 愿你尝遍烟火,仍然相信,人间值得! **

假如觉得本文对你有帮助,可以转发关注支持一下

免责声明:本文为用户发表,不代表网站立场,仅供参考,不构成引导等用途。 系统环境 windows
相关推荐
腾讯iOS面试题一分析
使用Kubespray部署Kubernetes集群
没登录网页也能个性化推荐?一文详解浏览器指纹
Ubuntu 上安装 Node.js
vue sass 中图片路径引用方式
首页
搜索
订单
购物车
我的