0x01 前言
如果您觉得本文对您有帮助,请赞赏,谢谢。
Hadoop 分布式文件系统(HDFS)被设计成适合运行在通用硬件(commodity hardware)上的分布式文件系统。它和现有的分布式文件系统有很多共同点。但同时,它和其他的分布式文件系统的区别也是很明显的。HDFS 是一个高度容错性的系统,适合部署在廉价的机器上。HDFS 能提供高吞吐量的数据访问,非常适合大规模数据集上的应用。HDFS 放宽了一部分 POSIX 约束,来实现流式读取文件系统数据的目的。HDFS 在最开始是作为 Apache Nutch 搜索引擎项目的基础架构而开发的。HDFS 是 Apache Hadoop Core 项目的一部分。
0x02 HDFS 概述
0x01 HDFS 的优缺点
HDFS 优点
高容错性:数据自动保存多个副本,副本丢失后,自动恢复。
适合批处理:移动计算而飞数据。数据位置暴露给计算框架。
适合大数据处理:GB,TB,设置PB级数据。百万规模以上文件数量。10K+ 节点规模。
流式文件访问:一次性写入,多次读取。保证数据一致性。
可构建在廉价机器上:通过多副本提高可靠性。提供容错和恢复机制。
HDFS 缺点
不适合低延迟数据访问场景:比如毫秒级,低延迟与高吞吐率。
不适合小文件存取场景:占用 NameNode 大量内存。寻道时间超过读取时间。
不适合并发写入,文件随机修改场景:一个文件只能有一个写者。仅支持 append。
0x02 HDFS 的组成
HDFS 采用 Master/Slave 的架构来存储数据,这种架构主要由四个部分组成,分别为 HDFS Client、NameNode、DataNode 和 Secondary NameNode。下面我们分别介绍这四个组成部分。
Client:就是客户端
文件切分。文件上传 HDFS 的时候,Client 将文件切分成 一个一个的Block,然后进行存储。
与 NameNode 交互,获取文件的位置信息。
与 DataNode 交互,读取或者写入数据。
Client 提供一些命令来管理 HDFS,比如启动或者关闭 HDFS。
Client 可以通过一些命令来访问 HDFS。
NameNode:就是 master,它是一个主管、管理者
管理 HDFS 的名称空间。
配置副本策略。当副本数低于规定数之后,就会自动增加副本数。
处理客户端读写请求。
管理数据块(Block)映射信息。NaseNode 保存 metadate 信息包括:文件 owership 和 permissions、文件包含哪些块、Block 保存在哪个 DataNode(由 DataNode 启动时上报)。
NameNode 的 metadata 信息在启动后会加载到内存,metadata存储到磁盘文件名为“fsimage”,Block 的位置信息不会保存到 fsimage,edits 记录对 metadata 的操作日志。
DataNode:就是Slave。NameNode 下达命令,DataNode 执行实际的操作
存储实际的数据块。文件被切分成固定大小的数据块。默认数据块大小为 64MB,可配置。若文件大小不到 64MB,则单独存成一个 block。
执行数据块的读/写操作。一个文件存储方式。按大小被切分成若干个 block,存储到不同节点上,默认情况下每个 block 有三个副本。
启动 DataNode 线程的时候向 NameNode 汇报 block 信息,通过向 NameNode 发送心跳保持与其联系 3 秒一次,如果 NameNode 10 分钟没有收到 DataNode 的心跳,则认为其已经 lost,并拷贝到其他 DataNode。
Secondary NameNode:并非 NameNode 的热备。
当 NameNode 挂掉的时候,它并不能马上替换 NameNode 并提供服务。
辅助 NameNode,分担其工作量。
定期合并 fsimage 和 fsedits,并推送给 NameNode。SNN 执行合并的时机:根据配置文件设置的时间间隔 fs.checkpoint.period 默认 3600 秒、根据配置文件设置 edits log 大小 fs.checkpoint.size 规定 edits 文件的最大值默认是 64MB。合并交给 Secondary Name Node 主要是因为 Name Node 主要为客户端交互,而合并的工作主要交给 Secondary Name Node。
在紧急情况下,可辅助恢复 NameNode。
0x03 HDFS 读写流程
HDFS 读流程
HDFS 的文件读取原理,主要包括以下几个步骤:
首先调用 FileSystem 对象的 open 方法,其实获取的是一个 DistributedFileSystem 的实例。
DistributedFileSystem 通过 RPC(远程过程调用)获得文件的第一批 block 的 locations,同一 block 按照重复数会返回多个 locations,这些 locations 按照 hadoop 拓扑结构排序,距离客户端近的排在前面。
前两步会返回一个 FSDataInputStream 对象,该对象会被封装成DFSInputStream 对象,DFSInputStream 可以方便的管理 DataNode 和 NameNode 数据流。客户端调用 read 方法,DFSInputStream 就会找出离客户端最近的 DataNode 并连接 DataNode。
数据从 DataNode 源源不断的流向客户端。
如果第一个 block 块的数据读完了,就会关闭指向第一个 block 块的 DataNode 连接,接着读取下一个 block 块。这些操作对客户端来说是透明的,从客户端的角度来看只是读一个持续不断的流。
如果第一批 block 都读完了,DFSInputStream 就会去 NameNode 拿下一批 blocks 的 location,然后继续读,如果所有的 block 块都读完,这时就会关闭掉所有的流。
HDFS 写流程
HDFS 的文件写入原理,主要包括以下几个步骤:
客户端通过调用 DistributedFileSystem 的 create 方法,创建一个新的文件。
DistributedFileSystem 通过 RPC(远程过程调用)调用 NameNode,去创建一个没有 blocks 关联的新文件。创建前,NameNode 会做各种校验,比如文件是否存在,客户端有无权限去创建等。如果校验通过,NameNode 就会记录下新文件,否则就会抛出 IO 异常。
前两步结束后会返回 FSDataOutputStream 的对象,和读文件的时候相似,FSDataOutputStream 被封装成 DFSOutputStream,DFSOutputStream 可以协调 NameNode 和 DataNode。客户端开始写数据到 DFSOutputStream,DFSOutputStream 会把数据切成一个个小 packet,然后排成队列 data queue。
DataStreamer 会去处理接受 data queue,它先问询 NameNode 这个新的 block 最适合存储的在哪几个 DataNode 里,比如重复数是3,那么就找到 3 个最适合的 DataNode,把它们排成一个 pipeline。DataStreamer 把 packet 按队列输出到管道的第一个 DataNode 中,第一个 DataNode 又把 packet 输出到第二个 DataNode 中,以此类推。
DFSOutputStream 还有一个队列叫 ack queue,也是由 packet 组成,等待 DataNode 的收到响应,当 pipeline 中的所有 DataNode 都表示已经收到的时候,这时 akc queue 才会把对应的 packet 包移除掉。
客户端完成写数据后,调用 close 方法关闭写入流。
DataStreamer 把剩余的包都刷到 pipeline 里,然后等待 ack 信息,收到最后一个 ack 后,通知 DataNode 把文件标示为已完成。
0x05 HDFS 的安全模式
安全模式(详细介绍)是 HDFS 所处的一种特殊状态,在这种状态下,文件系统只接受读数据请求,而不接受删除、修改等变更请求。在 NameNode 主节点启动时,HDFS 首先进入安全模式,DataNode 在启动的时候会向 NameNode 汇报可用的 block 等状态,当整个系统达到安全标准时,HDFS 自动离开安全模式。如果 HDFS 出于安全模式下,则文件 block 不能进行任何的副本复制操作,因此达到最小的副本数量要求是基于 DataNode 启动时的状态来判定的,启动时不会再做任何复制(从而达到最小副本数量要求)。
0x06 具体实现
0x01 Linux环境搭建
安装 HDFS 大致可以分为以下几个步骤:下载、解压、检查 Java 和 SSH 免密码登陆,修改 core-site.xml、HDFS-site.xml 文件,修改 masters 和 slaves 文件,格式化 NameNode,运行 start-HDFS.sh 文件。
安装 jdk。下载 Jdk rpm 版:jdk-8u181-linux-x64.rpm。下载后上传到目标系统。安装 jdk 命令:# rpm -ivh jdk-8u181-linux-x64.rpm
,安装完后使用命令:# java
、# javac
来测试 Java 环境是否安装成功。
修改 hosts 文件,添加主机名映射:centos01 - 192.168.198.128、centos02 - 192.168.198.129、centos02 - 192.168.198.130。对主机形成映射。
下载 Hadoop v1.2.1,下载 hadoop-1.2.1.tar.gz
包到 linux 上,利用 xftp 存放在 root 目录下,利用命令:# tar -xvzf hadoop-1.2.1.tar.gz
进行解压。解压后,我们将参考官方文档进行安装。
0x02 详细安装
我们将 centos01 作为 NameNode,将 centos02 作为 Secondary NameNode、DataNode,centos03 作为 DataNode。所以我们将配置如下:
在 centos01 上修改 conf/core-site.xml
文件,添加如下:
<configuration>
<!-- HDFS rpc调用端口 -->
<property>
<name>fs.default.name</name>
<value>HDFS://centos01:9000</value>
</property>
<!-- HDFS存储目录 -->
<property>
<name>hadoop.tmp.dir</name>
<value>/opt/hadoop</value>
</property>
</configuration>
默认的存储目录是 linux 下的 tmp 目录,服务器重启之后临时文件将会被删除,因此我们修改目录为 /opt/hadoop
。
如果因为频繁格式化,格式化命令为 bin 目录下:./hadoop namenode -format
,格式化后 DataNode 启动不了,那么将 hadoop.tmp.dir
目录清空,再格式化后就可以解决问题了(详细情况)。
在文件 conf/HDFS-site.xml
上添加如下,这个是配置你的 DataNode 数。
<configuration>
<!-- HDFS节点数 -->
<property>
<name>dfs.replication</name>
<value>2</value>
</property>
</configuration>
修改 conf/masters
文件,添加 centos02
,修改 conf/slaves
文件,添加 centos02
、centos03
。
为了更容易进行操作,我们对解压后的文件夹形成软链接简化操作。命令如下:# ln -sf /root/hadoop-1.2.1 /home/hadoop
形成软链接。
进入 centos01 conf 文件夹,利用命令 scp -r ./* root@centos02:/home/hadoop/conf/
拷贝文件到 centos02,centos03 的 conf 文件下。
完成后进入 centos01 bin 目录,先用命令 ./hadoop namenode -format
进行格式化,然后利用命令 # ./start-dfs
打开 HDFS 。访问网址 localhost:50070
便能进入 HDFS 监控中心。