世界最优秀的分布式文件系统架构演进之路

简介: 世界最优秀的分布式文件系统架构演进之路

孙玄:毕业于浙江大学,现任转转公司首席架构师,技术委员会主席,大中后台技术负责人(交易平台、基础服务、智能客服、基础架构、智能运维、数据库、安全、IT 等方向);前58集团技术委员会主席,高级系统架构师;前百度资深研发工程师;


【架构之美】微信公众号作者;擅长系统架构设计,大数据,运维、机器学习等技术领域;代表公司多次在业界顶级技术大会 CIO 峰会、Artificial、Intelligence、Conference、A2M、QCon、ArchSummit、SACC、SDCC、CCTC、DTCC、Top100、Strata+、Hadoop World、WOT、GITC、GIAC、TID等发表演讲,并为《程序员》杂志撰稿 2 篇。

一、前言

Hadoop 是一个由 Apache 基金会所开发的分布式系统基础架构。用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力进行高速运算和存储。

Hadoop 实现了一个分布式文件系统(Hadoop Distributed File System),简称HDFS,解决了海量数据存储的问题;实现了一个分布式计算引擎 MapReduce,解决了海量数据如何计算的问题;实现了一个分布式资源调度框架 YARN,解决了资源调度,任务管理的问题。而我们今天重点给大家介绍的是 Hadoop 里享誉世界的优秀的分布式文件系统-HDFS。

Hadoop 重要的比较大的版本有:Hadoop1,Hadoop2,hadoop3。同时也相对应的有 HDFS1,HDFS2,HDFS3 三个大版本。后面的 HDFS 的版本,都是对前一个版本的架构进行了调整优化,而在这个调整优化的过程当中都是解决上一个版本的架构缺陷,然而这些低版本的架构缺陷也是我们在平时工作当中会经常遇到的问题,所以这篇文章一个重要的目的就是通过给大家介绍HDFS 不同版本的架构演进,通过学习高版本是如何解决低版本的架构问题从而来提升我们的系统架构能力。

二、HDFS1

最早出来投入商业使用的的 Hadoop 版本,我们称为 Hadoop1,里面的 HDFS 就是 HDFS1,当时刚出来 HDFS1,大家都很兴奋,因为它解决了一个海量数据如何存储的问题。HDFS1 用的是主从式架构,主节点只有一个叫:Namenode,从节点有多个叫:DataNode。

我们往 HDFS 上上传一个大文件,HDFS 会自动把文件划分成为大小固定的数据块(HDFS1 的时候,默认块的大小是 64M,可以配置),然后这些数据块会分散到存储的不同的服务器上面,为了保证数据安全,HDFS1 里默认每个数据块都有3 个副本。Namenode 是 HDFS 的主节点,里面维护了文件系统的目录树,存储了文件系统的元数据信息,用户上传文件,下载文件等操作都必须跟 NameNode 进行交互,因为它存储了元数据信息,Namenode 为了能快速响应用户的操作,启动的时候就把元数据信息加载到了内存里面。DataNode 是 HDFS 的从节点,干的活就很简单,就是存储 block 文件块。

HDFS1 架构缺陷

缺陷一:单点故障问题(高可用)

我们很清楚的看到,HDFS1 里面只有一个 NameNode,那么也就是说如果这个Namenode 出问题以后,整个分布式文件系统就不能用了。

缺陷二:内存受限问题

NameNode 为了能快速响应用户的操作,把文件系统的元数据信息加载到了内存里面,那么如果一个集群里面存储的文件较多,产生的元数据量也很大,大到namenode 所在的服务器撑不下去了,那么文件系统的寿命也就到尽头了,所以从这个角度说,之前的 HDFS1 的架构里 Namenode 有内存受限的问题。

我们大体能看得出来,在 HDFS1 架构设计中,DataNode 是没有明显的问题的,主要的问题是在 NameNode 这儿。

三、HDFS2

HDFS1 明显感觉架构不太成熟,所以 HDFS2 就是对 HDFS1 的问题进行解决。

01、单点故障问题解决(高可用)

大家先跟着我的思路走,现在我们要解决的是一个单点的问题,其实解决的思路很简单,因为之前是只有一个 NameNode,所以有单点故障问题,那我们把设计成两个 Namenode 就可以了,如果其中一个namenode有问题,就切换到另外一个 NameNode 上。

所以现在我们想要实现的是:其中一个 Namenode 有问题,然后可以把服务切换到另外一个 Namenode 上。如果是这样的话,首先需要解决一个问题:如何保证两个 NameNode 之间的元数据保持一致?因为只有这样才能保证服务切换以后还能正常干活。

