目录

  • HDFS(三)执行流程
  • 一、dfs目录
  • 二、读取流程
  • 三、写入流程
  • 四、删除流程
  • 五、API操作


HDFS(三)执行流程

  HDFS上的数据不允许修改,Hadoop2.0后允许追加。

一、dfs目录

  1. dfs目录一般表示HDFS的存储目录
    a. dfs/name表示NameNode的持久化目录
    b. dfs/data表示DataNode的存储目录
    c. dfs/namesecondary表示SecondaryNameNode的存储目录
  2. name目录和data目录可以分开指定
  3. 当执行格式化指令时,会在指定的数据目录下,生成dfs/name目录
  4. 当格式化后,启动HDFS前,会生成一个最初的fsimage_0000000000000000000文件,该文件中存储的根节点的信息
  5. dfs/name/in_use.lock文件的作用是防止在同一台服务器上启动多个NameNode,避免管理紊乱
  6. 当启动HDFS时,会生成edits文件
  7. HDFS中有事务id的概念,当HDFS每接收一个事务操作(比如:mkdir put mv),都会分配相应的事务id,然后写到edits文件中
  8. 每生成一个新的edits文件,edits文件中都会以OP_START_LOG_SEGMENT开头,当一个edits文件写完后,会以OP_END_LOG_SEGMENT结尾。即在OP_START_LOG_SEGMENT- OP_END_LOG_SEGMENT存储的是这个edits文件所有的事务记录
  9. edits_inprogress文件的作用是记录当前正在执行的事务文件。后面的编号是以上一次Txid+1来命名的
  10. 初次使用HDFS时,有一个默认的edits和fsimage的合并周期(1分钟),以后在使用HDFS的过程中,达到条件edits_inprogress会和fsimage进行合并
  11. 上传文件底层会拆分成如下的事务过程:
    a. OP_ADD 将文件加入到指定的HDFS目录下,并以._Copyging_结尾,表示此文件还未写完
    b. ALLOCATE_BLOCK_ID 为文件分配块ID
    c. SET_GENSTAMP_V2 为块生成时间戳版本号,是全局唯一的
    d. ADD_BLOCK 写块数据
    e. OP_CLOSE 表示块数据写完
    f. OP_RENAME_OLD 将文件重命名,表示写完
  12. 当停止HDFS后再次启动HDFS时,当执行一个事务之后,底层会触发一次合并,然后生成一个新的edits文件
  13. seen_txid记录是的最新的edits_inprogress文件末尾的数字
  14. fsimage_N文件存储的N号事务前的所有的元数据信息
  15. fsimage_N.md5存储的是fsimage文件的md5校验码,可以通过MD5的校验和来校验文件的完整性:md5sum fsimage_n
  16. 查看edits文件:hdfs oev -i edits文件 -o xxx.xml。例如:hdfs oev -i edits_0000000000000000001-0000000000000000003 -o edits.xml
  17. 查看fsimage文件:hdfs oiv -i fsimage文件 -o xxx.xml -p XML。例如:hdfs oiv -i fsimage_0000000000000000012 -o fsimage.xml -p XML
  18. fsimage介绍:fsimage是一个二进制文件,当中记录了HDFS中所有文件和目录的元数据信息。

二、读取流程

hdfs 是顺序写 hdfs文件按时间排序_HDFS

  1. 使用HDFS提供的客户端开发库Client,向远程的NameNode发起RPC请求
  2. NameNode会视情况返回文件的部分或者全部block列表,对于每个block,NameNode都会返回有该block拷贝的DataNode地址;
  3. 客户端开发库Client会选取离客户端最接近的DataNode来读取block;如果客户端本身就是DataNode,那么将从本地直接获取数据
  4. 读取完当前block的数据后,关闭与当前的DataNode连接,并为读取下一个block寻找最佳的DataNode;
  5. 当读完列表的block后,且文件读取还没有结束,客户端开发库会继续向NameNode获取下一批的block列表。
  6. 读取完一个block都会进行checksum验证,如果读取DataNode时出现错误,客户端会通知NameNode,然后再从下一个拥有该block拷贝的DataNode继续读。
  7. 当文件最后一个块也都读取完成后,DataNode会连接NameNode告知关闭文件。

三、写入流程

hdfs 是顺序写 hdfs文件按时间排序_HDFS_02


1. 使用HDFS提供的客户端开发库Client,向远程的NameNode发起RPC请求

2. NameNode会检查要创建的文件是否已经存在,创建者是否有权限进行操作(用户也有不同的权限),成功则会为文件创建一个记录,否则会让客户端抛出异常

