HDFS集群的Namenode对租约的管理


  • HDFS集群的Namenode对租约的管理
  • 租约管理器
  • 租约管理
  • 1.添加租约
  • 2.更新租约
  • 3.删除租约
  • 4.检查租约
  • 5.租约恢复



 HDFS文件是write-once-read-many,并且不支持客户端的并行写操作,因而需要一种机制保证对HDFS文件的互斥操作。HDFS提供了租约机制来实现这个功能,租约是Namenode给予租约持有者(通常是客户端)在规定时间内拥有文件权限(写文件)的合同。


 在HDFS中,客户端写文件时需要先从租约管理器申请一个租约,成功申请租约之后客户端就成为了租约持有者,也就拥有了对该HDFS文件的独占权限,其他客户端在该租约有效时无法打开这个HDFS文件进行操作。

租约管理器

 Namenode的租约管理器保存了HDFS文件与租约、租约与租约持有者的对应关系,租约管理器还会定期检查它维护的所有租约是否过期。租约管理器会强制收回过期的租约,所以租约持有者需要定期更新租约,维护对该文件的独占锁定。当客户端完成了对文件的写操作,关闭文件时,必须在租约管理器中释放租约。
 为了便于管理,在租约管理器中将一个客户端打开的所有文件组织在一起构成一条记录,也就是LeaseManager.Lease类。其比较重要的几个字段有:
 1.holder字段:保存了客户端的信息
 2.paths字段:保存了该客户端打开的所有HDFS文件的路径
 3.lastUpdate字段:保存了租约最后的更新时间
 其比较重要的几个方法有:
 1.renew():更新客户端的lastUpdate
 2.expiredSoftLimit():判断当前租约是否超出了软限制,也就是写文件规定的租约超时时间,默认为60s
 3.expiredHardLimit():判断当前租约是否超出了硬限制,也就是文件关闭异常时,强制回收租约的时间,默认为40min

 LeaseManager是Namenode中维护所有租约操作的类,不仅保存了HDFS中所有租约的信息,提供租约的增、删、改、查方法,还维护一个Monitor线程定期检查 租约是否超时。对于长时间没有更新租约的文件,LeaseManager会触发租约恢复机制,然后关闭文件。其比较重要的字段有:
 1.leases:保存了租约持有者与租约的对应关系
 2.sortedLeases:以租约更新时间为顺序保护LeaseManager中的所有租约
 3.sortedLeasesByPath:保存了文件路径与租约的对应关系

租约管理

1.添加租约

 addLease()方法为客户端在HDFS文件上添加一个租约。其先通过getLease()方法构造租约,然后在保存租约的数据结构中添加这个租约的信息。

2.更新租约

 renewLease()方法更新租约,其首先从sortedLeases字段中移除这个租约,然后更新这个租约的最后更新时间。再重新加入sortedLeases中。

3.删除租约

 removeLease()方法删除租约,其直接从保存租约的数据结构中删除租约信息即可。
 两种情况下租约会被删除:
 (1)Namenode关闭构建中的HDFS文件时,会将INode从构建状态转换成非构建状态,由于客户端已经完成了文件的写操作,所以需要删除该文件的租约。
 (2)在进行目录树的删除操作时,对已经打开的文件,如果客户端从文件系统目录树中移出该HDFS文件,则需要删除租约。

4.检查租约

 checkLease()方法检查输入文件的租约持有者与实际的租约持有者是否相同,如果不同,则抛出异常。
 除了对输入文件进行检查外,租约管理器会定期检查所有租约,对长时间没有进行租约更新的文件,LeaseManager会对这个文件进行租约恢复操作,然后关闭这个文件。租约的定期检查操作由LeaseManager内部类Monitor执行,其为一个线程类,run()方法会每隔2s调用一次checkLease()检查租约。
 checkLease()方法会遍历LeaseManager中管理的所有租约,找出所有超过硬限制时间而未更新的租约。而租约保存了这个客户端打开的所有HDFS文件,所以checkLeases()方法会遍历这个租约上的所有文件,并调用internalReleaseLease()方法进行租约恢复。

5.租约恢复

 对HDFS文件的租约恢复操作是通过调用internalReleaseLease()方法实现的,这个方法将一个已经打开的文件进行租约恢复并关闭。如果成功关闭了文件,返回true;如果只是触发了租约恢复操作,返回false。
 租约恢复针对的是已经打开的构建中的文件,internalReleaseLease()方法会判断文件中所有数据块的状态,对于异常的状态会直接抛出异常。而checkLease()方法对于抛出异常的租约会直接删除。
 当文件处于构建状态时,有三种情况可以直接关闭文件:
 (1)这个文件所拥有的所有数据块都处于完成状态,也就是客户端还没来得及关闭文件和释放租约就出现了故障,这时可以直接关闭文件并删除租约。
 (2)文件的最后一个数据块处于提交状态,并且该数据块至少有一个有效的副本,这时可以直接关闭文件并删除租约。
 (3)文件的最后一个数据块处于构建中状态,但这个数据块的长度为0,且当前没有Datanode汇报接收了这个数据块,这种情况很可能是客户端向数据流管道中写数据前发生了故障,这时可以将最后一个未写入数据的数据块删除,之后关闭文件并删除租约。
 当最后一个数据块处于恢复状态或构建状态,且这个数据块已经写入数据时,构造一个新的时间戳作为recoveryId,调用initializeBlockRecovery()触发租约恢复操作,更新当前文件的租约持有者为“HDFS_Namenode”。

 具体的租约恢复操作则是在需要进行租约恢复的数据块上调用initializeBlockRecovery()方法,该方法会遍历所有保存副本的数据节点,选取一个最近一次进行汇报的Datanode作为主恢复节点,然后向这个Datanode发送租约恢复指令,Namenode会通过心跳将租约恢复的Namenode指令下发给该恢复节点。

 而租约恢复指令是通过心跳响应携带给主恢复Datanode的,主恢复Datanode的租约恢复流程为:

 (1)主恢复Datanode接收到指令后,调用recoverBlock()方法开始租约恢复,该方法会通过initReplicaRecovery()方法向数据流管道中参与租约恢复的数据节点收集副本信息,并从该数据块的所有副本中选取出一个最好的状态,作为所有副本恢复的目标状态。

 (2)然后主恢复Datanode会调用updateReplicaUnderRecovery()方法同步所有Datanode上该数据块副本至目标状态。同步结束后,这些Datanode上的副本长度和时间戳将一致。

 (3)最后,主恢复Datanode会调用commitBlockSynchronization()方法向Namenode报告这次租约恢复的结果。这次报告会更新Namenode上数据块的时间戳和长度,使Namenode上的数据块信息与Datanode上进行租约恢复后的副本一致。还会更新DatanodeStorageInfo以及INodeFile中的数据块信息。

hadoop获取租户凭证kinit hadoop多租户管理_HDFS