深入理解 HDFS(一):Block

HDFS 使用类似 Linux 文件目录结构来抽象表示存储的数据结构,使用 inode 来表示目录或文件。

当你通过 hdfs dfs -copyFromLoacl my.log / 命令上传一份日志文件,还是使用计算引擎存储临时状态或计算结果,你看见 HDFS 目录上的所有文件,在实际存储时都会被切割加工成一个个的块(默认大小 128M,快还有副本默认 3 个),最后这些 block 的元数据信息会统一存储在 NameNode 中。

1. 什么是 Block

上面所说的块就是我们今天的主角 Block:HDFS 存储数据的基本单元,其核心属性有:

  • id: 唯一标识,long 类型,默认情况下从 1073741824(2 的 30 次方)开始,每创建 1 个 block 自增 1;
  • blockName: 块的名称,字符串 blk_ + id,例如 blk_1073741825、blk_1073741826 等;
  • numBytes: 块的大小,long 类型,通常情况下 <= 128M,小于的原因要么文件本身大小 < 128M 或者是文件对应 blocks 的最后一块;
  • generationStamp: 邮戳信息,long 类型,NameNode 中 GenerationStamp 类负责生成默认从 1000 开始,每创建 1 个 Block 自增 1,用于 DataNode 重新加入集群时检测过时的副本;
  • bcId: 块集合 id 即 文件 inodeId,long 类型,NameNode 中 INodeId 负责生成默认从 16384(2 的 14 次方)开始,根目录 / 使用 16385,之后每创建目录或文件自增 1。

2. 从文件到 Block

有的文件只有 1 个 block,有的却有多个,为什么会有多个内部切割逻辑是什么? 假设变量 blockSize 表示 Block 默认大小,这里讨论 2 种情景:

情景 1:文件大小 <= blockSize

对于大小 <= blockSize 的文件只有 1 个 block。

情景 2:文件大小 > blockSize

对于大小 > blockSize 的文件至少有 2 个 block,block 数量计算可以理解为:Double.valueOf(Math.ceil( 文件大小 * 1.0 / blockSize)).longValue()

3. Block 物理存储

3.1 准备工作

为了调研做了一些前期准备工作:

  1. 搭建 hadoop 伪分布式集群;

  2. 查看 hadoop 集群状态;

  3. 上传文件到 HDFS;

  4. 查看上传文件元数据信息。

参照 HDFS 官网本地搭建了伪分布式集群,通过使用命令 hdfs dfsadmin -report 可见集群状态正常:

本地有个 697M 的 hadoop 安装文件,上传到 HDFS,使用相关命令进行查看:

shell 复制代码
# 创建 /tmp 目录hdfs dfs -mkdir /tmp# 上传文件hdfs dfs -copyFromLocal hadoop-3.3.6.tar.gz /tmp# 查看是否上传成功hdfs dfs -ls -h /tmp# 查看实际的 Blockhdfs fsck /tmp/hadoop-3.3.6.tar.gz -files -locations -blocks

复制代码

3.2 物理存储位置

那 HDFS 实际落盘文件存储在什么地方?

bash 复制代码
find /tmp -iname "blk_1073741825"# 输出如下:#/tmp/hadoop-root/dfs/data/current/BP-473427094-127.0.0.1-1690621293256/current/finalized/subdir0/subdir0/blk_1073741825
cd /tmp/hadoop-root/dfs/data/current/BP-473427094-127.0.0.1-1690621293256/current/finalized/subdir0/subdir0
ls -lh

复制代码

从上图可以看出前 5 个 block 大小都是 128M,最后一个 block 是 57 M:697 - 128 * 5(MB)和预想的一致,此时还发现每个 block 都会对应 1 个数据文件和 1 个元数据文件,文件命名方式:

  • block 数据文件命名:blk_ + blockId
  • block 元数据文件命名:blk_ + blockId + _ + generationStamp + .meta

3.3 Block 数据文件验证

那 block 对应的数据文件仅仅是按 128M 进行切割吗?HDFS 有没有做其它的处理?我们可以使用 split 命令按照 128M 切割原始文件:

shell 复制代码
# 按照大小 128M 切割文件,文件切割后split -b 128M hadoop-3.3.6.tar.gz# 对切割后的文件计算 md5ls | grep xa | grep -v 'grep' | xargs md5sum

复制代码

之后计算每个 block 数据文件的 md5

bash 复制代码
ls -lhls | grep blk | grep -Ev 'grep|*.meta' | xargs md5sum

复制代码

两种结果进行对比可以看出,每种方式每个文件的 md5 都是互相匹配,所以说明:HDFS 仅仅是按照 128M 做了切割。

3.4 有趣的实验:128M + 1 个字节的文件有几个 Block ?

如果上传 1 个 128M + 1 个字节的文件后,生成几个 block ?

shell 复制代码
# 生成 128M + 1 字节的文件,文件大小:128 * 1024 * 1024 + 1 = 134217729fio -filename=/root/128m1b.txt -direct=1 -ioengine=libaio -bs=4k -size=134217729 -numjobs=1 -iodepth=16 -runtime=1 -thread -rw=write -group_reporting -name="write_test"
# 上传到 hdfs hdfs dfs -copyFromLocal 128m1b.txt /tmp
# 查看究竟是几个 blockhdfs fsck /tmp/128m1b.txt -files -locations -blocks

复制代码

看来 HDFS 切割 block 还是很认真的。

4. 下载 NameNode 元数据信息

NameNode 存储元数据信息的文件前缀为 fsimage_,下面定位下目录:

shell 复制代码
# 定位目录find /tmp -iname "fsimage_*"
# 定位个最大编号的 fsimagels -alht /tmp/hadoop-root/dfs/name/current/
# 进入 home 目录,不要对 hadoop 工作目录造成影响cd ~
# 导出元数据信息到 xml 文件中hdfs oiv -i /tmp/hadoop-root/dfs/name/current/fsimage_0000000000000000078 -o fsimage.xml -p XML
# 打开 fsimage.xml 文件vim fsimage.xml  # xml格式化 :%!xmllint --format %

复制代码

打开 fsimage.xml 同样可以定位到 block 信息:

最后,大家如果有问题,欢迎留言讨论!

版权声明: 本文为 稀土掘金 作者【冰心的小屋】的原创文章。

原文链接: juejin.cn/post/726186...

文章转载请联系作者。

相关推荐
浊酒南街10 小时前
hive中map_concat函数介绍
数据仓库·hive·hadoop
qq_4465980413 小时前
contos7.9 部署3节点 hadoop3.4 集群 非高可用
大数据·hadoop
雷神乐乐13 小时前
Flume学习
hadoop·学习·flume
huaqianzkh15 小时前
了解Hadoop:大数据处理的核心框架
大数据·hadoop·分布式
Kika写代码16 小时前
【Hadoop】【hdfs】【大数据技术基础】实验三 HDFS 基础编程实验
大数据·hadoop·hdfs
heromps20 小时前
hadoop报错找不到主类
大数据·hadoop·eclipse
静听山水1 天前
基于ECS实例搭建Hadoop环境
hadoop
三劫散仙2 天前
Hadoop + Hive + Apache Ranger 源码编译记录
hive·hadoop·hbase·ranger
zmd-zk2 天前
hive中windows子句的使用
大数据·数据仓库·hive·hadoop·windows·分布式·big data
大数据魔法师2 天前
Hadoop生态圈框架部署(六)- HBase完全分布式部署
hadoop·分布式·hbase