3. 当客户端开始写入文件的时候,开发者会将文件切分成多个packets,并在内部以数据队列"data queue"的形式管理这些packets,并向NameNode申请新的blocks,获取用来存储replicas的合适的DataNode列表,列表的大小根据在NameNode中对replication的设置而定

4. 开始以pipeline(管道)的形式将packet写入所 有的replicas中。开发库把packet以流的方式写入第一个DataNode,该DataNode把该packet存储之后,再将其传递给在此 pipeline中的下一个DataNode,直到最后一个DataNode,这种写数据的方式呈流水线的形式

5. 最后一个DataNode成功存储之后会返回一个ack packet,在pipeline里传递至客户端,在客户端的开发库内部维护着"ack queue",成功收到DataNode返回的ack packet后会从"ack queue"移除相应的packet

6. 如果传输过程中,有某个DataNode出现了故障,那么当前的pipeline会被关闭,出现故障的DataNode会从当前的pipeline中移除, 剩余的block会继续剩下的DataNode中继续以pipeline的形式传输,同时NameNode会分配一个新的DataNode,保持 replicas设定的数量。

四、删除流程

  1. 先在NameNode上执行节点名字的删除。
  2. 当NameNode执行delete方法时,它只标记操作涉及的需要被删除的数据块,而不会主动联系这些数据块所在的DataNode节点。
  3. 当保存着这些数据块的DataNode节点向NameNode节点发送心跳时,在心跳应答里,NameNode节点会向DataNode发出指令,从而把数据删除掉。所以在执行完delete方法后的一段时间内,数据块才能被真正的删除掉。

五、API操作

二、API操作

  1. 读取文件
@Test
public void testConnectNamenode() throws Exception{
    Configuration conf=new Configuration();
    FileSystem fs=FileSystem.get(new URI("hdfs://192.168.234.21:9000"), conf);
    InputStream in=fs.open(new Path("/park/1.txt"));
    OutputStream out=new FileOutputStream("1.txt");
    IOUtils.copyBytes(in, out, conf);
}
  1. 上传文件
@Test
public void testPut() throws Exception{
    Configuration conf=new Configuration();
    conf.set("dfs.replication","1");
    FileSystem fs=FileSystem.get(new URI("hdfs://192.168.234.21:9000"),conf,"root");
    ByteArrayInputStream in=new ByteArrayInputStream("hello hdfs".getBytes());
    OutputStream out=fs.create(new Path("/park/2.txt"));
    IOUtils.copyBytes(in, out, conf);
}
  1. 删除文件
public void testDelete()throws Exception{
    Configuration conf=new Configuration();
    FileSystem fs=FileSystem.get(new URI("hdfs://192.168.234.21:9000"),conf,"root");
    //true表示无论目录是否为空,都删除掉。可以删除指定的文件
    fs.delete(new Path("/park01"),true);
    //false表示只能删除不为空的目录。
    fs.delete(new Path("/park01"),false);
    fs.close();
}
  1. 在hdfs上创建文件夹
@Test
public void testMkdir()throws Exception{
    Configuration conf=new Configuration();
    FileSystem fs=FileSystem.get(new URI("hdfs://192.168.234.21:9000"),conf,"root");
    fs.mkdirs(new Path("/park02"));
}
  1. 查询hdfs指定目录下的文件
@Test
public void testLs()throws Exception{
    Configuration conf=new Configuration();
    FileSystem fs=FileSystem.get(new URI("hdfs://192.168.234.21:9000"),conf,"root");
    FileStatus[] ls=fs.listStatus(new Path("/"));
    for(FileStatus status:ls){
        System.out.println(status);
    }
}
  1. 递归查看指定目录下的文件
@Test
public void testLs()throws Exception{
    Configuration conf=new Configuration();
    FileSystem fs=FileSystem.get(new URI("hdfs://192.168.234.214:9000"),conf,"root");
    RemoteIterator<LocatedFileStatus> rt=fs.listFiles(new Path("/"), true);
    while(rt.hasNext()){
        System.out.println(rt.next());
    }
}
  1. 重命名
@Test
public void testCreateNewFile() throws Exception{
    Configuration conf=new Configuration();
    FileSystem fs=FileSystem.get(new URI("hdfs://192.168.234.176:9000"),conf,"root");
    fs.rename(new Path("/park"), new Path("/park01"));
}
  1. 获取文件的块信息
@Test
public void testCopyFromLoaclFileSystem() throws Exception{
    Configuration conf=new Configuration();
    FileSystem fs=FileSystem.get(new URI("hdfs://192.168.234.176:9000"),conf,"root");
    BlockLocation[] data=fs.getFileBlockLocations(new Path("/park01/1.txt"),0,Integer.MaxValue);
    for(BlockLocation bl:data){
        System.out.println(bl);
    }
}