在 HDFS 中,block 是最顶层的存储单元,默认大小为 128MB。这个设计背后有几个关键考量:
寻址效率优化:较大的块大小可以减少 NameNode 需要维护的元数据量。假设一个 1TB 的文件,使用 128MB 块只需要约 8000 个块记录,而如果使用 4MB 块则需要 25 万条记录。
并行计算适配:HDFS 是为 Hadoop MapReduce 设计的,较大的块大小可以确保每个 Map 任务有足够的数据处理量。过小的块会导致任务启动开销占比过高。
实际配置建议:
注意:修改块大小需要重启集群,且只对新写入的数据生效。已有数据会保持原有的块大小。
Packet 是客户端与 DataNode 之间数据传输的基本单位,默认 64KB。这个设计解决了几个关键问题:
网络效率:过小的传输单元会导致 TCP/IP 协议头开销占比过高。64KB 在典型以太网 MTU(1500字节)下可以充分利用网络带宽。
流水线优化:在 pipeline 写入过程中,当一个 DataNode 开始处理当前 packet 时,下一个 packet 已经可以开始传输,实现并行化。
技术细节:
Chunk 是 HDFS 中最小的数据验证单元,固定 512 字节 + 4 字节校验和。这个精妙设计带来了:
细粒度校验:相比对整个 block 做校验,chunk 级校验可以精确到 512 字节的损坏检测。
空间效率:4字节校验和(CRC-32)只增加 0.78% 的存储开销,远低于常见的副本策略。
计算效率:现代 CPU 可以高效计算 CRC32,SSE4.2 指令集甚至提供硬件加速。
实际存储示例:
code复制| chunk1(512B) | CRC32(4B) | chunk2(512B) | CRC32(4B) | ... |
当客户端调用 create() 方法时:
NameNode 会执行以下检查:
关键元数据操作:
常见问题:如果客户端在写入过程中崩溃,NameNode 会等待 lease 超时(默认1小时)后自动回收资源。
当客户端开始写入数据时:
第一个 block 的分配流程:
机架感知策略细节:
数据在 pipeline 中的流动过程:
客户端内部机制:
BufferedOutputStream 中dataQueueackQueueDataNode 处理流程:
错误处理机制:
当客户端调用 close() 时:
确保所有数据都刷出:
NameNode 最终确认:
NameNode 在响应读请求时:
返回的信息包含:
客户端缓存策略:
ClientProtocol.getBlockLocations 获取更新客户端选择 DataNode 的考虑因素:
优先级顺序:
负载均衡:
读取时的校验过程:
客户端校验流程:
关键配置参数:
dfs.bytes-per-checksum:512(默认)dfs.client.read.shortcircuit:是否启用短路读关键配置参数:
xml复制<property>
<name>dfs.client.block.write.retries</name>
<value>3</value>
</property>
<property>
<name>dfs.client.block.write.replace-datanode-on-failure.policy</name>
<value>DEFAULT</value>
</property>
实践经验:
dfs.client.write.packet.size(但不要超过 MTU)dfs.datanode.max.xcievers 足够大短路读配置:
xml复制<property>
<name>dfs.client.read.shortcircuit</name>
<value>true</value>
</property>
<property>
<name>dfs.domain.socket.path</name>
<value>/var/run/hadoop-hdfs/dn_socket</value>
</property>
缓存策略:
dfs.namenode.path.based.cache.refresh.interval.ms)写入失败检查清单:
hdfs dfsadmin -report 检查节点状态读取失败检查清单:
hdfs fsck)文件级别:
.checksum 文件存储完整校验和hadoop fs -checksum 命令验证Block 级别:
.meta 文件DataNode 会定期执行:
块扫描:
dfs.datanode.scan.period.hours)损坏处理:
读时验证:
dfs.client.read.verify)写时验证:
dfs.checksum.type)