vlambda博客
学习文章列表

HDFS架构演进之路


本文尝试说明下面四个问题

1.HDFS 如何实现有状态的高可用架构
2.HDFS 如何解决单机内存受限问题
3.HDFS 支持亿级流量的密码
4.SecondaryNameNode 作用

1. HDFS 如何实现有状态的高可用架构

1.1 HDFS 架构演进之路

Hadoop 大版本有三个,Hadoop1、hadoop2、Hadoop3,对应的HDFS 也有三个版本 HDFS1、HDFS2、HDFS3,本文会介绍 三个版本之间的架构区别

1.2 HDFS1 架构

HDFS 是一个分布式的文件系统, 它是一个主从式的架构,其核心组件就是 NameNode(主节点,一个) 和 DataNode(从节点,多个)。

Namenode 主要是接收客户端的请求和负责元数据管理,而 Datanode 主要就是负责存储数据。Datanode 中存储的数据都是一个个的块,每个块大小默认 64M

具体使用一个客户端上传数据的示例来说明:

1.HDFS 会把用户上传的文件切分成很多个 block,默认 每个 block 大小是64M,2.然后把这些 block 存储在不同的 datanode 上,并且为每个 block 生成 3 个副本。3.而每个 block 存在哪个 datanode上以及哪些 block 属于一个文件这些信息都存储在 Namanode 上,这些数据就是元数据4.Namanode 为了快速响应用户的请求,还会把这些元数据放到内存中。

下面是一个简单的 HDFS1 的架构图HDFS架构演进之路

1.3 HDFS2 架构-实现有状态的高可用架构

虽然 HDFS1 解决了分布式存储的问题,但是他的设计还是有一些缺陷,比如:

1.单点问题:因为 HDFS1 中只有一个 Namenode ,而所有的元数据信息都存储在 Namenode 上,而一旦 Namenode 出现问题,所有的元数据就会丢失,而整个集群也就无法使用了2.内存受限问题:Namenode 为了快速响应用户的请求,会把所有元数据信息放到内存中,随着时间的推移,元数据信息增多,必然会撑爆内存

基于这个两个问题,HDFS2 诞生了,HDFS2 使用 HA 解决单点问题,使用 联邦 解决内存受限问题。

1.3.1 HDFS2 架构-实现有状态的高可用架构

其实解决单点的问题,最直接的办法就是在引入一个主节点(Namenode)呗。只要有两个 Namenode,并且两个Namenode的数据一致,当其中一个坏掉时,使用另一个替换就可以了。其实HDFS2就是这么解决的。HDFS架构演进之路HDFS2 又引入了一个 Namenode 并且给 Namenode 增加了状态,一个是 Active 状态的,一个 Standby 状态的,工作中由 Active 的 Namenode 负责接受用户的操作请求,当 Active 的 Namenode 异常时,Standby 状态的 Namenode 会切换状态变为 Active 状态。

但是这样就会引入另外几个问题:

1.一个是 Namenode 间的数据同步2.一个是 Namenode 间的状态自动切换

下面具体讲解下,HDFS2 如何解决这两个问题:

1.3.2 Namenode 间的数据同步

两个 Namenode 要能达到切换的条件,必然是两个 Namenode 的元数据要一致,那么如何保证两个 Namenode 的元数据一致呢。HDFS 引入了 JournalNode 集群(类似zookeeper),该集群能保证数据的一致性。

在工作中, Active 的 Namenode 会向 JournalNode 同步新的元数据信息,而 Standby 的 Namenode 会读取 JournalNode 的元数据信息。一旦 Active 的 Namenode 出现异常,Standby 的 Namenode 会随时切换为 Active。

1.3.3 Namenode 间的状态自动切换

那么 Standby 的 Namenode 如何切换 Active 呢?HDFS 又引入了 zookeeper 集群,并且为每个 Namenode 增加了一个 zkfc 的服务。zkfc 会定时监控 Namenode 的状态,一旦 Namenode 状态异常就会退出 zk的选举列表。

HDFS2 具体的架构图如下:

HDFS架构演进之路

提示:

1.JournalNode 集群多少台合适?JournalNode 在实际工作中的压力很小,一般 200 台以上使用 3 台 Journalnode 足够了,200台以上使用5台基本都解决了2.JournalNode 集群是否可以使用 zookeeper 替代 其实是可以的,当时这个具体要自己该源码去实现