保证两个 NameNode 之间元数据一致。

为了解决两个 NameNode 之间元数据一致的问题,引入了第三方的一个 JournalNode 集群。

JournalNode 集群的特点:JournalNode 守护进程是相对轻量级的,那么这些守护进程可与其它 Hadoop 守护进程,如 NameNode,运行在相同的主机上。由于元数据的改变必须写入大多数(一半以上)JNs,所以至少存在 3 个 JournalNodes 守护进程,这样系统能够容忍单个 Journal Node 故障。当然也可以运行多于 3 个JournalNodes,但为了增加系统能够容忍的故障主机的数量,应该运行奇数个JNs。当运行 N 个 JNs 时,系统最多可以接受 (N-1) / 2 个主机故障并能继续正常运行,所以 Jounal Node 集群本身是没有单点故障问题的。

引入了 Journal Node 集群以后,Active 状态的 NameNode 实时的往 Journal Node 集群写元数据,StandBy 状态的 NameNode 实时从 Journal Node 集群同步元数据,这样就保证了两个 NameNode 之间的元数据是一致的。

两个 NameNode 自动切换

目前虽然解决了单点故障的问题,但是目前假如 Active NameNode 出了问题,还需要我们人工的参与把 Standby NameNode 切换成为 Active NameNode,这个过程并不是自动化的,但是很明显这个过程我们需要自动化,接下来我们看 HDFS2是如何解决自动切换问题的。为了解决自动切换问题,HDFS2 引入了 ZooKeeper集群和 ZKFC 进程。

02、内存受限问题解决

前面我们虽然解决了高可用的问题,但是如果 NameNode 的元数据量很大,大到当前 NameNode 所在的服务器存不下,这个时候集群就不可用了,换句话说就是NameNode 的扩展性有问题。为了解决这个问题,HDFS2 引入了联邦的机制。

如上图所示这个是一个完整的集群,由多个 namenode 构成,namenode1 和 namenode2 构成一套 namenode,我们取名叫 nn1,这两个 namenode 之间是高可用关系,管理的元数据是一模一样的;namenode3 和 namenode4 构成一套 namenode,假设我们取名叫 nn2,这两个 namenode 之间也是高可用关系,管理的元数据也是一模一样的,但是 nn1 和 nn2 管理的元数据是不一样的,他们分别只是管理了整个集群元数据的一部分,引入了联邦机制以后,如果后面元数据又存不了,那继续扩 nn3, nn4… 就可以了。所以这个时候 NameNode 就在存储元数据方面提升了可扩展性,解决了内存受限的问题。

联邦这个名字是国外翻译过来的,英文名是 Federation,之所以叫联邦的管理方式是因为 Hadoop 的作者是 Doug cutting,在美国上学,美国是联邦制的国家,作者从国家管理的方式上联想到元数据的管理方式,其实这个跟我们国家的管理方式也有点类似,就好比我们整个国家是一个完整的集群,但是如果所有的元数据都由北京来管理的话,内存肯定不够,所以中国分了34个省级行政区域,各个区域管理自己的元数据,这行就解决了单服务器内存受限的问题。

HDFS2 引入了联邦机制以后,我们用户的使用方式不发生改变,联邦机制对于用户是透明的,因为我们会在上游做一层映射,HDFS2 的不同目录的元数据就自动映射到不同的 namenode 上。

03、HDFS2 的架构缺陷

缺陷一:高可用只能有两个 namenode

为了解决单点故障问题,HDFS2 设计了两个 namenode,一个是 active,另外一个是 standby,但是这样的话,如果刚好两个 NameNode 连续出问题了,这个时候集群照样还是不可用,所以从这这个角度讲,NameNode 的可扩展性还是有待提高的。

注意:这个时候不要跟联邦那儿混淆,联邦那儿是可以有无数个 namenode 的,咱们这儿说的只能支持两个 namenode 指的是是高可用方案。

缺陷二:副本为 3,存储浪费了 200%

其实这个问题 HDFS1 的时候就存在,而且这个问题跟 NameNode 的设计没关系,主要是 DataNode 这儿的问题,DataNode 为了保证数据安全,默认一个block 都会有 3 个副本,这样存储就会浪费了 200%。

四、HDFS3

其实到了HDFS2,HDFS就已经比较成熟稳定了,但是HDFS3还是精益求精,再从架构设计上重新设计了一下。

01、高可用之解决只能有两个namenode

