在Hadoop-2.x版本之前,HDFS集群中的NameNode是单点故障的,即整个集群中只存在一个NameNode,虽然存在SecondaryNameNode,但由于二者关于命名空间的数据有可能不一致,比如NameNode在两次检查点间隔之间出现问题,这势必会导致部分数据的丢失。如果NameNode所在的主机或者namenode进程不可用,整个集群直到NameNode重启或者转移到SecondaryNameNode所在主机为止将使不可用的。上述情况主要以下面两种方式影响HDFS集群的整体可用性:
- 当出现非计划中的事件时如主机宕机,直到管理员重启NameNode为止,集群将不可用。
- 当进行计划中的维护事件时,如在NameNode主机上执行软硬件升级,将导致集群停机。
HDFS的高可用性(High Availability HA)特性解决了上述问题。通过在同一个集群中运行两个冗余的NameNode,其中一个处于active状态,另一个处于standby状态实现了热备份。这允许当其中一台主机宕机时能够进行快速故障恢复到另一个NameNode,或者在按计划维护时能够平滑地切换。
在简单了解了HDFS的高可用性及其优点后,现在学习一下HA的架构。在典型的HA集群中,两台单独的主机被配置为NameNode,任何时候只有一个NameNode处于现役(active)状态,另一个则处于待机(standby)状态。处于现役状态的NameNode负责集群中的所有客户端操作,而待机状态的NameNode则简单地做为从设备,维护足够的状态数据以在必要时提供快速恢复功能。
待机的NameNode如何与现役NameNode保持状态同步呢,即上面提到的维护足够的状态数据。Hadoop为此提供了一组称为JournalNodes(JNs)的彼此分开的守护进程,两个NameNode与该组进程通信。当现役NameNode执行了任何命名空间的改变时,它向JNs中的大多数守护进程记录该变化的一条记录,待机的NameNode能够从JNs读取这些记录,并不断地监视这些记录对edits日志的修改。待机的NameNode不仅查看edits记录,也将它们用于自己的命名空间。在故障切换中,待机的NameNode在使自己成为现役NameNode之前需要确保从JNs读取了所有的记录,这确保了在故障切换之前命名空间的状态是完全同步的。为了实现快速地故障切换,待机的NameNode需要拥有集群中关于块位置的最新信息,这需要DataNodes在两个NameNode中都进行了配置,并向它们发送块位置信息和心跳。
任何时候只有一个NameNode是现役状态对HA集群的正确运行是至关重要的,否则命名空间的状态很快会在两个NameNode之间出现分歧,增加数据丢失的风险或者其它不正确的结果,这是因为两个NameNode都想JNs写数据,也都在读数据,很容易出现数据不一致的情况。为了阻止这种所谓的分裂大脑的场景(split-brain scenario),JournalNodes在任何时候只允许一个NameNode做为写入者,这样的话就不会出现数据不一致的情况,有些类似与多线程或者多进程中的锁。在故障切换期间,将要成为现役NameNode的节点简单地接管向JournalNodes写数据的角色,这将有效地阻止其它NameNode继续处于现役状态,允许新的现役NameNode安全地进行故障切换。