Hadoop分布式文件系统HDFS

HDFS的探究:java

HDFS

HDFS是 Hadoop Distribute File System的缩写,是谷歌GFS分布式文件系统的开源实现,Apache Hadoop的一个子项目,HDFS基于流数据访问模式的分布式文件系统,支持海量数据的存储,容许用户将百千台组成存储集群,HDFS运行在低成本的硬件上,提供高吞吐量,高容错性的数据访问。node

优势

  • 能够处理超大文件(TB、PB)。
  • 流式数据访问 一次写入屡次读取,数据集一旦生成,会被复制分发到不一样存储节点上,响应各类数据分析任务请求。
  • 商用硬件 能够运行在低廉的商用硬件集群上。
  • 异构软硬件平台的可移植性,HDFS在设计的时候就考虑到了平台的能够移植性,这种特性方便了 HDFS在大规模数据应用平台的推广。

缺点

  • 低延迟的数据访问,要求地时间延迟数据访问的应用不是在HDFS上运行,能够用Hbase,高吞吐量的同时会以提升时间延迟为代价。
  • 大量小文件 因为namenode将文件的元数据存储在内存中,所以受制于namenode的内存容量,通常来讲目录块和数据库的存储信息约占150个字节也就是说若是有100万个文件,每个文件占一个数据块,则须要300MB内存,可是存储十亿个就超出了当前的硬件能力了。
  • 多用户写入,任意修改文件。HDFS中的文件写入只支持一个用户,且只能以添加的方式正在文件末尾添加数据,不支持多个写操做,不支持文件的任意位置修改。

数据块

HDFS默认的块大小是128M,与单一磁盘上的文件系统类似,HDFS也被划分为块大小的多个分块。HDFS中小于一个块大小的文件不会占据整个块的空间,当一个1M的文件存储在一个128M的块中时,文件只占1M的磁盘空间,而不是128M。HDFS的块比磁盘的块大,目的时为了最小化的寻址开销,假设寻址时间约为10ms,传输速度为100M/s,为了使寻址时间仅占传输时间的1%,咱们要将块设置成100MB,默认块的大小为128M,这个块的大小也不能设置得过大。MapReduce中的map任务一般一次只处理一个数据块的数据,所以若是任务数量太少了(少于集群中的节点数量),做业的运行速度就会比较慢。python

NameNode

元数据节点(NameNode)的做用是管理分布式文件的命名空间,一个集群只有一个NameNode节点,主要负责HDFS文件系统的管理工做包括命名空间管理和文件Block管理,在HDFS内部,一个文件被分红为一个或者多个Block的全部元数据信息,主要包括“文件名 —>>数据块的映射“,”数据块 —>>DataNode“的映射列表,该列表经过DataNode上报给NameNode创建,NameNode决定文件数据块到具体的DataNode节点的映射。数据库

NameNode管理文件系统的命名空间(namespace),它维护这文件系统树以及文件树中全部的文件(文件夹)的元数据。管理这些信息的文件有两个,分别是命名空间镜像文件(namespace image)和操做日志文件(edit log),这些信息被缓存在RAM中,也会持被持久化存储在硬盘。apache

为了周其性地将元数据节点地镜像文件fsimage和日志edits合并,以防止日志文件过大,HDFS定义了辅助元数据节点(Secondary NameNode)上也保存了一份fsimage文件,以确保在元数据文件中地镜像文件失败时能够恢复。缓存

容错机制

NFS

备份组成文件系统元数据持久状态的文件,将本地持久状态写入磁盘地同时,写入一个远程挂载地文件系统(NFS)安全

辅助节点

运行一个辅助的Namenode,不做为Namenode使用,按期合并编辑日志和命名空间镜像,通常在一台单独的物理计算机上运行,由于它须要占用大量CPU时间,而且须要与namenode同样多的内存来执行合并操做,会保存Namenode合并后的命名空间和镜像文件,通常会滞后于NameNode节点的。服务器

RAID

使用磁盘陈列NameNode节点上冗余备份Namenode的数据。网络

DataNode

数据节点只负责存储数据,一个Block会在多个DataNode中进行冗余备份,一个块在一个DataNode上最多只有一个备份,DataNode上存储了数据块ID和数据块内容以及他们的映射关系。负载均衡

DataNode定时和NameNode通讯,接收NameNode的指令,默认的超时时长为10分钟+30s。 NameNode上不永久保存DataNode上有哪些数据块信息,经过DataNode上报的方式更新NameNode上的映射表,DataNode和NameNode创建链接后,会不断和 NameNode保持联系,包括NameNode第DataNode的一些命令,如删除数据或把数据块复制到另外一个DataNode上等,DataNode一般以机架的形式组织,机架经过一个交互机将全部的系统连接起来。机架内部节点之间传输速度快于机架间节点的传输速度。

