前言
在HDFS中,当每次客户端用户往某个文件中写入数据的时候,为了保持数据的一致性,此时其它客户端程序是不允许向此文件同时写入数据的。那么HDFS是如何做到这一点的呢?答案是租约(Lease)。换句话说,租约是HDFS给予客户端的一个写文件操作的临时许可证,无此证件者将不被允许操作此文件。本文我们将要深入分析HDFS内部的租约机制,包括租约的添加、移除、管理操作等等。
HDFS租约的概念
HDFS租约可能很多使用HDFS的人都或多或少都知道一些,大致的理解一般如下:“客户端在每次读写HDFS文件的时候获取租约对文件进行读写,文件读取完毕了,然后再释放此租约”。但是是否有人仔细研究过这个租约内部到底包含了什么信息呢,它与租约持有者也就是客户端用户是一种怎样的逻辑关系呢?首先我们需要了解的就是这个问题。下面是HDFS租约的相关定义:
- 每个客户端用户持有一个租约。
- 每个租约内部包含有一个租约持有者信息,还有此租约对应的文件Id列表,表示当前租约持有者正在写这些文件Id对应的文件。
- 每个租约内包含有一个最新近更新时间,最近更新时间将会决定此租约是否已过期。过期的租约会导致租约持有者无法继续执行写数据到文件中,除非进行租约的更新。
综合上述3点,租约的结构关系如图1-1所示。
图 1-1 租约内部结构
租约类代码中的定义如下:
class Lease {
// 租约持有者
private final String holder;
// 最近更新时间
private long lastUpdate;
// 当前租约持有者打开的文件
private final HashSet<Long> files = new HashSet<>();
...
每次当客户端用户新写入一个文件的时候,它会将此文件Id加入到它所对应的租约中,同时更新lastUpdateTime值。讲述完租约的概念,下面我们在来看租约的管理。
HDFS租约的管理
在HDFS中,每天会有许许多多的应用程序在读写文件,于是就会有各个租约的生成。那么这些租约是如何管理的呢?如果有些客户端用户写某文件后未及时关闭此文件,导致此租约一直未释放,从而造成其他用户无法对此文件进行写操作,面对这种情况,HDFS中的做法是怎样的呢?以上提到的问题就是租约管理的内容了。
LeaseManager租约管理器
HDFS租约管理的操作集中在一个类上:LeaseManager。它与CacheManager(缓存管理类),SnapshotManager(快照管理类)类似,是一个中心管理类,运行在Active NameNode的服务中。租约类的定义就是在LeaseManager中的。在LeaseManager租约管理器中,它所做的事情主要归纳为两类。
第一个,维护HDFS内部当前所有的租约,并以多种映射关系进行保存。保存的映射关系分为如下3种:
- 租约持有者对租约的映射关系。
- 文件Id对租约的映射关系。
- 按照时间排序进行租约集合的保存,此关系并不是一种映射关系。
以上3种关系的代码定义如下:
public class LeaseManager {
...
// 租约持有者对租约的映射图
private final SortedMap<String, Lease> leases = new TreeMap<>();
// 按照时间进行排序的租约队列
private final PriorityQueue<Lease> sortedLeases = new PriorityQueue<>(512,
new