_00006 Hadoop FileSystem源码浅析(如何与NameNode通信)

来源:互联网 发布:iphone6splus自带软件 编辑:程序博客网 时间:2024/05/02 00:44
博文作者:妳那伊抹微笑
个性签名:世界上最遥远的距离不是天涯,也不是海角,而是我站在妳的面前,妳却感觉不到我的存在
技术方向:Flume+Kafka+Storm+Redis/Hbase+Hadoop+Hive+Mahout+Spark ... 云计算技术
转载声明:可以转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明,谢谢合作!
qq交流群:214293307  云计算之嫣然伊笑(期待与你一起学习,共同进步)


# FileSystem的create方法(主要是围绕下面这张原理图说的)


public FSDataOutputStream create(Pathf)throws IOException {

    return create(f,true);

  }

# 进入create(f, true);

public FSDataOutputStreamcreate(Path f,boolean overwrite)

    throws IOException {

    return create(f, overwrite,

                  getConf().getInt("io.file.buffer.size", 4096),

                  getDefaultReplication(),

                  getDefaultBlockSize());

  }

# 进入create(一直点下去,这里省略一些重复的步骤),会看到create是一个接口

  public abstract FSDataOutputStream create(Path f,

      FsPermission permission,

      boolean overwrite,

      int bufferSize,

      short replication,

      long blockSize,

      Progressable progress) throws IOException;

看到这里FielSystem的create方法是一个接口,子类肯定实现了,想要知道是什么子类,可以在FileSystem执行create的那里打个断点就知道了具体子类是什么了。具体子类就是DistributedFileSystem

# 看DistributedFileSystem中的create方法

public FSDataOutputStreamcreate(Path f,FsPermission permission,

    boolean overwrite,

    int bufferSize,short replication,long blockSize,

    Progressable progress) throws IOException {

 

    statistics.incrementWriteOps(1);

    return new FSDataOutputStream

       (dfs.create(getPathName(f), permission,

                   overwrite, true, replication,blockSize, progress, bufferSize),

        statistics);

  }

dfs是org.apache.hadoop.hdfs.DFSClient这个类

# 进入new FSDataOutputStream 看看FSDataOutputStream的构造方法

在类的注释中可以看到这么一句话Utility that wraps a {@link OutputStream} in a{@link DataOutputStream},说明这个类是对OutputStream的一个封装,我们就不需再看这个类了,因为它只是对OutputStream的一个封装,只需要看OutputStream就行了,返回到上一个步骤

# 进入dfs.create方法看看

LOG.debug(src + ": masked=" + masked);

    final DFSOutputStream result = newDFSOutputStream(src, masked,

        overwrite, createParent,replication, blockSize, progress, buffersize,

        conf.getInt("io.bytes.per.checksum", 512));

    beginFileLease(src, result);

    return result;

# 进入new DFSOutputStream(src, masked…

/**

     * Create a new output stream tothe given DataNode.

     * @see ClientProtocol#create(String,FsPermission, String, boolean, short, long)

     */

    DFSOutputStream(String src,FsPermission masked, boolean overwrite,

        boolean createParent,short replication,long blockSize,Progressable progress,

        int buffersize,int bytesPerChecksum)throws IOException {

      this(src, blockSize, progress, bytesPerChecksum,replication);

 

      computePacketChunkSize(writePacketSize,bytesPerChecksum);

 

      try {

        // Make sure the regular create() is done through the old create().

        // This is done to ensure that newer clients (post-1.0) can talk to

        // older clusters (pre-1.0). Older clusters lack the new  create()

        // method accepting createParent as one of the arguments.

        if (createParent) {

          namenode.create(

            src, masked, clientName, overwrite,replication, blockSize);

        } else {

          namenode.create(

            src, masked, clientName, overwrite,false, replication,blockSize);

        }

      } catch(RemoteException re) {

        throwre.unwrapRemoteException(AccessControlException.class,

                                      FileAlreadyExistsException.class,

                                      FileNotFoundException.class,

                                      NSQuotaExceededException.class,

                                      DSQuotaExceededException.class);

      }

      streamer.start();

    }该类的构造方法上说/**

     * Create a new output stream to the givenDataNode.

     * @see ClientProtocol#create(String,FsPermission, String, boolean, short, long)

    */(创建一个指向DataNode的输出流)

这个DFSOutputStreamDFSClient.的内部类

# 进入namenode.create方法

/**

   * Create a new file entry in thenamespace.

   */

  public void create(String src,

                     FsPermissionmasked,

                             StringclientName,

                             boolean overwrite,

                             short replication,

                             long blockSize

                             ) throws IOException;

看注释说在namespace创建一个entry(namespace就是NameNode中维护的两张核心表之一

The NameNode controls twocritical tables:

 *  1)  filename->blocksequence(namespace))这就是namespace

# 回到上一步,这里的namenode是什么呢?

Namenode就是  public final ClientProtocolnamenode;是一个接口,说明了DFSClient是一个分布式文件系统的客户端,也就是RPC的客户端,就是说RPC客户端含有一个RPC服务端的代理对象。这个代理对象就是ClientProtocol接口,这个ClientProtocol就是NameNode的一个接口。结论就是这里看到的namenode是ClientProtocol,实质上就是NameNode的代理对象。文件创建好了,现在来看看流…

# 点击查看streamer.start();可以看到streamer是一个线程类,streamer的是DataStreamer,现在看看DataStreamer的源码,看看它的run方法

// The DataStreamer class is responsible for sending data packets to the

    // datanodes in the pipeline. It retrieves a new blockid and blocklocations

    // from the namenode, and starts streaming packets to the pipeline of

    // Datanodes. Every packet has a sequence number associated with

    // it. When all the packets for a block are sent out and acks for each

    // if them are received, the DataStreamer closes the current block.

rivate classDataStreamer extends Daemon {

从注释上可以看出D啊他Streamer类负责发送数据包给datanode,它从namenode中渠道blockid跟blocklocations。每一个packet有一个它自身的序列号,当一个block的所有包发送并被确认之后,关闭当前block,实际上就是关闭指向当前快的输出流。

问题:

1.      谁发送这些包?------DataStreamer

2.      发送给谁?-------------DataNode

3.      谁发送确认?---------- DataNode(就是发送给DataStreamer一个确认的收到数据的信息)

4.      谁接收确认?----------- DataStreamer(接收DataNode发送的确认)

也就是把数据写到DataNode节点的block文件中(linux文件系统中的)

 

用户上传数据的时候是不是通过NameNode来转的?(只是向namenode申请了blockid跟blocklocation) 肯定不是的,要是都通过namenode来转,而且namenode又是单点的,namenode负担就太重了。数据是直接上传到datanode的。

# 总结

FileSystem的create方法其实就是把一个数据发送到linux文件系统中,但是HDFS的API封装的非常好,对于用户来说是透明的



妳那伊抹微笑

The you smile until forever 、、、、、、、、、、、、、、、、、、、、、
1 0
原创粉丝点击