美文网首页
Hadoop源码分析-HDFS写数据的契约机制

Hadoop源码分析-HDFS写数据的契约机制

作者: 晨磊的微博 | 来源:发表于2021-01-19 14:34 被阅读0次

    每创建一个文件后,会为每个文件创建一个契约(lease)

    先引入一个小的背景,假如多个客户端同时要并发的写Hadoop HDFS上的一个文件,这个事儿能成吗? 明显不可以接受啊,因为HDFS上的文件是不允许并发写的,比如并发的追加一些数据什么。 所以HDFS里有一个机制,叫做文件契约机制。 也就是说,同一时间只能有一个客户端获取NameNode上面一个文件的契约,然后才可以向获取契约的文件写 入数据。 此时如果其他客户端尝试获取文件契约的时候,就获取不到,只能干等着。 通过这个机制,可以保证同一时间只有一个客户端在写一个文件。 在获取到了文件契约之后,在写文件的过程期间,那个客户端需要开启一个线程,不停的发送请求给 NameNode进行文件续约,告诉NameNode: NameNode大哥,我还在写文件啊,你给我一直保留那个契约好吗? 而NameNode内部有一个专门的后台线程,负责监控各个契约的续约时间。 如果某个契约很长时间没续约了,此时就自动过期掉这个契约,让别的客户端来写。

    1. 添加契约

    1. FSNamesystem.startFileInternal(),可以看到leaseManager.addLease()就是开始添加契约代码。
      image
    2. LeaseManager.addLease(),
    • 1:这里如果没有lease,那就new一个,然后把这个lease存储到一个TreeMap和一个TreeSet里,如果已经有lease对象了,那么就调用renewLease();
    • 2:sortedLeasesByPath是个TreeMap,这里就是把刚才获得的leasesrc变量都put到这个map中(这个src应该就是文件的路径);
    • 3:paths是个TreeSet,就是把src存储到一个set中。
    • 后面让我们看看renewLease()方法
      image
    1. LeaseManager.renewLease();1:先把lease从set中移除;2:然后调用lease.renew()3:最后又把lease添加到set中。直接看2

      image
    2. Lease.renew()1这里就是把更新了leaselastUpdate2这里简单注意下LeaseLeaseManager的内部类。

      image

    在第2步这里我们说到,使用到了TreeMap那么肯定就是要对Lease进行排序了。那么是根据什么排序的呢?我们看看Lease的实现。

    1. Lease,可以看到Lease实现了Comparable接口,实现了compareTo方法,并且进行比较的字段是lastUpdate
      image

    到此我们可以总结下了,所谓文件的契约其实就是创建一个Lease对象,然后把这个对象存储到一个TreeMap和一个TreeSet中。使用集合的原因是,因为有很多契约,但是对应的每个文件就一个契约,而使用TreeMapTreeSet的原因是因为要为契约按照最后更新时间进行升序排序。

    1. 那么这些代码都执行完之后,会从第3步的代码继续执行,我们继续看看后面有什么。再后面,就是又进行Editlog日志同步了。如果进去看看就是Editlog的双缓冲机制了。我们之前讲过就不看了。
      image

    2. 契约的续约-类似心跳

    1. 那么这些都执行完了,客户端创建文件的流程也就结束了。不过我们还得看下客户端那边的代码。可以看到客户端这里再创建完文件后,又创建了一个DFSOutputStream对象,然后又调用了DFSOutputStream的start方法。
      image
    2. DFSOutputStream.start(),这里有调用了DataStreamer.start(),而DataStreamer其实是个线程。DFSOutputStreamDataStreamer这两类,是写数据的核心类。我们后面在详细聊。
      image
    3. 以上所有的代码,都是DFSOutputStream.newStreamForCreate()所调用的。而后面又执行了beginFileLease()方法。
      image
    4. DFSClient.beginFileLease(),这里其实就是续约
      image
    5. LeaseRenewer.put(),这里启动了一个线程,run方法里调用了LeaseRenewer.this.run(id);
      image
    6. LeaseRenewer.run(),这里就是调用了renew();然后再后面就获得了新的契约时间。那肯定renew()就是续约了。
      image
    7. LeaseRenewer.renew(),这边的续约代码写的比较隐蔽。那就是在if那里,就是c.renewLease()。这里有个for循环,可以看到是遍历的DFSClient对象。也就是说这里应该是给所有客户端续约了。
      image
    8. 一看到下面的代码,应该就想到要去NameNodeRpcServer里去找了。
      image
    9. 这里的代码就很简答了。其实后面的代码跟上面我们说的创建契约的代码是一样的。


      image
      image
      image

    3. 契约续约的监控

    客户端写文件,总不能一直写,总会写完吧。所以光创建契约和续约怎么行呢。还得有个线程监控写完了移除契约的。LeaseManager有个内部类Monitor就是做这事情的。

    1. Monitor也是个线程,所以,肯定执行的是run方法了。然后是个for循环,这里就是类似while(true),循环里关键的代码就是这么一行needSync = checkLeases();,最后有个sleep,sleep时间是2秒。

      image
    2. checkLeases();1:这里是获得最老的契约;2:这是判断如果最老的契约没有超时,那么直接break了;这个超时时间是1小时。

      image
    3. 如果超时了,那么就执行移除契约的操作removeLease(leaseToCheck, p);。具体就不看了,肯定是从刚才那个treemaptreeset里移除这个契约呗。

      image
    4. 到此我们画个图,简单总结下契约这事:


      image

    相关文章

      网友评论

          本文标题:Hadoop源码分析-HDFS写数据的契约机制

          本文链接:https://www.haomeiwen.com/subject/tugqzktx.html