公司真题库

【字节跳动】HDFS 写数据流程与 NameNode 高可用

91学AI·2026/7/20·8 阅读

考察点

这道题出自字节跳动大数据工程师一面,是 Hadoop 体系的基础必考题。写流程要看你能不能把 client、NameNode、DataNode 三方的交互讲完整,特别是 pipeline 复制和 ack 回传的细节;NameNode 挂了怎么办则是考 HA 架构的理解——Active/Standby 切换、共享编辑日志、fencing。追问常往"写入过程中某个 DataNode 挂了怎么办"、"为什么用 QJM 而不是 NFS 共享存储"、"联邦和 HA 解决的不是一个问题"走。

参考答案

写数据完整流程

第一步,客户端向 NameNode 发起 create 请求。NameNode 做权限检查和文件是否已存在的检查,通过后返回成功——注意此时还没有分配任何 block。客户端随后开始写数据,DFSOutputStream 把数据切成 packet(64KB 级别)填入内部队列。

第二步,为 block 申请 DataNode 列表。数据攒够一个 block(默认 128MB)时,客户端向 NameNode 申请 block 分配。NameNode 按机架感知策略返回若干 DataNode 组成 pipeline(假设副本数 3):第一个副本优先放在客户端所在节点(client 是集群外机器则随机挑负载低的),第二个副本放另一个机架的节点,第三个副本放第二个副本同机架的另一节点。这个策略在可靠性(跨机架抗机架级故障)和写带宽(副本二、三同机架,省跨机架流量)之间取平衡。

第三步,pipeline 流水线复制。客户端把 packet 发给第一个 DataNode,第一个一边落盘一边转发给第二个,第二个再转发给第三个——注意不是客户端分别发三份,而是流水线传递,客户端只出一份网络流量。每个 DataNode 收到 packet 后向上一级回 ack,逐级回传到客户端。所有副本确认后这个 packet 才算写成功。写够一个 block 后,重复第二步申请下一个 block,新 block 的 DataNode 列表可能不同。

第四步,关闭与确认。数据写完,客户端调用 close,等待所有 ack,然后通知 NameNode finalize——NameNode 把文件元数据(block 列表、大小)持久化到 edits log。整个过程中 DataNode 定期向 NameNode 心跳汇报 block 状态,NameNode 据此维护元数据的最终视图。

写过程中 DataNode 挂了

这是高频追问。pipeline 中某个 DataNode 故障时,客户端检测到后执行 pipeline recovery:跳过故障节点,用剩余节点重建 pipeline 继续写;同时给 block 分配一个新的 generation stamp(版本号),通知 NameNode。事后 NameNode 发现该 block 副本数不足,会调度复制任务补齐第三个副本。整个过程对写入方透明,只是该 block 的副本在补齐前处于欠复制状态。这个机制体现了 HDFS 的设计取向:写入路径容错优先,副本一致性异步收敛。

NameNode 挂了的两个层次

先分清 NameNode 管什么:全部元数据(目录树、文件到 block 的映射、block 到 DataNode 的映射),存在内存里,持久化靠 fsimage(全量快照)+ edits log(增量操作日志)。NameNode 挂了,整个集群的元数据服务停摆——读写全废,这是 Hadoop 1.x 时代的著名单点。

HDFS HA:Active/Standby 架构

Hadoop 2.x 引入 HA:部署两个 NameNode,一主(Active)一备(Standby)。核心要解的问题是元数据怎么同步——方案是共享编辑日志,生产上主流用 QJM(Quorum Journal Manager):部署奇数个(通常 3 个)JournalNode 组成轻量级集群,Active 把每条 edits 写入多数派(2/3)才算成功,Standby 持续从 JournalNode 读取并重放 edits,保持内存元数据与 Active 准实时同步。同时 DataNode 的 block report 是同时发给两个 NameNode 的,保证 Standby 也有完整的 block 位置信息——这两条保证了 Standby 能在秒级接管。

故障切换由 ZKFC(ZooKeeper FailoverController)负责:每个 NameNode 机器上跑一个 ZKFC,监控本机 NameNode 健康并在 ZooKeeper 上持有分布式锁,Active 失联后另一个 ZKFC 抢锁、执行 fencing(确认旧主真的死了,常用的手段是 ssh 过去 kill 进程,以及让共享存储拒绝旧主写入,防止脑裂双写)、把本机提升为 Active。客户端通过逻辑 nameservice 配置自动重定向到新主。

一个常被混淆的点:Federation 不是 HA

HA 解决的是可用性(主挂了能切),不解决扩展性——所有元数据还是单个 Active 的内存扛着,文件数到几亿级别内存和 RPC 都会成为瓶颈。Federation(联邦)解决的是水平扩展:部署多对 NameNode,每对负责一个命名空间(比如 /user、/tmp 各归一对),底层共用 DataNode 存储池。两个机制正交,大厂集群通常是 Federation + 每个命名空间各自 HA。面试时能主动澄清"HA 和联邦解决的是不同问题",说明概念边界清晰。

可能的追问

  • 为什么 QJM 优于早期 NFS 共享存储方案?NFS 本身是单点且需要额外 fencing 硬件手段;QJM 基于多数派协议,自带防脑裂的 epoch 机制,部署轻量,容忍半数节点挂掉。
  • 写 block 时 NameNode 返回的列表是怎么挑节点的?机架感知 + 负载均衡:考虑机架分布、磁盘剩余空间、节点 IO 繁忙度,避免热点。
  • fsimage 什么时候合并?HA 架构下 Standby 定期做 checkpoint:把内存 fsimage 与 edits 合并成新 fsimage 推回 Active,非 HA 时代这是 SecondaryNameNode 的活——注意 SecondaryNameNode 不是热备,只做 checkpoint,这是经典辨析题。

评论 (0)

暂无评论,快来抢沙发吧!

91学AI

© 2026 91学AI · 按岗位学 AI 与大数据. All rights reserved.