目录
一、HDFS是什么
随着移动互联网技术的发展,产生的用户数据也越来越多,对服务器存储需求也越来越大。服务器存储扩展有两个方向:1)垂直扩展,添加多个磁盘,缺点是单台机器能支持的磁盘总数有限,并且磁盘数太多会影响机器读取数据的能力。2)水平扩展,添加多台机器组成集群,将文件分散到集群中各个机器上存放,但是需要机器间网络通信以及某个节点挂掉无法提供的问题,而HDFS的出现便是为了解决这个问题的。
HDFS是一个分布式文件系统:引入存放文件元数据信息的服务器Namenode和实际存放数据的服务器Datanode,对数据进行分布式储存和读取。
二、类Linux文件系统
Linux 的ext格式文件系统将一个磁盘分区格式化后,有两个重要的组成部分:inode(索引块)和data block(数据块)。其中inode存放文件路径,文件本身属性,已经存放文件内容的数据块的编号(当文件内容由多个数据块构成时,存放的是编号列表), 数据块存放文件实际的数据数据内容。读取文件内容时,先根据文件路径找到inode,然后从inode读取文件信息以及数据块编号,根据数据块编号读取数据块内容。因此Linux文件系统也被称为索引式文件系统。
HDFS文件系统也设计了类似架构:NameNode(相当于inode)和 Datanode(相当于data block)。Namenode负责存放文件元信息,Datanode负责实际存放数据。
三、HDFS分层架构
Hdfs 是一个文件系统,底层存储依赖操作系统本身的文件存储机制,它将数据分片存放在不同主机上,并且存放的是文件内容序列化后的二进制数据。对于像我这样曾经的初学者来说,最容易犯得一个错误就是喜欢到Linux主机上直接使用cat 命令去查看hdfs 存放的文件内容,实际上只会看到一堆乱码。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块都读完,这时就会关闭掉所有的流。
4.2 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 把文件标示为已完成。
四、HDFS Block Replication 机制
Hdfs 在存放一个大文件时,比如100GB的日志文件,需要分片存放,在hdfs 术语中,被称之为block(块),每个块的默认大小是128M(低版本中是64M),文件不足128M时,仍然会占用1个block(和Linux 数据块不同的是,该block的实际磁盘占用量为文件实际大小)。当hdfs上小文件过多时,NameNode要记录的元信息也会变得特别多,容易让NameNode内存溢出。
Hdfs 为了解决Datanode节点挂掉时,该节点的数据块无法访问的问题,引入了数据块 replication。Hdfs默认是3副本(自身 + 两个复制块)备份机制,可以设置配置参数来修改副本数目。Hdfs的3副本选择放在哪些Datanode节点上,是根据机架(放置服务器的架子,现在服务器都基本都是刀片式服务器,1个架子上可以放置多台服务器)配置来选择的,具体策略如下:
1) 第一个副本选择离client距离最近的节点,要求client与hdfs集群在同一局域网内才生效(如果是外网环境访问,则只能随机选择一个节点)。如果client 刚好是集群内的一台主机,则直接选择该Datanode作为首个副本放置地。
2) 第二个副本选择和第一个副本在同一机架下的其他主机。
3) 第三个副本选择和第二个副本不在同一机架的其他主机。
五、NameNode 和 Datanode
1. NameNode 会负责整个文件系统的信息,使用FSNameSystem类来表示,负责维护文件系统目录树结构信息,文件对应的block编号列表,以及每一个block在哪几台datanode机器上存放。
NameNode主要是通过两个数据结构FsImage和EditsLog来实现Metadata的更新。在启动hdfs时,会从FSImage文件中读取当前HDFS文件的Metadata,之后对HDFS的操作步骤都会记录到edit log文件中。
NameNode 启动时,FsImage存放的是上一次checkpoint后的文件元信息,然后和editlog进行合并,构建新的FsImage并做checkpoint。这个过程可能会非常耗时,因为如果NameNode长时间没有过进行重启操作的话,NameNode是不会做日志合并操作的,所有HDFS引入了SecondaryNameNode角色,它是1个不与NameNode在一台机器上的单独进程,主要职责便是定期通过网络拉取NameNode的FsImage和Editlog做合并操作,生成新的checkpoint,发回给NameNode。
2. Datanode 负责实际的数据存储,主要有以下功能:
1) 向NameNode注册以及保持心跳:Datanode 同 NameNode 之间是一个单向通信模型。NameNode 为了保证自身的运行效率,不会主动向 Datanode 发起通信请求,因此所有通信行为都由 Datanode 主动触发。Datanode 启动时会发送注册请求,注册成功后,会定时发送心跳信息,告诉NameNode自己存活,同时取回NamoNode向其发送的指令。
2) 存取数据功能:Datanode启动时创建了dataxceiverServer类的实例,该类用来接收客户端的上传/下载数据请求。
3) block上报功能:NameNode在刚启动时,并不知道文件的block 和存放机器Datanode 的对应关系,因为FsImage中没有保存这个映射关系。Datanode启动时,会先扫描自己存储目录下所有的Block,然后上报给NameNode,NameNode根据上报信息来构建映射关系。在运行期间,如果有block在Datanode上被新建或删除,Datanode也会调用reportBlock方法及时上报信息。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。