2. HDFS 如何解决单机内存受限问题

其实解决内存受限跟解决单点的思路类似,既然一台主机不行就引入多台

HDFS架构演进之路

乍一看图跟 HA 的第一个图是一样的,但是实现不同,HA里的两个 Namenode 数据是要一致的,而这里的 Namenode 数据必须是不一样的 (虽然图上看不出区别),否则就没有解决内存受限的问题。这个就是 Namenode 的联邦。

那 Namenode HA + 联邦 后的架构图就如下:

HDFS架构演进之路

可以看到我们需要为 联邦 内的每个 Namenode 提供 HA.

但这样就会又引入一个问题,就是用户访问数据的时候到底应该访问哪个 Namenode 呢?

1.其实这个就类似数据库的分库分表一样,需要提供一个路由的方案来解决访问的问题,这个路由 Hadoop 并没有提供,需要自己封装。2.或者可以 分业务存储,比如 A 业务都存储到 Namenode1 ,B 业务都使用 Namenode2,这样就简单解决了。

提示:

1.一般没有必要的话,不建议使用联邦(规模 1万台以下的集群)

3. HDFS 支持亿级流量的密码

3.1 HDFS 支持的亿级流量具体什么?

这里所属的支持亿级流量具体是指客户端的请求,因为 Namenode 管理元数据,所有任务在执行的时候都要请求 Namenode 的元数据,而一旦任务多了这个请求量还是很可观的。因为像大的企业上动不动就几十万,甚至上百万的任务,每个任务再有几十个请求,那每天几千万的访问量还是有的。

所以 Namenode 必须可以应对 亿级 的元数据请求,为了应对这么大流量的访问所以 Namenode 才把所有的元数据信息都放到内存中了。但是又为了数据安全,Namenode 又会把 元数据信息放到磁盘上,且为了 HA 元数据还得写到 JournalNode 集群中。

那问题就来了,如果元数据只内存中,当然能够支持亿级的请求,但是又要写磁盘,又要写 JournalNod ,Namenode 如何解决的呢?其实 Namenode 在管理元数据的时候,使用了两个方法来解决此问题:那就是 双缓冲分端加锁

3.2 双缓冲

双缓冲其实就是两块内存(代码里其实就是两个list)HDFS架构演进之路Namenode 在接收客户端的元数据操作请求时,是先把数据写入内存1中,当内存1中的数据写到一定程度的时候,把内存1 与内存2交换(这里是指针交换,不是内存的copy),然后把交换后的内存刷新到磁盘或者Journalnode中。

具体的实现大概如图:

3.3 分段加锁

在 Namenode 元数据管理这块,HDFS 使用了多线程去实现的,很多地方加了使用 synchronized 加了锁,但是它并没有对所有代码加锁,而是只对有线程安全问题的地方加锁。

这块具体的需要看源码。

4. SecondaryNameNode 作用

在 HDFS 中 还有一个 服务叫 SecondaryNameNode,在HDFS1中,他的作用很重要,主要是为了合并 Fsimage 和 Editlog 的。在讲 SecondaryNameNode 之前,先说下 Fsimage 和 Editlog 。在上面我们介绍过,其实 Namendoe 的元数据是存储在磁盘上的,实际上所有的历史元数据都会在 Fsimage 文件中,而新增的元数据信息是存储在 Editlog 中的。当 Namenode 启动的时候是会合并 Fsimage 和 Editlog 文件,并且把他们都读入内存中。这就有个问题,如果 Editlog 文件过多(Editlog 可以有很多个)了,在合并的时候就会很耗时,然后拖慢 Namenode 的启动,所以防止 Editlog 文件过多,就引入 SecondaryNameNode 服务,定期合并 Fsimage 和 Edit 文件。

具体的合并流程如图:

SecondaryNameNode 本地最开始也有一个与Namenode一样的 Fsimage 文件,然后定期去拉取 Editlog 文件到本地,然后与自己的 Fsimage 合并,合并成功后,去替换 Namenode 中的 Fsimage ,并删除已经合并的 Editlog 文件

提示:从 HDFS2 以后 SecondaryNameNode 就可以不用启动了,因为此功能由 standby namenode 实现即可