Hadoop 生态面试专题
概述
面试官考察大数据基础,通常围绕 HDFS、YARN、MapReduce、HBase、ZooKeeper 五条主线出题:原理理解、流程细节、场景设计、故障排查各占一头。本文按模块整理高频问答,答案直击要点,方便自查与复盘。
一、HDFS 高频问答
Q1:HDFS 写入一个 128MB 文件,流程是怎样的?
1. 客户端向 NameNode 请求创建文件(写数据块 0)
2. NameNode 校验权限与配额,返回第一批 DataNode 列表
3. 客户端建立与 DataNode 的管线(Pipeline),分块写入
4. 每块写完后逐级 ACK:DataNode3 → DataNode2 → DataNode1 → 客户端
5. 当前块写完,请求下一批 DataNode,重复直到写完
6. 全部写完,客户端 close,NameNode 完成文件提交关键点:数据以 64KB 包(Packet)流式传输;ACK 逐级回传保证副本一致性。
Q2:NameNode 宕机会发生什么?如何避免?
- 无 HA:NameNode 单点,宕机后整个集群不可读写(数据不丢,元数据在 FsImage/Edits)。
- 有 HA:QJM 共享日志 + ZKFC 自动切换,Standby 在 30 秒级接管。
Q3:安全模式(SafeMode)是什么?
NameNode 启动时进入安全模式:只读不写,等待 DataNode 上报块报告,副本数达到阈值(默认 0.999)后自动退出。运维可 hdfs dfsadmin -safemode enter/leave/get 手动控制。
Q4:副本放置策略为什么是"同机架 2 副本 + 异机架 1 副本"?
- 同机架 2 副本:机架内带宽高,读写快,且机架内故障可恢复。
- 异机架 1 副本:容忍整机架故障,兼顾安全性与写性能。
- 综合:3 副本在可靠性(容忍 1 机架挂)与性能(跨机架流量少)间取得平衡。
Q5:小文件问题如何解决?
大量小文件会撑爆 NameNode 内存(每个文件约 150 字节元数据),并让 MapReduce 任务数失控。方案:
- 合并小文件(Hive 的
concatenate、SequenceFile)。 - 使用 Hudi/Iceberg 等表格式自动管理文件数。
- 写入侧控制:Flume 调大滚动阈值、批处理合并输出。
二、YARN 高频问答
Q1:YARN 的资源管理模型?
- ResourceManager:全局调度,管理队列与资源。
- NodeManager:单节点资源(内存/CPU)代理,启动 Container。
- ApplicationMaster:每个应用一个,负责申请资源与任务调度。
- Container:资源分配的最小单元(
yarn.nodemanager.resource.memory-mb/cpu-vcores)。
Q2:FIFO / Capacity / Fair 调度器如何选择?
| 调度器 | 特点 | 适用 |
|---|---|---|
| FIFO | 先进先出,简单但大作业阻塞小作业 | 单用户测试 |
| Capacity | 队列容量隔离 + 弹性借用 + 抢占 | 多团队生产(默认) |
| Fair | 公平分享,短作业响应快 | 多用户混合负载 |
Q3:AM 挂了会怎样?
AM 由 RM 监督,挂掉后 RM 按 mapreduce.job.recovery 配置决定:可重启的 AM 从最近 checkpoint 恢复任务,否则整个作业失败重跑。容器失败由 AM 自行重试申请。
Q4:如何提高 MapReduce 作业并行度?
- 调大
mapreduce.map.memory.mb后能同时跑的 Container 数受节点资源上限约束。 - 增加 Reducer 数
-D mapreduce.job.reduces=N(与分区目标数匹配)。 - 检查是否有空闲资源被队列占用(Capacity 队列弹性借用)。
三、MapReduce 高频问答
Q1:MapReduce 全流程?
Split 分片 → Map → 分区/排序 → Combiner → 溢写合并(Spill/Merge)
→ Shuffle 拉取 → Reduce 归并 → 输出Q2:Shuffle 为什么要排序?Sort 发生在哪里?
排序是分区内按 Key 排序,目的是让相同 Key 聚集,便于 Reduce 归并。发生两处:
- Map 端:溢写前在内存缓冲区按分区 + Key 排序,溢写文件归并时再次归并排序。
- Reduce 端:拉取多个 Map 输出后按 Key 归并。
Q3:Combiner 和 Partitioner 的区别?
- Combiner:Map 端的本地 Reduce,先合并一部分数据,减少网络传输(如求和可合并,求平均值不可)。
- Partitioner:决定每条数据进入哪个 Reduce 分区,默认按 Key 哈希取模。
Q4:数据倾斜如何定位与解决?
定位:看 Reduce 阶段各任务处理量差异巨大,或单个任务长时间运行。
| 方案 | 说明 |
|---|---|
| 两阶段聚合 | 先局部聚合打散 Key,再全局聚合 |
| 预过滤 | Join 前过滤掉无效数据(如空 Key) |
| 随机前缀 + 扩容 | 对热点 Key 加随机前缀后 Join |
| 优化 Join 策略 | 小表用 MapJoin 广播 |
Q5:Reduce 任务数如何确定?
- 默认 1 个,通常按目标分区数设置。
- 输出为动态分区时,Reducer 数影响输出文件数。
- 与集群容量平衡:过多 Reducer 造成小文件与调度开销。
四、HBase 高频问答
Q1:RowKey 设计要点?
- 散列均匀(加盐/哈希前缀)避免热点。
- 长度适中,避免过长浪费。
- 利用有序性,让范围查询共享前缀。
- 避免单调递增主键。
Q2:写一条数据经历了什么?
Put → WAL 追加 → MemStore → 返回成功 → (Flush)→ StoreFile/HFileQ3:为什么 HBase 写比读快?
写走顺序追加(WAL + MemStore),批量落盘;读要查 MemStore + BlockCache + 多个 StoreFile,可能触发 Compaction 前的多次磁盘 IO。另外随机读放大比随机写明显。
Q4:RegionServer 宕机数据会丢吗?
不会。MemStore 中未落盘数据在 WAL 中有记录,RegionServer 恢复后或 Region 转移到其他节点后,从 WAL 重放恢复。
Q5:热点问题怎么治理?
- 根源:RowKey 设计(单调递增/不加盐)。
- 治理:加盐前缀 + 预分区;临时拆分热点 Region;观察 Region 分布调均衡。
五、ZooKeeper 高频问答
Q1:ZooKeeper 为什么能保证一致性?
ZAB 协议:所有写请求经 Leader 分配全局递增 ZXID 并广播,过半节点 ACK 才提交;Follower 按 ZXID 顺序同步。读可在任意节点返回,属最终一致。
Q2:Leader 选举的投票比较规则?
ZXID 大的优先(数据最新),ZXID 相同则 myid 大的优先,获得过半投票者成为 Leader。
Q3:集群最少几台?为什么是奇数?
- 过半可用:2 台无意义(任一挂都达不到 2/2 的过半,1 挂即不可用)。
- 3 容忍 1、5 容忍 2,奇数节点在容错数相同下成本最低。
Q4:Watch 机制的一次性问题?
Watcher 只触发一次,触发后失效,需要重新注册才能继续监听,防止事件堆积造成风暴。
Q5:分布式锁如何实现?和 Redis 锁比?
- 实现:
/locks下建临时顺序节点,取最小序号,Watch 前一个节点,会话结束自动删除释放。 - 对比:ZK 锁无过期误删、无主从切换丢失问题,更可靠但吞吐低;Redis 锁性能高、实现简单,极端场景(主从切换)可能丢锁。
六、场景设计题
场景一:电商订单表每日增量同步到 HDFS
方案:Sqoop lastmodified 增量导入 → 按日期分区落地 /ods/order/dt=xxx
Oozie/DolphinScheduler 定时调度,失败重试 + 数据校验考察点:增量策略、分区设计、调度编排。
场景二:亿级用户行为日志实时采集
方案:应用端 → Kafka → Flume/Logstash 或直写 Kafka → HDFS/实时链路
Flume taildir 断点续传,多级聚合减少直连 HDFS 的压力考察点:采集可靠性、断点续传、多级拓扑。
场景三:用户订单明细实时点查(按订单号)
方案:HBase + RowKey=订单号(预分区 + 加盐)→ 毫秒级 Get
关联查询建 Phoenix 二级索引考察点:RowKey 设计、HBase 场景适用性判断。
七、一句话速记
| 模块 | 一句话 |
|---|---|
| HDFS | 元数据在 NameNode 内存,数据三分块在 DataNode,HA 靠 QJM+ZKFC |
| YARN | RM 管全局、NM 管节点、AM 管作业、Container 是资源单元 |
| MapReduce | Split → Map → Shuffle(分区/排序/合并)→ Reduce |
| HBase | 写 WAL+MemStore、读合并多源,RowKey 决定生死 |
| ZooKeeper | ZAB 过半提交、临时节点管在线状态、Watch 一次性 |