HDFS Block
- 为什么hdfs上文件的存储不用原始文件,而使用block
- 为什么block块一般比较大, 例如128M, 256M
- 如何通过namenode读取数据 (本地读取和远程读取)
- block/chunk/packet 术语
1.为什么hdfs上文件的存储不用原始文件,而使用block
- 作为一种对原始文件的抽象, 可以屏蔽掉因为物理磁盘的限制而造成无法存储超级大的文件的问题
- 简化了的存储子系统, 因为块的大小是固定的, 一些管理计算就不再依赖于文件, 而是依赖于块的大小 (当然元数据信息的也可以剥离出来, 方便管理)
- 便于进行容错 (由于元数据的分离, 被拆分到多个块中的文件, 具有更高的容错)
2. 为什么block块一般比较大, 例如128M, 256M
由于hadoop中存储的的数据更多的应用场景是全量读取, 所以更大的块有更高的读取速度
例如: seekTime: 10ms, transfer rate: 100MB/s
block 大小 | 个数 | 读取耗时(s) |
---|---|---|
100MB | 1 | 100MB/100MB/s + 10ms = 1.01s |
10MB | 10 | (10MB/100MB/s + 10ms) * 10 = 1.1s |
从上可以看出较大的block块有更好的读取性能 (seekTime不会因为block的大小而受到影响)
hdfs fsck / -files -blocks
3. 如何通过namenode读取数据 (本地读取和远程读取)
3.1 读数据
client_read_file.png从上图可以看出通过FDDataInputStream
屏蔽掉了具体底层的block, 如果是多个block的话,读完一个之后将关闭和datanode的链接,并和另一个datanode建立连接开始读取它上面的block
3.2 读容错
DFSInputStream
和 datanode通信发生错误时 (此时不论datanode出了什么问题, 可能是宕机了), DFSInputStream
将重试含有该block的其他datanode,从其上读取数据, 并将上次错误datanode记录下来以防无限重试
3.3 写数据
client_write_file.png同样的写文件的时候hdfs通过DFSOutputStream
来屏蔽掉了具体的细节
写数据的时候是DFSOutputStream
会将要写的数据切分成多个packet, 将其写入data queue
, DataStreamer
来消费这个队列,伴随着向namenode申请block地址, 并由datanode自己去完成副本的建立
DFSOutputStream
同时维护一个ack queue
用来判断哪些packet已经同步好了
3.4 写容错
当一个datanode宕掉的时候 (副本为3)
- pipeline将结束掉, 任何
ack queue
的数据将加入到data queue
中 - 如果datanode恢复过来, 要删除之前写的坏数据
- 从完好的2个datanode建立pipeline (一共2个datanode) (后续会再往该pipeline中添加datanode)
- namenode检测到副本数不够, 将对这个块进行复制
4. block/chunk/packet 术语
block: hdfs存储的最小单位
chunk: block被切成了一个个的chunk,并且每个都有一个checksum
packet: 一组用于传输的chunk, 包含一个header, 多个checksum和多个数据内容
ref:
- Hadoop The Definitive Guide
- https://stackoverflow.com/questions/22353122/why-is-a-block-in-hdfs-so-large