想象你是一座大型社区图书馆的馆长。图书馆有数百万册藏书,一个巨大的仓库,以及成千上万的读者。你不可能把所有书都放在一间屋子里——放不下,也太危险(一场火灾就全毁了)。于是你想出一个办法:建一栋有无数房间的大楼,把书拆成整齐的章节分册,分散存放在不同房间,每个房间放多份副本。为了让读者能快速找到任何一本书,你设置了一本“总索引册”,记录每本书的每个章节放在了哪个房间的哪个架子上。 这就是分布式文件系统的核心思想——而 Google 的 GFS(Google 文件系统)和开源的 HDFS(Hadoop 分布式文件系统)就是这套“图书馆系统”的工程实现。它们把海量数据“拆书分册”,存进成百上千台廉价服务器组成的“大仓库”里,由一台“总索引册”服务器(NameNode)统一调度。本文将带你走进这栋数据大楼的内部,看看它如何设计楼层、分配房间、处理故障,以及今天的大数据工程师又是如何对它进行“改造升级”的。
掌握分布式文件系统架构,是理解整个大数据生态(Hive、Spark、Flink)的地基。无论你做数据工程师、架构师还是 AI 基础设施开发,面试和实战中都绕不开这套设计逻辑。
可视化演示
展示HDFS写入流水线中副本在DataNode间的传递、副本放置与容错机制,以及纠删码相较3副本的存储开销优化,可切换三种模式观察。
本节配有交互动效(进入视口后自动加载,约 3KB)。
写入流水线 客户端向NameNode请求,获得DataNode列表 数据按pipeline依次传给后续DataNode作副本 DN1 → DN2 → DN3 流水线写入避免客户端重复传输,效率高。
总索引册与大楼
社区图书馆决定不再把书一本本完整存放在单间库房,而是建一栋巨大的“数据大楼”。大楼里有成千上万个房间(DataNode),每个房间专门存放标准大小的“分册”——比如 128MB 一章。馆长办公室里摆着一本总索引册(NameNode),上面记录了:哪些书被拆成了哪些分册、每个分册存放在哪个房间的哪个架子上、读者当前正在借走哪些分册。这套设计,就是 HDFS 的宏观骨架。
在技术世界里,“总索引册”叫 NameNode(名字节点),“数据大楼的房间”叫 DataNode(数据节点)。NameNode 只负责管理元数据——即“文件叫什么、分成几块、每块在哪”这类信息,不存真实数据。DataNode 则真正保管数据内容。为了让管理更简单,文件被拆成固定大小的 块(Block),默认 128MB,每个块独立存储、独立复制。
这个“拆书分册”的设计带来了三个好处:第一,单本书可以超过单个房间的容量(单个文件可以大于单台磁盘);第二,每个分册可以复制多份放在不同房间,防止火灾/磁盘损坏造成数据丢失;第三,读者可以直接从离自己最近的房间读取某个分册,实现负载均衡。当然也有代价——总索引册一旦丢失,整栋大楼就“失明”了,这引出了后面要讲的 HA(高可用)方案。
回到图书馆的比喻:总索引册虽然不占太多空间,但它必须放在最安全的保险柜里,并且时刻保持更新。任何一个分册的房间出了问题,索引册都能立刻发现并安排重新抄录一份。这就是 NameNode 与 DataNode 各司其职的精髓——元数据集中、数据分散。
- 块大小HDFS 默认每个块 128MB,远大于传统文件系统的 4KB,这是为了减少元数据条目数。
- 块数量文件总大小除以单块大小,向上取整。
写入流水线
现在,一位读者(客户端)想把一本新书存入图书馆。流程是什么样的?他不能自己抱着一堆分册随便找个房间塞进去——他必须先到馆长办公室(NameNode)申请一个“图书编号”(写入许可)。馆长翻开总索引册,找到一个有空间的房间列表,告诉读者:“你可以把这些分册依次放到 1 号房、3 号房、5 号房。”更聪明的是,馆长还会指定“管线顺序”:先放入 1 号房,再由 1 号房直接转发给 3 号房,3 号房再转发给 5 号房,像接力赛一样,而不是让读者来回跑三趟。
在 HDFS 中,这个“接力赛”就叫 写入流水线(Pipeline)。客户端将数据切分成一个个 数据包(Packet,默认 64KB),沿管线依次发送。第一个 DataNode 收到一个包后,一边落盘一边转发给下一个 DataNode,同时最后一个节点会向上游逐级发送确认(ACK)。整个过程像消防员传递水桶救火——每一级只做“接、传、确认”三件事,效率极高。
这样做最大的好处是减少了客户端与各个 DataNode 之间的网络传输次数。如果让客户端分别给三个副本节点各传一遍,就要消耗三倍的客户端带宽;而流水线方式下,客户端只需传一份数据,由节点间内部转发完成复制。Google 的 GFS 论文中详细描述了这一设计,HDFS 沿用了同样的思想。
图书馆馆长不需要亲自帮读者搬书,读者只需把书交给第一个房间的管理员,后面的房间之间会自动接力。这套流水线设计让“写一本 1TB 的大书”变得像“串一串糖葫芦”一样顺畅——一颗一颗串,串完一整串。而在 AI 时代,训练数据动辄 TB 级,流水线写入的高效性直接决定了数据集准备的速度。
- 数据量文件被切分为数据包依次发送,总数据量不变。
- 管线深度每个 Packet 在管线中经过的节点数,约等于副本数加一。
副本放置策略
图书馆馆长有一个重要的“排书原则”:同一本书的分册副本,不能放在同一栋楼里(否则火灾就全没了),也不能放在治安太差的街区。在分布式系统中,这个“街区”就是 机架(Rack)。一个机架上的多台服务器共享一个网络交换机和电源,如果机架断电或交换机故障,整批机器都会“失联”。
HDFS 默认的副本放置策略是 机架感知(Rack Awareness):第一个副本放在客户端所在机架的一个 DataNode 上(写入最快);第二个副本放在同机架的另一个 DataNode 上(满足机架内冗余,且流量可控);第三个副本放在不同机架的某个 DataNode 上(防止整个机架失效)。这就像图书馆把一本书的三个副本分别放在“本栋楼一层”“本栋楼二层”和“隔壁栋楼”——既兼顾了写入效率,又最大化了容灾能力。
这个策略是“效率”与“安全”的折中。如果三个副本都放同一机架,虽然机架内带宽高、写入快,但一个机架断电就全丢;如果三个副本放三个不同机架,安全但跨机架网络流量巨大。Google 的 GFS 论文和 Hadoop 官方文档都强调“机架感知”是分布式存储的基石——它要求管理员配置网络拓扑,让系统“知道”每台服务器在哪个机架。
回到图书馆:馆长把副本放得“既不太近也不太远”。太近,一起遭殃;太远,调书太慢。这个朴素的“三副本折中”至今仍是分布式存储领域最经典可靠的设计之一——虽然它浪费了 200% 的空间,但换来了“随便挂掉一台机器都不丢数据”的确定性保障。对 AI 训练来说,几 TB 的模型参数和数据集,可靠性远比空间成本更重要。
- 本地副本第一副本写客户端所在节点,省去跨机架传输。
- 机架内第二副本第二副本放同机架另一节点,带宽高。
- 跨机架第三副本第三副本放不同机架,防止整机架故障。
心跳机制与故障
图书馆的每个房间管理员每隔几分钟就会到馆长办公室报到一次:“我还在,书都完好。”如果有管理员连续很久不来报到,馆长就会在索引册上标记该房间“失联”,并安排其他房间重新抄录这些分册的副本。这就是 心跳机制(Heartbeat)——是分布式系统感知“谁还活着”的眼睛。
在 HDFS 中,每个 DataNode 默认每 3 秒 向 NameNode 发送一次心跳,携带自己的存储容量、剩余空间、当前块数量等信息。NameNode 如果连续 10 分钟 没有收到某个 DataNode 的心跳,就判定该节点死亡,然后把该节点上所有块的副本标记为“副本数不足”,并调度其他节点重新复制。这个“3 秒报到、10 分钟判死”的参数设计很讲究:太短会误判(网络抖动);太长会导致系统对故障反应迟钝。
心跳不只是“我活着”的信号,它还是 控制指令的下行通道。NameNode 会在心跳响应中携带命令:如“把某块复制到某节点”“删除某块”“关停某个节点进入维护模式”。这就像馆长在管理员报到时顺便递上一张纸条:“今天去 3 号房抄一本书。”这种“上行状态 + 下行指令”的双向通信模式是所有分布式系统(包括 K8s、ZooKeeper)的通用设计。
图书馆馆长不需要亲自巡查每个房间,管理员的自发报到让“这件事”变得极其轻量。同样,HDFS 的心跳机制让 NameNode 不必主动轮询所有节点,而是被动接收状态——这对上万个节点的集群来说,是唯一可行的规模化解法。如果你在面试中被问“NameNode 怎么知道 DataNode 挂了”,答案就是心跳超时。
- 心跳间隔DataNode 每 3 秒发送一次心跳给 NameNode。
- 超时倍数NameNode 连续 10 分钟未收到心跳,即 3 秒 × 200。
小文件问题
图书馆的“总索引册”有个尴尬的短板:它的纸张是有限的,每一条“某书某章在某房间”的记录都要占一行。如果一个读者存了 1000 本只有 1 页的小册子,索引册就要记 1000 行;但如果他存 10 本很厚的书(每本 100 分册),索引册只需 1000 行记录。索引册的内存空间,取决于文件数量,而不是数据总量。HDFS 里这条规则同样成立——NameNode 的元数据条目与文件/块数量成正比,而与存储的数据量关系不大。
一个小文件(比如 1KB)在 HDFS 中也要占用一个独立的 Block,产生一条元数据记录。每条元数据记录在 NameNode 内存中大约占用 150 字节。1000 万个 1KB 的小文件意味着 1000 万个块,元数据就占了 1.5GB 内存——而它实际存储的数据只有 10GB。相比之下,1000 万个 128MB 的块(即约 1.2PB 数据)的元数据也只有 1.5GB。这就是 小文件问题(Small Files Problem):文件数量才是 NameNode 内存的杀手,而不是数据量。
解决方案也很直接:把许多小文件“打包”成一个大文件——比如使用 HAR(Hadoop Archive)、SequenceFile,或者数据湖方案中的 Hudi/Iceberg,它们本质都是“把小册子合订成一本厚书”,减少索引册的记录条数。在 AI 场景中,海量小图片、小文本片段常常作为训练数据,通常会先用 TFRecord 或 Parquet 格式做 合并(Coalescing),这正是对 HDFS 小文件问题的经典规避。
图书馆馆长最怕的不是书太多,而是“书太碎”。所以优秀的图书管理员会把零散的小册子定期合订成合集,贴上醒目标签。HDFS 用户也养成了同样的习惯:宁可写大文件,也不要写海量小文件。对 AI 工程师而言,理解这一点能避免“数据明明不多,集群却 OOM”的诡异问题。
- 元数据大小每个 Block 约 150 字节元数据。
- 总内存NameNode 内存与块数量成线性关系。
纠删码演进
三副本方案虽然简单可靠,但它太“奢侈”了——存 1TB 数据实际要占 3TB 空间。图书馆馆长会想:“有没有一种办法,既不用存三份,又能在任一分册丢失时把它恢复出来?”答案是数学:纠删码(Erasure Coding, EC)。它把数据切成若干数据块,再计算出若干校验块。任何一块丢了,都可以用剩下的块(数据块+校验块)通过数学运算恢复出来。
纠删码最经典的是 Reed-Solomon(RS)编码,常用配置是 RS(6,3):把数据切成 6 个数据块,计算 3 个校验块,总共 9 块,任意丢失 3 块都能恢复。对比三副本:同样存储 6 个数据块,三副本需要 18 块空间;而 EC 只需 9 块,节省了 50% 的存储空间。代价是什么呢?如果一块丢失,重建时需要读取至少 6 块(副本重建只需读 1 块),网络 IO 和 CPU 开销显著增加。
HDFS 在 3.0 版本中正式引入了 EC 支持(此前主要靠 Apache Ozone/Kudu 等外部系统实现)。工程上的权衡是:冷数据(不常访问)用 EC 省空间,热数据(频繁读写)用副本保性能。这就像图书馆对“新书畅销书”买多本放各层,对“十年没人借的古籍”只存一份原稿+电子扫描即可——访问频率决定冗余策略。GFS 论文中的设计虽然没有完整实现 EC,但后续的 Colossus(GFS 的下一代)已经将纠删码作为核心存储手段。
纠删码是分布式存储从“蛮力冗余”走向“数学冗余”的关键一步。今天的云存储厂商(AWS S3、Azure Blob、阿里云 OSS)几乎全部使用 EC 来降低成本——这也是“对象存储”与 HDFS 在底层架构上的核心差异之一。对 AI 工程师来说,理解 EC 能帮你回答“为什么同样是存 100TB 数据,S3 比自建 HDFS 便宜这么多”。
- 数据块数原始文件被切成 k 个数据块,如 k=6。
- 校验块数通过编码算法生成 m 个校验块,如 m=3。
- 容错能力最多可丢失 m 个块而不丢数据。
- 存储效率有效数据占比为 k/(k+m)。
AI 应用场景
大数据训练集的海量小文件合并
阶段:数据准备(Data Preparation)
解决的问题:AI 训练数据集常包含数百万张小图片或短文本片段,直接写入 HDFS 会导致 NameNode 元数据爆炸、训练读取性能低下。传统方式“小文件直接存”会让集群在几百万文件时陷入卡顿。
具体案例:某自动驾驶公司积累了 500 万张标注图片(每张约 200KB)。数据工程师将这些图片按 TFRecord 格式每 1000 张打包成一个文件,最终只产生 5000 个文件,训练读取吞吐量提升了 5 倍,NameNode 内存占用从可能崩溃的边缘降到安全范围。这个过程本质是对“小文件问题”的工程化解。
模型 checkpoint 的三副本存储
阶段:模型训练与容灾(Training & Checkpointing)
解决的问题:大模型训练(如 GPT 级别)每隔几小时保存一次数 TB 的模型权重。传统单机存储无法容纳且不安全。使用 HDFS 三副本策略,任一节点宕机都不影响 checkpoint 的完整性。
具体案例:某大模型团队使用 10 台 GPU 服务器做分布式训练,每 2 小时将 5TB 的模型权重写入 HDFS(默认三副本)。训练中途某台 DataNode 磁盘损坏,系统通过心跳感知并自动在其他节点重建副本,训练任务无感知继续运行。
冷热数据分层与纠删码存储
阶段:数据归档(Archival)
解决的问题:AI 公司积累了多年训练数据、日志和实验记录,总量达数十 PB,使用三副本成本过高。传统方式“一律三副本”导致存储成本几乎占 IT 预算三分之一。
具体案例:某互联网 AI 部门将超过 180 天未访问的冷数据迁移到启用 EC(6,3) 的 HDFS 归档目录,存储空间占用降低 50%,每年节省约 800 万元服务器采购费用。查询冷数据时读取延迟有轻微上升(需要解码),但对离线分析影响可忽略。
Python 演示
import hashlibimport randomimport time class DataNode: def __init__(self, node_id, rack): self.node_id = node_id self.rack = rack self.blocks = {} self.alive = True self.last_heartbeat = time.time() def heartbeat(self): self.last_heartbeat = time.time() def store_block(self, block_id, data): self.blocks[block_id] = data def is_dead(self, timeout=10): return time.time() - self.last_heartbeat > timeout class NameNode: def __init__(self, replication=3): self.datanodes = [] self.file_table = {} self.replication = replication def register_datanode(self, datanode): self.datanodes.append(datanode) def choose_datanodes(self, rack): same_rack = [dn for dn in self.datanodes if dn.rack == rack] other_rack = [dn for dn in self.datanodes if dn.rack != rack] chosen = [] if same_rack: chosen.append(random.choice(same_rack)) if len(chosen) < self.replication and same_rack: chosen.append(random.choice(same_rack)) while len(chosen) < self.replication: chosen.append(random.choice(other_rack)) return chosen[:self.replication] def write_file(self, path, data): block_size = 64 blocks = [data[i:i + block_size] for i in range(0, len(data), block_size)] locations = [] for idx, block in enumerate(block_id_assign()): if len(locations) == 0: continue block_ids = [hashlib.md5(f"{path}-{i}".encode()).hexdigest()[:8] for i in range(len(blocks))] for bid, block in zip(block_ids, blocks): client_rack = random.choice(list(set(dn.rack for dn in self.datanodes))) targets = self.choose_datanodes(client_rack) for dn in targets: dn.store_block(bid, block) locations.append((bid, [dn.node_id for dn in targets])) self.file_table[path] = locations return locations def check_health(self): dead = [] for dn in self.datanodes: if dn.is_dead(): dead.append(dn.node_id) return dead def block_id_assign(): yield hashlib.md5(b"fake").hexdigest()[:8] def main(): nn = NameNode(replication=3) racks = ["rack-a", "rack-a", "rack-b", "rack-b"] for i in range(4): dn = DataNode(node_id=f"dn-{i}", rack=racks[i]) nn.register_datanode(dn) data = b"hello hdfs! " * 40 locations = nn.write_file("/user/ai/data.bin", data) print("=== 文件块分布 ===") for block_id, nodes in locations: print(f"block {block_id} -> {', '.join(nodes)}") print("=== 心跳检查 ===") time.sleep(1) for dn in nn.datanodes: dn.heartbeat() print(f"存活节点数: {len(nn.datanodes) - len(nn.check_health())}") if __name__ == "__main__": main()
block_size = 64设定块大小(实际 HDFS 为 128MB),演示文件被切分。def choose_datanodes(self, rack)实现机架感知策略:优先同机架、再跨机架。dn.store_block(bid, block)将块数据写入 DataNode 的 blocks 字典,模拟磁盘存储。def check_health(self)遍历所有 DataNode,判定心跳超时的节点并返回。nn.write_file("/user/ai/data.bin", data)模拟客户端通过 NameNode 完成一次文件写入。
常见误区
误区很多人以为 NameNode 保存了一份完整的数据(或数据副本),所以 NameNode 挂了数据就全丢了。实际它是“索引”,不存数据本体。
正解NameNode 只存元数据——文件路径、块 ID、块位置、副本数,总内存通常几 GB 到几十 GB。它不存数据内容。NameNode 挂了会导致“找不到文件”,但 DataNode 上的数据块还在,等 NameNode 恢复后仍可继续使用。就像图书馆的总索引册丢失后,书仍在各个房间里,只是没人知道在哪。需要重建索引(或依赖 JournalNode 恢复)。
为何常见:因为“NameNode“这个名称里的”Name“看似重要,初学者容易把它理解成”数据中枢“,而不是”名字中枢”。
误区有人以为 HDFS 写三副本是客户端拷贝三份,分别发给三个 DataNode,导致客户端带宽占用三倍。
正解实际是流水线写入:客户端写一份给第一个 DataNode,第一个节点边存边转发给第二个,第二个再转发给第三个。客户端只需消耗一份数据的网络带宽。这就像消防员传水桶,不是每个人跑三趟水源。
为何常见:直觉上以为“多个副本 = 多次写入”,忽略了流水线这种经典优化设计。GFS 论文首次描述了该机制。
误区以为心跳设得越短,系统发现故障越快,所以应该设 100ms 而不是 3 秒。
正解心跳太短会给 NameNode 和网络带来巨大压力。上万节点每 100ms 上报一次,每秒 10 万次心跳,NameNode 的 RPC 处理会成瓶颈。3 秒是权衡后的经验值。而且故障检测不仅要快,还要避免误判——网络抖动时短心跳容易误杀健康节点,导致无谓的副本重建风暴。
为何常见:初学者只关注“快”而忽略了分布式系统中的效率和稳定性权衡。
误区以为把块从 128MB 调到 1GB 能省更多空间,因为块越多元数据越多,块少就省了。
正解块大小与磁盘利用率不是直接关系。文件大小不能被块大小整除时,最后一个块会有空间浪费(这部分才是碎片)。增大块可以减少 NameNode 内存压力,但会降低存储灵活性和 MapReduce 并行度。块过大会让单任务处理数据量过大,导致并行度下降。
为何常见:将“块大小”与“存储效率”混淆,实际关键是“文件数量”而非“块大小”。
误区EC 存储效率更高,所以应该把所有数据都用 EC 存,彻底取消副本机制。
正解EC 在读取时需要解码计算,单块丢失重建要读 k 个块,相比三副本直接复制一块,CPU 和网络开销大很多。对热数据(频繁读)、小文件(k+m 块的元数据开销大)不合适。生产实践通常“热数据三副本、冷数据 EC”。S3 等对象存储大量使用 EC,但底层服务器仍保留部分副本以保障低延迟读取。
为何常见:只看到 EC 的空间优势,忽视了它的计算和重建代价。
面试题
Q1. HDFS 中 NameNode 的主要职责是什么?
- A.存储所有的文件数据内容
- B.管理文件系统的元数据← 正确答案
- C.执行 MapReduce 计算任务
- D.负责数据的加密解密
答案:B。NameNode 相当于图书馆的“总索引册”,它只管理元数据(文件路径、块位置、副本数),不存数据本体,也不执行计算任务。存储数据的是 DataNode。选项 A 混淆了 NameNode 与 DataNode 的职责。
Q2. HDFS 默认的块大小是多少?
- A.4KB
- B.64MB
- C.128MB← 正确答案
- D.1GB
答案:C。HDFS 默认块大小为 128MB(Hadoop 2.x 之后),早期版本是 64MB。4KB 是传统本地文件系统的块大小,1GB 则太大,会严重影响并行度。块越大元数据越少,但并行度越低。
Q3. HDFS 三副本的默认放置策略是?
- A.三个副本分别放在三个不同机架
- B.两个副本同机架,一个副本跨机架← 正确答案
- C.三个副本都放在客户端所在机架
- D.随机放置在任何 DataNode 上
答案:B。默认策略是“第 1 副本在客户端所在节点,第 2 副本在同机架另一节点,第 3 副本在跨机架节点”。三个全放不同机架虽安全但跨机架网络开销大;全放同机架又无法容忍机架故障。B 是效率与安全的经典折中。
Q4. 关于 HDFS 写入流水线,下列说法正确的是?
- A.客户端分别向每个副本节点独立传输数据
- B.客户端只向第一个 DataNode 传输,后续节点间自行复制← 正确答案
- C.副本数量由客户端在写入时决定
- D.写入过程不需要 NameNode 参与
答案:B。流水线是 HDFS/GFS 的核心设计之一:客户端将数据包发给第一个 DataNode,第一个节点存好后再转发给第二个,依次传递,最后逐级确认。这样客户端只需消耗一份数据的带宽。选项 D 错误,写请求必须先向 NameNode 申请。
Q5. HDFS 中 DataNode 心跳超时默认判定为节点死亡的时间是?
- A.3 秒
- B.30 秒
- C.10 分钟← 正确答案
- D.1 小时
答案:C。HDFS 中 DataNode 每 3 秒发送一次心跳,NameNode 若连续 10 分钟(600 秒)未收到某节点心跳才判定其死亡。3 秒是心跳间隔而非超时时间。10 分钟是经验值,兼顾故障检测速度和误判率。
Q6. HDFS 中“小文件问题”会导致哪些影响?
- A.NameNode 内存被大量元数据占满← 正确答案
- B.文件读写性能急剧下降← 正确答案
- C.磁盘空间利用率下降← 正确答案
- D.DataNode 存储空间不足
答案:ABC。每个小文件至少占一个块,产生一条元数据,消耗 NameNode 内存;大量小文件让读写频繁切换,性能下降;最后一个小块不足 128MB 会浪费磁盘空间。这三点是小文件问题的核心影响。选项 D 的“存储空间不足”不是小文件导致的。
Q7. 在 Reed-Solomon 编码 RS(6,3) 中,存储空间利用率和容错能力分别是?
- A.67%,可容忍丢失 3 个块← 正确答案
- B.50%,可容忍丢失 6 个块
- C.75%,可容忍丢失 9 个块
- D.100%,可容忍丢失 3 个块
答案:A。RS(6,3) 表示 6 个数据块 + 3 个校验块,总存储 9 块,数据占 6/9≈67%。最多可容忍丢失任意 3 块(m=3)。B 选项数据错误,C 是“仅存副本”的概念,D 是“无冗余”的概念。EC 相对三副本(30% 利用率)显著节省空间。
Q8. 关于 HDFS 与 GFS 的共同设计思想,下列说法正确的是?
- A.元数据集中管理,数据分散存储← 正确答案
- B.通过心跳机制感知节点故障← 正确答案
- C.移动计算比移动数据更高效← 正确答案
- D.所有副本必须跨机架放置
答案:ABC。GFS 与 HDFS 都遵循“单一元数据节点 + 大量数据节点”的模式,都用心跳探活,都强调将计算任务调度到数据所在节点(数据本地性)。但 D 错误——默认策略不是“所有副本跨机架”,而是两副本同机架、一副本跨机架。
Q9. HDFS 中数据块默认复制因子(副本数)是多少?
- A.1
- B.2
- C.3← 正确答案
- D.5
答案:C。HDFS 默认副本数为 3,这是可靠性与成本权衡的结果。1 份太危险,2 份在机架故障时仍可能全丢,3 份可以容忍单机架故障。这个配置可通过 dfs.replication 参数调整,但生产环境默认 3 是业界共识。
Q10. 在 HDFS 数据写入过程中,哪些组件参与了确认应答(ACK)?
- A.客户端(Client)← 正确答案
- B.NameNode← 正确答案
- C.第一个 DataNode
- D.最后一个 DataNode← 正确答案
答案:ABD。数据包沿管线从第一个 DataNode 传到最后一个,最后一个节点写完返回 ACK,逐级回传到客户端。NameNode 参与的是写入许可和块分配阶段,不参与数据包的 ACK 链。选项 B 的 NameNode 在 ACK 链路中不出现,这是流水线设计的要点。