QJM(Quorum Journal Manager)是 Apache Hadoop HDFS(分布式文件系统)中实现 NameNode 高可用性(High Availability, HA) 的核心组件之一。它的主要职责是提供高可用、强一致的共享存储服务,用于存储 HDFS 的元数据编辑日志(Edit Log)。
在传统的非HA HDFS架构中:
- 单点故障问题: 只有一个活动的 NameNode(Active NN)。如果这个 Active NN 宕机,整个 HDFS 集群将不可用,直到手动启动备用的 NameNode(Standby NN)并加载元数据(FsImage 和 Edit Logs)。
- 元数据存储: Edit Log 只存储在 Active NN 的本地磁盘上。Standby NN 需要定期从 Active NN 获取 Edit Log 片段来保持状态同步,但这存在延迟,且 Active NN 的本地磁盘故障会导致元数据丢失。
QJM 就是为了解决这些问题而设计的。
QJM 的核心目标
- 消除 NameNode 单点故障: 允许多个 NameNode(一个 Active,一个或多个 Standby)同时存在。
- 提供可靠的共享 Edit Log 存储: 确保 Edit Log 被安全、一致地存储,即使单个或多个 JournalNode 故障,也不会导致数据丢失或 Active NN 不可用。
- 保证元数据一致性: 确保 Active NN 写入的 Edit Log 操作能被所有 Standby NN 读取并应用到它们的内存状态中,保持所有 NameNode 的元数据视图最终一致。
- 快速故障切换: 当 Active NN 故障时,Standby NN 能快速(通常在几十秒内)接管服务,因为它的元数据状态已经通过持续读取 QJM 中的 Edit Log 保持最新。
QJM 的架构与关键组件
-
JournalNodes (JNs):
- 角色: QJM 的核心服务进程。它们是轻量级的守护进程,运行在独立的物理机或虚拟机节点上。
- 功能: 共同组成一个 基于 Paxos 协议 的分布式共享存储系统,专门用于存储和管理 HDFS 的 Edit Log。
- 部署: 必须部署奇数个(例如 3, 5, 7)。这是为了在发生网络分区或节点故障时,能形成法定人数(Quorum)来达成共识,确保系统的可用性和一致性。
- 存储: 每个 JN 在本地磁盘上维护 Edit Log 文件的副本。
-
Active NameNode (Active NN):
- 角色: 处理所有客户端的读写请求。
- 功能: 在执行任何修改 Namespace(创建文件、删除文件、修改权限等)的操作时,会先将对应的 Edit Log 记录同步地(Synchronously) 写入到 JournalNode Quorum。只有当写入被大多数(Quorum)JN 确认成功后,操作才会被认为提交成功,并返回给客户端。
-
Standby NameNode (Standby NN):
- 角色: 热备节点,时刻准备在 Active NN 故障时接管服务。
- 功能: 持续地(通常是异步地)从 JournalNode Quorum 读取新的 Edit Log 记录(称为
edits
)。它将这些记录应用到自身内存中维护的 Namespace 状态(从加载的 FsImage 开始),从而保持与 Active NN 的状态实时同步(低延迟)。它也定期将内存状态 Checkpoint 到新的 FsImage 并存储在共享存储(通常是另一个共享目录或 NFS)中。
-
ZooKeeper (ZK) Quorum:
- 角色: QJM 本身不直接依赖 ZooKeeper 来存储 Edit Log,但整个 HDFS HA 架构通常依赖 ZooKeeper 来实现以下功能:
- 故障检测与转移: 通过 ZKFC (ZKFailoverController) 监控 NameNode 健康状态,并在 Active NN 故障时触发自动故障转移,选举新的 Active NN。
- Active NN 锁管理: 确保同一时刻只有一个 NN 能成为 Active(防止脑裂)。
- 关系: QJM 和 ZK 协同工作,但职责分离:QJM 管数据(Edit Log) 的高可用和一致性;ZK 管控制(选举、锁、故障转移触发)。
- 角色: QJM 本身不直接依赖 ZooKeeper 来存储 Edit Log,但整个 HDFS HA 架构通常依赖 ZooKeeper 来实现以下功能:
QJM 的工作原理 (写入流程 - Paxos 变体)
当 Active NN 需要写入一条 Edit Log 记录时:
- 事务 ID 分配: Active NN 为这次写入分配一个全局单调递增的事务 ID (
txid
)。 - 准备阶段 (Prepare): Active NN 向 所有 JournalNode 发送一个
prepare
请求,包含txid
和 Edit Log 数据。 - JournalNode 响应: 每个 JN 检查接收到的
txid
:- 如果该
txid
大于它已接受的最高txid
,则 JN 承诺接受这个txid
的写入,并回复ACK
(Acknowledge)。 - 否则,回复
NACK
(Negative Acknowledge)。
- 如果该
- 法定人数确认: Active NN 等待来自 大多数 (Quorum) JournalNode 的
ACK
。 - 提交阶段 (Accept): 如果收到 Quorum 数量的
ACK
:- Active NN 向 所有 JournalNode 发送
accept
请求,指示它们正式提交(持久化)该txid
对应的 Edit Log 记录。 - JournalNodes 收到
accept
后,将记录持久化到本地磁盘,并回复ACK
。
- Active NN 向 所有 JournalNode 发送
- 操作完成: Active NN 收到来自 大多数 (Quorum) JournalNode 对
accept
请求的ACK
后,认为该 Edit Log 记录已成功提交,可以安全地应用到自己的内存状态,并返回成功给客户端。 - 未达成 Quorum: 如果在
prepare
或accept
阶段没有收到 Quorum 数量的ACK
,写入失败。Active NN 会重试或触发错误处理(可能最终导致自己放弃 Active 状态)。
QJM 如何保证高可用和一致性
-
法定人数 (Quorum) 机制:
- 写入需要获得大多数 (N/2 + 1) JNs 的确认。
- 读取(Standby NN 同步)也需要从大多数 JNs 读取,确保读取到的数据是已提交的最新数据(因为任何提交的数据都至少存在于一个 Quorum 的节点中)。
- 只要故障的 JournalNode 数量 不超过半数 (F < N/2),系统就能继续工作(写入和读取都能达成 Quorum)。例如,部署 3 个 JN,最多允许 1 个故障;部署 5 个 JN,最多允许 2 个故障。
-
强一致性:
- 写入协议(基于 Paxos)保证了只要写入成功(返回给客户端),该 Edit Log 记录就已经被持久化到 Quorum 数量的 JNs 上。
- 所有后续的读取(由 Standby NN 执行)都能看到这个已提交的记录,因为读取也要求 Quorum 确认,而 Quorum 中必然包含至少一个持有最新记录的 JN。
-
数据完整性:
- 每个 Edit Log 条目都包含校验和(Checksum)。
- NameNode 和 JournalNode 在读写数据时都会验证校验和,防止静默数据损坏。
-
防护脑裂 (Fencing):
- 虽然 QJM 本身不直接处理脑裂,但 HDFS HA 架构依赖 ZooKeeper 和
ZKFC
来确保只有一个 Active NN:- 只有持有 ZooKeeper 上特定锁(Ephemeral ZNode)的 NN 才能成为 Active。
- 当
ZKFC
检测到 Active NN 不健康或失去 ZK 连接时,会尝试获取锁并触发 Standby NN 的切换。在切换前,新的 Active NN 会通过 QJM 执行fencing
操作:它会向所有 JN 发送一个特殊标记,确保旧的(可能假死的)Active NN 即使恢复也无法再成功写入 Edit Log(因为 JN 会拒绝旧 Active NN 的写入请求)。
- 虽然 QJM 本身不直接处理脑裂,但 HDFS HA 架构依赖 ZooKeeper 和
QJM 的优势
- 真正的 HA: 消除 NameNode 单点故障。
- 强一致性: 保证元数据操作的持久化和一致性。
- 高性能: 相比基于 NFS 的 HA 方案,QJM 通常性能更好,延迟更低。
- 专为 HDFS 设计: 轻量级,只存储 Edit Log,没有通用文件系统的开销。
- 部署简单: JN 是轻量进程,易于部署和管理。
- 开源标准: 是 Apache Hadoop 社区推荐和广泛使用的 HA 方案。
QJM 的局限性/注意事项
- JournalNode 数量: 必须部署奇数个,增加了硬件/虚拟机成本(但通常 3 个就足够)。
- 网络要求: JN 之间以及 JN 与 NN 之间的网络需要低延迟和高可靠性,网络分区会影响可用性。
- 小文件写入: Edit Log 写入是同步操作,大量小文件操作可能会对性能产生一定影响(需要优化)。
- 独立故障域: 为了更高的容灾能力,JournalNode 应部署在不同的机架或物理节点上。
- 监控: 需要监控 JournalNode 的健康状态、磁盘空间以及法定人数是否满足。
总结
QJM 是 HDFS 高可用架构的基石。它通过部署一组奇数个 JournalNode 进程,利用基于 Paxos 的共识协议,为 Active NameNode 提供了一个可靠、强一致的共享存储来写入 Edit Log。Standby NameNode 则通过持续读取 QJM 中的 Edit Log 来保持元数据的实时同步。结合 ZooKeeper 进行故障检测和主备切换控制,QJM 使得 HDFS 能够在 Active NameNode 发生故障时实现数十秒级别的自动故障转移,极大地提高了 Hadoop 集群的可用性和可靠性。
理解 QJM 的核心在于理解其 Quorum 机制、基于 Paxos 的写入协议 以及它与 ZooKeeper 在 HDFS HA 架构中各自的职责分工(数据 vs 控制)。