DataNode同时做为服务器接收客户端的范围呢,处理数据块的读、写请求。DataNode之间还会相互他通讯,执行数据块复制任务,在数据块复制任务,在客户端执行写操做时,DataNode之间须要相互通讯配合,保持写操做的一致性,DataNode的功能包括:

  1. 保存Block,每一个块对应原数据信息文件,描述这个块属于那个文件,第几个块等信息。
  2. 启动DataNode线程,向NameNode按期汇报Block信息。
  3. 按期向NameNode发送心跳保持联系。若是10分钟没有接收到心跳,则认为其lost,将其上的Block复制到其余DataNode节点上。

SecondaryNameNode

SecondaryNameNode按期地建立命名空间地检查点。首先从NameNode下载fsimage和edit.log而后在本地合并他们,将合并后地fsimage和edit.log上传回到NameNode,这样减小了NameNode从新启动NameNode时合并fsimage和edits.log花费地时间,按期合并fsimage和edit.log文件,使得edits.log大小保持在限定返回内并起到冷备份的做用,在NameNode失效的时候,能够恢复fsimage。SecondaryNameNode与NameNode一般运行在不一样的机器上,内存呢与NameNode的内存同样大。

参数dfs.namenode.secondary.http-address设置SecondaryNamenode 的通讯地址,SecondaryNamenode上的检查点进程开始由两个配置参数控制,第一个参数dfs.namenode.checkpoint.period,指定两个连续检查点之间的时间差默认1小时。dfs.namenode.checkpoint.txns,定义NameNode上新增事务的数量默认1百万条。即便没有到达设定的时间也会启动fsimage和edits的合并。

工做流程

  1. SecondaryNameNode会按期和NameNode通讯,请求其中止使用edits文件,暂时将更新的操做写道一个新的文件edits.new上来。这个操做时瞬间完成的,上层写日志的函数时彻底赶不到差异。

  2. SecondaryNameNode经过HTTP GET的方式从NameNode上获取fsimage和edits.log文件,并下载到相应的目录下。

  3. SecondaryNameNode将下载下来的fsimage载入到内存,而后一条一条的执行edits文件中的哥哥更新操做,使内存中的fsimage保持最新;这个过程就是edits和fsimage文件合并。

  4. SecondaryNameNode 执行完3操做后,会经过POST的方式新的fsimage文件发送到NameNode节点上。

  5. Namenode从SecondaryNameNode接收到更新的fsimage替换旧的fsimage文件,同时将edits.new改名为edits文件,这个过程当中edits就变小了。

HDFS工做机制

机架感知

在HDFS中,数据块被复制成副本,存放在不一样的节点上,副本的存放是HDFS可靠性和性能的关键,优化副本存放策略使HDFS区分于其余大部分分布式文件系统的共同要特征,HDFS采用了一种称为机架感知的(rck-aware)的策略来改进数据的可靠性,可用性和网络带宽的利用率。HDFS实例通常运行在多个机架的计算机组成的集群上,不一样机架上的两台机器之间的通讯时经过交互机。在多数状况下,一个机架上的两台机器间的带宽会比不一样机架的两台机器的带宽大。

经过一个机架感知的过程,NameNode能够肯定每个Datanode所属的机架id,一个简单的策略是将副本放在不一样的机架,能够有效防止一个机架失效时数据的丢失,而且容许读数据的时候充分利用各个机架的带宽,这种策略设置能够将副本均匀分布在集群中,有利于当组件失效的状况下的负载均衡,可是 ,由于这种策略的一个写操做须要传输数据块到多个机架这样增长了写的代价。

多数状况下副本系数时3,HDFS的存放策略时将一个副本存放在本地的机架上,一个副本放在同一机架的另一个节点上 ,最后一个副本放在不一样机架的节点上,这种策略减小了机架间的数据传输,提升了写操做的效率。机架间的错误远比节点的错误少,这种策略提减小了读取数据时须要的网络传输总带宽。这种策略下,副本并非均匀分布在同一个机架上。三分之一的副本在一个节点,三分之二的副本在一个机架上,其余副本均匀分布在剩下的机架中,这种策略在不损害数据可靠性和可读性能的状况下改进了写的性能。

分配原理

  • 有了机架感知,NameNode就能够画出下图所示的datanode网络拓扑图,

最底层是Hx是 datanode, 则H1的rackid=/D1/R1/H1,H1的parent是R1,R1的是D1,有了这些rackid信息就能够计算出任意两台datanode之间的距离

distance(/D1/R1/H1,/D1/R1/H1)=0  相同的datanode
distance(/D1/R1/H1,/D1/R1/H2)=2  同一rack下的不一样datanode
distance(/D1/R1/H1,/D1/R1/H4)=4  同一IDC下的不一样datanode
distance(/D1/R1/H1,/D2/R3/H7)=6  不一样IDC下的datanode

 

  • 写文件时根据策略输入 dn 节点列表,读文件时按与client由近到远距离返回 dn 列表

