SECONDARY NAMENODE 不是 HA 中的 STANDBY 节点

835 阅读4分钟

在与同事讨论「多活」与 「HA」 的区别时,我联想到 HDFS 中 NameNode HA。

NameNode HA 就是一个 Active 节点,一个 Standby 节点,这就是通常我们听到的 HA(High Availability 高可用)架构,同时只有 Active 节点提供服务,另一个节点作为 backup,当 Active 节点挂掉,Standby 节点能变为 Active 节点,保证服务不间断。

而「多活」有所不同,多活实际上是多个 Active 节点,同时工作,都能响应请求。

当我提到 NameNode HA 时,同事立马想到 「Secondary NameNode」,但 Secondary NameNode 与 HA 并没有关系,只能说 Secondary NameNode 这名字取得比较糟糕,下面来看看啥是 Secondary NameNode。

首先我们得知道 「FsImage」 和 「EditLog」。

EditLog:对元数据的每一次更改都会记录在名为 EditLog 的文件中,该文件由 NameNode 维护,存储在 NameNode 节点的本地磁盘,比如在 HDFS 中新建一个文件、修改备份因子都会记录在 EditLog 文件中。

FsImage:整个文件系统的信息,包括文件与 block 的映射和文件系统的属性,存储在一个名为 FsImage 的文件中,该文件也存储在 NameNode 的本地磁盘。保存文件系统目录树以及文件和 block 的对应关系,理解为元数据镜像文件,某个时刻整个 HDFS 系统文件信息的快照;

两者的关系:EditLog 保存元数据更改记录,一个文件只记录一段时间的信息,该文件会在某些时刻合并到 FsImage,FsImage 中的信息要比 EditLog 记录的信息慢一步。

假设没有 EditLog,每次写操作对元数据进行了更改,都通过写 FsImage 的方式进行,那么必定会大大降低写操作效率。因为 FsImage 中存储的是 HDFS 文件系统所有的元数据信息,随着数据量增大,该文件也会增大,每次都对它进行写操作,耗时会很长,所以通过 EditLog 作为临时文件就解决了该问题,只需要定期将 EditLog 中的内容合并到 FsImage 即可。

如果对元数据的修改每次都以写磁盘上文件的方式进行,那必定会降低读写效率,NameNode 实际上将 FsImage 和 EditLog 中记录的元数据信息加载到内存中。

当 NameNode 启动时,会从磁盘读取 FsImage 文件将元信息加载到内存,再读取 EditLog 文件中的信息将元数据同步至最新状态,NameNode 只会在启动的时候合并 FsImage 和 EditLog 文件。

如果长时间没有重启 NameNode,EditLog 文件将会变得非常大,写数据将会越来越慢,对于高并发、数据量大的场景,写操作很慢肯定是不能容忍的。只有下一次重启 NameNode 时才会将 EditLog 合并到 FsImage,但生产环境是很少重启的,必须保证服务不间断,并且 EditLog 文件非常大的话,会导致 NameNode 重启时间变长。

那么这个问题如何解决呢?HDFS 引入了 SecondaryNameNode。

SecondaryNameNode

SecondaryNameNode 不是 NameNode 的备份,不是为了做高可用(HA)的。

checkpoint 是触发 FsImage 和 EditLog 文件进行合并的条件,形成新的 FsImage,也就是检查点。到达 checkpoint 时,会将 FsImage 和 EditLog 文件读取到内存,并通过 http 的方式发送给 SecondaryNamenode,由 SecondaryNamenode 完成合并,再发回给 NameNode。

checkpoint 的触发条件有两个:

  • 指定时间间隔,通过 dfs.namenode.checkpoint.period 进行配置,默认是一小时;
  • 指定 EditLog 文件大小,通过 dfs.namenode.checkpoint.txns 进行配置,默认是 1 百万条事务记录;

只要达到任何一个触发条件,就会将 EditLog 合并到 FsImage。

FsImage 和 EditLog 合并过程

img
img
  1. 检查是否触发 checkpoint 条件;
  2. 触发 checkpoint,NameNode 停止向 edits 中写新的记录,另外生成一个 edits.new 文件,将新的事务记录在此文件中;
  3. SecondaryNameNode 通过 HTTP 请求,从 NameNode 下载 fsimage 和 edits 文件,合并生成 fsimage.chkpoint 文件;
  4. SecondaryNameNode 再将新生成的 fsimage.chkpoint 上传到 NameNode 并重命名为 fsimage,直接覆盖旧的 fsimage,实际上中间的过程还有一些 MD5 完整性校验,检查文件上传下载后是否完整;
  5. 将 edits.new 文件重命名为 edits 文件,旧的 edits 文件已经合并到 fsimage;

注:SecondaryNameNode 也会将 fsimage 等信息载入内存,上图把这一块省略了。