1. HDFS上默认块大小和副本数
1.1 对块的理解
hadoop2.x中,hdfs-site.xml
中的dfs.blocksize
参数表示hdfs的块大小,默认值为134217728(bytes),即128M。它是hdfs存储处理数据的最小单元,可以根据实际需求改变块大小,但是一般不建议这么做。
文件 | 参数 | 默认值 | 描述 |
---|---|---|---|
hdfs-site.xml | dfs.blocksize | 134217728 | 块大小(byte) |
块大小为什么要设计成128M
是为了最小化寻址时间,目前磁盘的传输速率普遍是在100M/S左右,所以设计成128M每块。
1.2 对副本的理解
副本的设置让hadoop具备高可靠性的特点,数据不会轻易丢失。副本是存储在datanode中的,由hdfs-default.xml文件的dfs.replication参数控制,伪分布式部署是1份,集群部署是3份。
文件 | 参数 | 默认值 | 描述 |
---|---|---|---|
hdfs-site.xml | dfs.replication | 3 | HDFS上文件副本数 |
1.3 要点
- 数据上传HDFS,不可能凭空增加新的数据内容。
- dfs.blocksize,规格,未满一个规格,也会占用一个block文件。
1.4 例子
** 例子:**
假设hdfs默认块大小128M,副本数为3,一个文件260M,上传到HDFS上,文件分为3个块(128M+128M+4M)存储,又因为是3副本,实际会占用9个块,总共是260*3=780M的大小
** 题:**
一个文件160M,块大小128M ,副本数为2。请问:实际存储多少块,实际多少存储空间?答:存储4块,320M。
2. 小文件
一般来说,小文件是文件大小小于10M的数据,由于hadoop的架构特性,它只能有一台主namenode,如果小文件特别多的话,小文件占用的块也特别多,namenode需要维护的块的元数据信息的数量也多,所以我们一般把小文件合并成大文件再放到hdfs上,也有上传hdfs后再合并的。通过减少小文件来减少nn维护的块的元数据数量。可以通过脚本定期扫描hdfs上是否存在小于10M的文件,并对其进行合并。
3. HDFS架构
HDFS采用主从(Master/Slave)架构来存储数据,这种架构主要由四个部分组成,分别为NameNode、SecondaryNameNode、DataNode和HDFS Client。一个HDFS集群是由一个NameNode和一定数目的DataNode组成的。NameNode是一个中心服务器,负责管理文件系统的名字空间 (Namespace )及客户端对文件的访问。集群中的DataNode一般是一个节点运行一个DataNode进程,负责管理它所在节点上的存储。
3.1 NameNode
NameNode就是HDFS的Master架构,主要负责HDFS文件系统的管理工作,具体包括名称空间(namespace)管理,文件Block管理。
- 名称空间(namespace)管理:它维护着文件系统树(filesystem tree)以及文件树中所有的文件和文件夹的元数据(metadata)。管理这些信息的文件有两个,分别是Namespace镜像文件(fsimage)和操作日志文件(edit log),这些信息被Cache在RAM中,当然,这两个文件也会被持久化存储在本地硬盘。
- 文件Block管理:Namenode记录着每个文件中各个块所在的数据节点的位置信息(元数据信息),从NameNode中你可以获得每个文件的每个块所在的DataNode。但是他并不持久化存储这些信息,因为这些信息NameNode会在每次启动系统时动态地重建这些信息。
这些元数据信息主要为:
"文件名 -> 数据块"映射
"数据块 -> DataNode列表"映射
其中,"文件名 -> 数据块"保存在磁盘上进行持久化存储,需要注意的是NameNode上不保存"数据块 -> DataNode列表"映射,该列表是通过DataNode上报给NameNode建立起来的。NameNode执行文件系统的名称空间(namespace)操作,例如打开、关闭、重命名文件和目录,同时决定文件数据块到具体DataNode节点的映射。
注意:
- NN的fsimage的个数默认是保留2个,控制的参数是hdfs-default.xml文件的dfs.namenode.num.checkpoints.retained参数
文件 | 参数 | 默认值 | 描述 |
---|---|---|---|
hdfs-site.xml | dfs.namenode.num.checkpoints.retained | 2 | NN和SNN上fsimage_*文件保留数目 |
hdfs-site.xml | dfs.namenode.num.extra.edits.retained | 1000000 | NN和SNN上edits文件保留数目,默认是1百万 |
3.2 SecondaryNameNode
SecondaryNameNode主要是定时对NameNode的数据snapshots进行备份的,这样可尽量降低NameNode崩溃之后导致数据丢失的风险,其所做的工作就是从NameNode获得fsimage和edits后把两者重新合并发给NameNode。这样,既能减轻NameNode的负担又能安全地备份,一旦HDFS的Master架构失效,就可以借助Secondary NameNode进行数据恢复。但是辅助Namenode总是落后于主Namenode,所以在Namenode宕机时,数据丢失是不可避免的。通常,Secondary Namenode 运行在一个单独的物理机上,因为合并操作需要占用大量的CPU时间以及和Namenode相当的内存。
定期合并FSImage和Editlog的周期时间是由hdfs-site.xml
文件的dfs.namenode.checkpoint.period
属性决定的,默认一小时合并一次,同时如果Editlog操作日志记录满 1000000条也会触发合并机制,由dfs.namenode.checkpoint.txns
属性控制,两者满足一个即可。
文件 | 参数 | 默认值 | 描述 |
---|---|---|---|
hdfs-site.xml | dfs.namenode.checkpoint.period | 3600 | 两个周期性检查点之间的间隔(秒) |
hdfs-site.xml | dfs.namenode.checkpoint.txns | 1000000 | 两个周期性检查点之间的名称空间记录数 |
SNN元数据同步流程
- SecondaryNameNode引导NameNode滚动更新操作日志,并开始将新的操作日志写进edits.new。
- SecondaryNameNode将NameNode的fsimage文件和edits文件复制到本地的检查点目录。
- SecondaryNameNode将fsimage文件导入内存,编辑日志Edits文件,将其合并生成fsimage.ckpt文件,并将新的fsimage.ckpt文件压缩后写入磁盘。
- SecondaryNameNode将新的fsimage.ckpt文件传回NameNode。
- NameNode在接收新的fsimage.ckpt文件后,将fsimage.ckpt替换为fsimage,然后直接加载和启用该文件
- NameNode将edits.new更名为edits。
3.3 DataNode
DataNode是负责存储数据的组件,一个数据块Block会在多个DataNode中进行冗余备份;而一个DataNode对于一个块最多只包含一个备份。所以可以简单地认为DataNode上存储了数据块ID和数据块内容,以及它们的映射关系。一个HDFS集群可能包含上千个DataNode节点,这些DataNode定时和NameNode进行通信,接受NameNode的指令,为了减轻NameNode的负担,NameNode上并不永久保存哪个DataNode上有哪些数据块的信息,而是通过DataNode启动时的上报来更新NameNode上的映射表。DataNode和NameNode建立连接后,就会不断地和NameNode保持联系,反馈信息中也包含了NameNode对DataNode的一些命令,如删除数据或者把数据块复制到另一个DataNode。
- 应该注意的是:NameNode不会发起到DataNode的请求,在这个通信过程中,它们严格遵从客户端/服务器架构。
DataNode也作为服务器接受来自客户端的访问,处理数据块读/写请求。DataNode之间还会相互通信,执行数据块复制任务,同时,在客户端执行写操作的时候,DataNode之间需要相互配合,以保证写操作的一致性。
DataNode是文件系统Worker中的节点,用来执行具体的任务:存储文件块,被客户端和NameNode调用。同时,它会通过心跳(Heartbeat)定时向NameNode发送所存储的文件块信息,并隔一段时间进行内存和磁盘数据集块校验,更新内存中的信息和磁盘中信息的不一致情况(默认6小时,生产环境是情况缩短,建议改为3小时)
文件 | 参数 | 默认值 | 描述 |
---|---|---|---|
hdfs-site.xml | dfs.heartbeat.interval | 3 | datanode心跳上报间隔(秒) |
hdfs-site.xml | dfs.datanode.directoryscan.interval | 21600 | DataNode扫描数据目录并协调内存块和磁盘块之间的差异的时间间隔(秒)。 |
** 补充**
当文件块损坏,且由于块自我修复的间隔时间还没到,可以进行手动修复:
hdfs debug的作用是在多副本的环境下手动修复元数据、块或者副本,我们在这里只说修改副本,这里的xxx是指副本路径,该路径必须驻留在HDFS文件系统上。
[ruoze@rzdata001 ~]$ which hdfs
~/app/hadoop/bin/hdfs
[ruoze@rzdata001 ~]$ hdfs | grep debug
[ruoze@rzdata001 ~]$ # 帮助命令找不到debug的信息,但是hdfs debug 命令缺失存在
使用方法:hdfs debug recoverLease -path /xxx/yyy/zzzfile -retries 10
但是有可能: 手动修复 + 自动修复都是失败的.所以需要建立数据重刷机制。
3.4 client
在实际的开发环境中,在集群环境中开发往往存在很多安全隐患,例如集群文件被误删等等,所以一般的开发工作都是本地完成开发的。本地做MR开发时,由于没有hadoop环境,所以调试工作往往变的很难进行,所以在本地搭建一个hadoop client,不仅能提供本地调试环境,还能从直接从本地访问到hdfs 数据和提交任务到hadoop环境中。你可以在本地运行MR,不登陆服务器就能查看数据。
注意:
- 访问HDFS的程序或HDFS shell命令都可以称为HDFS的客户端(client )。这只是部分而已,Java API, Thrift接口、C语言库、用户空间文件系统〔Filesystem in Userspace,FUSE)等都是。
- 在 HDFS的客户端中至少需要指定HDFS集群配置中的NameNode地址以及端口号信息,或者通过配置HDFS的core-site.xml配置文件来 指定。一般可以把客户端和HDFS节点服务器放在同一台机器上。但其前提是机器资源允许,并且我们能够接受不可靠的应用程序代码所带来的稳定性降低的风险。
如何安装?未完待续
5. 指定更改HDFS的存储目录到/home/ruoze/tmp目录下
5.1 查找参数
https://hadoop.apache.org/docs/r2.10.0/hadoop-project-dist/hadoop-hdfs/hdfs-default.xml
中查找关键词dir
,找到dfs.datanode.data.dir=file://${hadoop.tmp.dir}/dfs/data
,即 dfs.datanode.data.dir
引用的是参数${hadoop.tmp.dir}
;
再找hadoop.tmp.dir
,未找到;
转到https://hadoop.apache.org/docs/r2.10.0/hadoop-project-dist/hadoop-common/core-default.xml
中查找hadoop.tmp.dir
,发现hadoop.tmp.dir=/tmp/hadoop-${user.name}
。
即当前HDFS的存储目录为/tmp/hadoop-ruoze
文件 | 参数 | 默认值 | 描述 |
---|---|---|---|
core-site.xml | hadoop.tmp.dir | /tmp/hadoop-${user.name} | HDFS的存储目录 |
5.2 关闭hdfs和yarn
[ruoze@rzdata001 hadoop]$ stop-dfs.sh
19/12/03 13:09:26 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
Stopping namenodes on [rzdata001]
rzdata001: stopping namenode
localhost: stopping datanode
Stopping secondary namenodes [rzdata001]
rzdata001: stopping secondarynamenode
19/12/03 13:09:43 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
[ruoze@rzdata001 hadoop]$
5.3 修正权限
[root@rzdata001 tmp]# chmod -R 777 /home/ruoze/tmp
5.4 存量数据转移
[root@rzdata001 tmp]# mv /tmp/hadoop-ruoze/dfs /home/ruoze/tmp/
5.5 向core-site.xml新增参数
[ruoze@rzdata001 hadoop]$ pwd
/home/ruoze/app/hadoop/etc/hadoop
[ruoze@rzdata001 hadoop]$ vim core-site.xml
<property>
<name>hadoop.tmp.dir</name>
<value>/home/ruoze/tmp</value>
</property>
[ruoze@rzdata001 hadoop]$
5.6 重启hdfs和yarn
[ruoze@rzdata001 hadoop]$ start-dfs.sh
19/12/03 13:13:55 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
Starting namenodes on [rzdata001]
rzdata001: starting namenode, logging to /home/ruoze/app/hadoop-2.6.0-cdh5.16.2/logs/hadoop-ruoze-namenode-rzdata001.out
localhost: starting datanode, logging to /home/ruoze/app/hadoop-2.6.0-cdh5.16.2/logs/hadoop-ruoze-datanode-rzdata001.out
Starting secondary namenodes [rzdata001]
rzdata001: starting secondarynamenode, logging to /home/ruoze/app/hadoop-2.6.0-cdh5.16.2/logs/hadoop-ruoze-secondarynamenode-rzdata001.out
19/12/03 13:14:10 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
[ruoze@rzdata001 hadoop]$ jps
3360 NameNode
3493 DataNode
3800 Jps
3661 SecondaryNameNode
[ruoze@rzdata001 hadoop]$ start-yarn.sh
starting yarn daemons
starting resourcemanager, logging to /home/ruoze/app/hadoop-2.6.0-cdh5.16.2/logs/yarn-ruoze-resourcemanager-rzdata001.out
localhost: starting nodemanager, logging to /home/ruoze/app/hadoop-2.6.0-cdh5.16.2/logs/yarn-ruoze-nodemanager-rzdata001.out
[ruoze@rzdata001 hadoop]$
5.7 测试
[ruoze@rzdata001 hadoop]$ jps
3360 NameNode
3857 ResourceManager
3969 NodeManager
3493 DataNode
3661 SecondaryNameNode
4269 Jps
[ruoze@rzdata001 hadoop]$
[ruoze@rzdata001 tmp]$ hadoop fs -ls /
19/12/03 13:15:26 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
Found 2 items
drwx------ - ruoze supergroup 0 2019-12-01 19:04 /tmp
drwxr-xr-x - ruoze supergroup 0 2019-12-01 18:51 /user
[ruoze@rzdata001 tmp]$