本文主要介绍hdfs lease的设计以及实现。
写在前面
https://www.cnblogs.com/jhcelue/p/6783076.html
https://blog.csdn.net/yexiguafu/article/details/118890014
https://www.jianshu.com/p/33e1a5a2b876
https://blog.csdn.net/breakout_alex/article/details/101456998
https://www.cnblogs.com/Scott007/archive/2013/05/30/3108928.html
读写锁简介,现实中有许多写少读多的场景,在程序实现时就期望同一时间只能有一个写线程可以获取写锁,但是同时可以多个读线程可以获取读锁,于是java便有了ReentrantReadWriteLock。ReentrantReadWriteLock采用读写分离策略,允许多个线程可以同时获取读锁。后面文章中提及的读写锁就使用此种实现。
Hdfs Lease简介
HDFS被设计成Write-Once-Read-Many,即不支持并发写,这里的写不单单指数据写入,也包括创建,修改等。当一个客户端向Namenode获取文件锁以后,其他客户端应该获取不到。这里会有个问题,如果多客户端同时获取,怎么保证一致性呢?很明显Namenode那边需要一个请求读写锁,保证请求的一致性。HDFS使用FSNamesystemLock一个大的读写锁,所有文件rpc操作都共用此锁,逻辑上比较简单。当要写一个文件时,先要获取到大的write锁,后面才获取文件的锁信息。
这里会有一个问题,就是如果某个客户端获取到锁信息以后,异常关闭,这个文件会永远被锁住,所以锁信息应该要有一个时效,有时效的锁信息hdfs称之为lease。常见的做法是client保存lease,根据失效时间去更新lease。但是hdfs client不会获取和保存lease而是定时去renew lease,来保证server端lease不失效。
Lease构成
class Lease {
private final String holder;
private long lastUpdate;
private final HashSet<Long> files = new HashSet<>();
}
Holer:clientName,这里要注意的是clientName如何产生。
this.clientName = "DFSClient_"+ dfsClientConf.getTaskId()+"_" +
ThreadLocalRandom.current().nextInt() + "_" +
Thread.currentThread().getId();
不同进程不同线程都唯一,具体看客户端是否共用一个实例。
lastUpdate:lease最后更新时间。
Files:这个客户端的占用files的inode列表。
Lease过期相关
Hdfs对于所有的lease过期判断都使用统一值,并且不能配置。主要有两个值,softLimit和hardLimit,这两个值都在leaseManager中。
softLimit值为60s,主要用于判断lease过期。值得注意的是不会有线程定时去判断lease是否softLimit过期,而是先有A客户端占用file的lease,后有B客户端也需要去获取同一个file的lease,发现A的lease的lastUpdate与当前时间差值大于softLimit,A的lease会失效,B会获取此file的新lease。这里就会发现一个问题,如果A发生错误了以后,没有其他人再去访问A所占用的file,这个file lease会永远遗留在内存中,所以hardLimit产生了。
hardLimit值为3600s,有一个线程会定时判断lease是否hardLimit过期,过期就处理。
Lease的客户端更新
客户端会定时去更新lease,由于lease是对于clientName来说,所以renew lease只需要clientName,通过单次renew可以更新此clientName占用的所有file。更新的频率是softLimit/2即30s,如果client的rpctimeout小于60s,为rpctimeout/2。
Lease recover
正常情况下client端不需要考虑lease的回收,当发生一些奇怪问题的时候,客户端也可以选择去发rpc recoverlease去回收lease。下面主要剖析正常情况下namenode如何recoverlease。还有一个要注意的是一个文件处于underConstruction和这个文件有lease本质上是成对出现的,在设计层面来说这两个东西具有一致性。
由于softLimit的设计,所以任何需要addLease之前,都会去判断是否存在lease,以及存在lease是否需要recoverLease,这些实现都是在FSNamesystem.recoverLeaseInternal中实现,这个方法本质做了以下事情:
图中recoverLease还有一些block相关的判断,后面研究block的时候会补全。
与Lease相关的RPC接口
用到lease的rpc:Create,append,truncate。RenewLease,recoverLease。
用到File underConstruction的rpc:getFileInfo,getBlockLocations,isFileClose,complete,addblock,abandonBlock。
喜欢就点赞、收藏一下~