当时在设计 HDFS2 的时候只是使用了两个 NameNode 去解决高可用问题,那这样的话,集群里就只有一个 NameNode 是 Standby 状态,这个时候假设同时两个NameNode 都有问题的话,集群还是存在不可用的风险,所以在设计 HDFS3 的时候,使其可支持配置多个 NameNode 用来支持高可用,这样的话就保证了集群的稳定性。

02、解决存储浪费问题

HDFS3 之前的存储文件的方案是将一个文件切分成多个Block进行存储,通常一个 Block 64MB 或者 128MB,每个 Block 有多个副本(replica),每个副本作为一个整体存储在一个 DataNode 上,这种方法在增加可用性的同时也增加了存储成本。ErasureCode 通过将 M 个数据 block 进行编码(Reed-Solomon,LRC),生成 K 个校验(parity)block,这 M+K 个 block 组成一个 block group,可以同时容忍 K 个 block 失败,任何 K 个 block 都可以由其他 M 个 block算出来。overhead 是 K/M。

以 M=6,K=3 为例,使用 EC 之前,假设 block 副本数为 3,那么 6 个 block 一共 18 个副本,overhead 是 200%,使用 EC 后,9 个 block,每个 block 只需一个副本,一共 9 个副本,其中 6 个数据副本,3 个校验副本,overhead 是 3/6 = 50%。

在存储系统中,纠删码技术主要是通过利用纠删码算法将原始的数据进行编码得到校验,并将数据和校验一并存储起来,以达到容错的目的。其基本思想是将 k 块原始的数据元素通过一定的编码计算,得到m块校验元素。对于这 k+m 块元素,当其中任意的 m 块元素出错(包括数据和校验出错),均可以通过对应的重构算法恢复出原来的 k 块数据。生成校验的过程被称为编码(encoding),恢复丢失数据块的过程被称为解码(decoding)。

Reed-Solomon(RS)码是存储系统较为常用的一种纠删码,它有两个参数 k 和m,记为 RS(k, m)。如下图所示,k 个数据块组成一个向量被乘上一个生成矩阵(Generator Matrix)GT 从而得到一个码字(codeword)向量,该向量由k个数据块和 m 个校验块构成。如果一个数据块丢失,可以用 (GT) - 1 乘以码字向量来恢复出丢失的数据块。RS(k,m) 最多可容忍 m 个块(包括数据块和校验块)丢失。

它是社区最新的 HDFS3 内部的方案,需要对整个 HDFS 内部实现进行改造,包括 DataNode,NameNode 还有 DFSClient,该方案同时支持在线和离线 EC。

03、在线 EC

当前 HDFS block 的副本作为一个整体连续(contiguous)的存储在一个DataNode 上,在 locality 上具有一定的优势,特别是对于 MapReduce 这样的应用,但是这种方法不好做在线 EC。当前社区方案不以 block 为单位进行 EC,而是以 strip 为单位进行 EC(HDFS 依旧管理 Block)设计思路参考了 QFS。对于配置了 EC 的文件,客户端写入时将文件的数据切成一个个的 64KB 的 strip,相邻的 strip 发往不同的 DataNode,比如当前使用 (6,3)-Reed-solomon 编码,当前正在写的文件有 6 个 strip:strip1, strip2, strip3, strip4, strip5, strip6,那么这 6 个 strip 和相应的编码出来的 3 个校验 strip 共 9 个 strip 会并行的发往 9 个不同的DataNode。这种方式写入性能更好,但是也会对网卡出口带来一些压力,同时牺牲了 locality。如果文件大小不是 64KB * 6 的整数倍(本文例子),那么最后一个strip group 显然不是满的,这时客户端还会将最后一个 strip group 的长度记在校验块中,后续读的时候,可以根据这个长度和数据块长度还有文件长度来校验。

对于 append 和 hflush 操作,最后一个 parity strip group 很可能还没有切换成新的 strip group,这就需要 DataNode 更新最后一个 parity strip 的数据。

读操作,丢失 block 时,只需要读 9 个 DataNode 中任意 6 个 DataNode 即可修复。修复过程需要读多个 DataNode,耗费网络带宽和磁盘 IO。

04、离线 EC

该方案也支持离线 EC,可以异步的将多副本文件转成 EC 文件,通过集成在NameNode 中的 ECManager 和 DataNode 上的 ECWorker 来支持。命令行工具提供 replication 和 ec 之间的转换,可以通过命令行配置哪些文件/目录使用 EC。在转换方程中,不支持 append。

这样的话,HDFS3 靠就删码技术解决了存储浪费的问题。

五、尾声