文件读取

  1. HDFS Client 经过FileSystem对象的Open方法打开要读取的文件。

  2. DistributeFileSystem负责向远程的元数据(NameNode)发起RPC调用,获得文件的数据信息。返回数据块列表,对于每一个数据块,NameNode返回该数据块的DataNode地址。

  3. DistributeFileSystem返回一个 FSDataInputSteam对象给客户端,客户端调用FSdataInputSteam对象的read()方法开始读取数据。

  4. 经过对数据流反复调用read()方法,把数据从数据节点传输到客户端。

  5. 当数据读取完毕时,DFSInputSteam对象会关闭此数据节点的连接,链接此文件下一个数据块的最近数据节点。

  6. 当客户端读取完数据时,调用FSDataInputSteam对象的close()关闭输入流。

API

方法名 返回值 说明
read(ByteBuffer buf) int 读取数据放到buf缓冲区,返回所读取的字节数。
read(long pos,byte[] buf, int offset ,int len) int 输入流的指定位置开始把数据读取到缓冲区中,pos指定从 输入文件读取的位置,offset数据写入缓冲区位置的(偏移量)len读操做的最大的字节数。
readFully(long pos,byte[] buff[]) void 从指定位置,读取全部数据到缓冲区
seek(long set) void 指向输入流的第offset字节
relaseBuffer(ByteBuffer buff) void 删除

代码

package hdfs;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

import java.net.URI;


public class DataInputStream {
    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        FileSystem fs = FileSystem.get(new URI("hdfs://192.168.1.101:9000"),conf,"hadoop");
        Path src = new Path("/input/test");
        FSDataInputStream dis = fs.open(src);
        String str = dis.readLine();
        while (str.length() > 0) {
            System.out.println(str);
            str = dis.readLine();
            if (str == null) break;
        }
        dis.close();
    }
}

 

文件写入

  1. 客户端调用DistributedFileSystem对象的create方法建立一个文件输出流对象
  2. DistributedFileSystem向远程的NameNode系欸但发起一次RPC调用,NameNode检查该文件是否存在,若是存在将会覆盖写入,以及客户端是否有权限新建文件。
  3. 客户端调用的FSDataOutputStream对象的write()方法写数据,首先数据先被写入到缓冲区,在被切分为一个个数据包。
  4. 每一个数据包发送到用NameNode节点分配的一组数据节点的一个节点上,在这组数据节点组成的管线上依次传输数据包。
  5. 管线上的数据接按节点顺序反向发挥确认信息(ack)最终由管线中的第一个数据节点将整条管线确认信息发给客户端。

代码

package hdfs;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

import java.net.URI;

public class DataOutputStream {
    public static void main(String[] args) throws Exception {

        Configuration conf = new Configuration();
        //设置 hdfs 地址 conf  用户名称
        FileSystem fs = FileSystem.get(new URI("hdfs://192.168.1.101:9000"), conf, "hadoop");

        //文件路径
        Path path = new Path("/input/write.txt");

        //字符
        byte[] buff = "hello world".getBytes();
        FSDataOutputStream dos = fs.create(path);
        dos.write(buff);
        dos.close();
        fs.close();

    }
}

 

数据容错

数据节点

每一个DataNode节点按期向NameNode发送心跳信号,网络割裂会致使DataNode和NameNode失去联系,NameNode经过心跳信号的缺失来检测DataNode是否宕机。当DataNode宕机时再也不将新的I/O请求发给他们。DataNode的宕机会致使数据块的副本低于指定值,NameNode不断检测这些须要复制的数据块,一旦发现低于设定副本数就启动复制操做。在某个DataNode节点失效,或者文件的副本系数增大时均可能须要从新复制。

名称节点

名称节点保存了全部的元数据信息,其中最核心的两大数据时fsimage和edits.logs,若是这两个文件损坏,那么整个HDFS实例失效。Hadoop采用了两种机制来确保名称节点安全。

  1. 把名称节点上的元数据同步到其余的文件系统好比(远程挂载的网络文件系统NFS)
  2. 运行一个第二名称节点SecondaryNameNode当名称节点宕机后,可使用第二名称节点元数据进行数据恢复,但会丢失一部分数据。

所以会把两种方式结合起来一块儿使用,当名称节点发生宕机的时候,首先到远程挂载的网络文件系统中获取备份的元数据信息,放到第二名称节点上进行恢复并把第二名称节点做为名称节点来使用。

数据出错

某个DataNode获取的数据块多是损坏的,损坏多是由DataNode的存储设备错误,网络错误或者软件bug形成的。HDFS使用校验和判断数据块是否损坏。当客户端建立一个新的HDFS会计算这个每一个数据块的校验和。并将校验和做为一个单独的隐藏文件保存在同一个HDFS命名空间下。当客户端获取文件内容后,它会检验从DataNode获取的数据和对应的校验是否匹配,若是不匹配客户端从其余Datanode获取该数据块的副本。HDFS的每一个DataNode还保存了检查校验和日志,客户端的每一次检验都会记录到日志中。

相关文章
相关标签/搜索