好了,到目前为止我们看到 HDFS,三个大的版本的演进的过程,一开始是HDFS1,HDFS1 有问题,所以就有了 HDFS2,HDFS2 就是为了解决 HDFS1 架构缺陷的,同学们,我们回过头来想想,其实 HDFS1 的那些架构设计问题,是不是我们平时的项目当中也是存在的,所以以后大家在项目中遇到类似问题的时候,不妨可以参考借鉴一下 HDFS2 的解决的思路。HDFS3 是对 HDFS2 的优化,其实 HDFS3 解决的这些问题,如果自己设计过文件系统的同学(本人自己设计过分布式图片服务器)也可用类似的思路去解决系统的高可用和副本造成存储浪费的问题。

希望能给大家带来收获,同学们加油!!!

目录
相关文章
|
2月前
|
安全 应用服务中间件 API
微服务分布式系统架构之zookeeper与dubbo-2
微服务分布式系统架构之zookeeper与dubbo-2
|
2月前
|
负载均衡 Java 应用服务中间件
微服务分布式系统架构之zookeeper与dubbor-1
微服务分布式系统架构之zookeeper与dubbor-1
|
2月前
|
存储 JSON 数据库
Elasticsearch 分布式架构解析
【9月更文第2天】Elasticsearch 是一个分布式的搜索和分析引擎,以其高可扩展性和实时性著称。它基于 Lucene 开发,但提供了更高级别的抽象,使得开发者能够轻松地构建复杂的搜索应用。本文将深入探讨 Elasticsearch 的分布式存储和检索机制,解释其背后的原理及其优势。
190 5
|
23天前
|
运维 供应链 安全
SD-WAN分布式组网:构建高效、灵活的企业网络架构
本文介绍了SD-WAN(软件定义广域网)在企业分布式组网中的应用,强调其智能化流量管理、简化的网络部署、弹性扩展能力和增强的安全性等核心优势,以及在跨国企业、多云环境、零售连锁和制造业中的典型应用场景。通过合理设计网络架构、选择合适的网络连接类型、优化应用流量优先级和定期评估网络性能等最佳实践,SD-WAN助力企业实现高效、稳定的业务连接,加速数字化转型。
SD-WAN分布式组网:构建高效、灵活的企业网络架构
|
28天前
|
消息中间件 关系型数据库 Java
‘分布式事务‘ 圣经:从入门到精通,架构师尼恩最新、最全详解 (50+图文4万字全面总结 )
本文 是 基于尼恩之前写的一篇 分布式事务的文章 升级而来 , 尼恩之前写的 分布式事务的文章, 在全网阅读量 100万次以上 , 被很多培训机构 作为 顶级教程。 此文修改了 老版本的 一个大bug , 大家不要再看老版本啦。
|
3月前
|
存储 NoSQL Java
一天五道Java面试题----第十一天(分布式架构下,Session共享有什么方案--------->分布式事务解决方案)
这篇文章是关于Java面试中的分布式架构问题的笔记,包括分布式架构下的Session共享方案、RPC和RMI的理解、分布式ID生成方案、分布式锁解决方案以及分布式事务解决方案。
一天五道Java面试题----第十一天(分布式架构下,Session共享有什么方案--------->分布式事务解决方案)
|
3月前
|
弹性计算 Cloud Native Windows
核心系统转型问题之核心系统需要转型到云原生分布式架构的原因如何解决
核心系统转型问题之核心系统需要转型到云原生分布式架构的原因如何解决
|
3月前
|
Cloud Native 云计算 微服务
云原生时代:企业分布式应用架构的惊人蜕变,从SOA到微服务的大逃亡!
【8月更文挑战第8天】在云计算与容器技术推动下,企业分布式应用架构正经历从SOA到微服务再到云原生的深刻变革。SOA强调服务重用与组合,通过标准化接口实现服务解耦;微服务以细粒度划分服务,增强系统灵活性;云原生架构借助容器化与自动化技术简化部署与管理。每一步演进都为企业带来新的技术挑战与机遇。
123 6
|
3月前
|
Kubernetes 负载均衡 算法
如何在kubernetes中实现分布式可扩展的WebSocket服务架构
如何在kubernetes中实现分布式可扩展的WebSocket服务架构
69 1
|
4月前
|
NoSQL 算法 Java
(十三)全面理解并发编程之分布式架构下Redis、ZK分布式锁的前世今生
本文探讨了从单体架构下的锁机制到分布式架构下的线程安全问题,并详细分析了分布式锁的实现原理和过程。
102 6

热门文章

最新文章