HDFS租约实践

本文深入探讨了HDFS租约机制,包括租约的用途、模型、LeaseManager和LeaseRenewer的角色。租约作为一种有时间约束的锁,确保了HDFS的写入互斥。LeaseManager负责租约的生命周期管理,而LeaseRenewer在客户端进行续约操作。文章还介绍了在实际应用中如何避免租约异常,如正确管理文件流,解决Other-Create和Re-Create问题,以及源码解析,帮助理解租约的工作原理。
摘要由CSDN通过智能技术生成

一、租约详解
Why租约
HDFS的读写模式为 “write-once-read-many”,为了实现write-once,需要设计一种互斥机制,租约应运而生
租约本质上是一个有时间约束的锁,即:在一定时间内对租约持有者(也就是客户端)赋予一定的权限

HDFS租约模型

Lease和DFSClient的对应关系为一对一(即:在Hdfs-Server端,为每个DFSClient建立一个Lease),Lease包含的主要信息有:
  * holder:租约持有者(即:DFSClient)
  * lastUpdate:上次续约时间
  * paths:该租约持有的文件路径
  * softLimit和hardLimit
    > 当前时间减去Lease的lastUpdate超过softLimit,允许其它DFSClient抢占该Client持有的filepath(softLimit的默认值为1min)
    > 当前时间减去Lease的astUpdate超过hardLimit,允许LeaseManager强制将该租约回收销毁(hardLimit的默认值为1hour)


顾名思义,LeaseManager是租约的管理者,运行于HDFS-Server端,其主要功能特性有:
  * 维护了DFSClient和Lease的映射关系(参见leases属性)
  * 维护了filePath和Lease的映射关系(参见sortedLeasesByPath属性)
  * 对租约进行生命周期和状态的管理:
    > 创建租约或正常情况下的销毁租约
    > 赋予(或撤销)FilePath权限给租约(撤销FilePath,如:执行文件流的close方法)
    > 接受续约请求,对租约进行续约处理(即:更新Lease的lastUpdate字段)
    > 对超过hardLimit的租约进行销毁处理(参见:LeaseManager.Monitor类)


顾名思义,LeaseRenewer是租约的续约者,运行于HDFS-Client端,其主要功能特性有:
  * LeaseRenewer维护了一个DFSClient列表和一个定时线程,循环不断的为各个DFSClient进行续约操作
  * LeaseRenew本质上是一个heartbeat,方便对超时的DFSClient进行容错处理
  * 从client到server端续约的主流程如下:LeaseRenewer -> DFSClient -> NameNodeRpcServer -> FSNamesystem -> LeaseManager
  * 其它细节此处不再阐述,直接看源码即可


LeaseManager用来管理租约,那么,FSNamesystem用来协调租约,其主要功能特性有:
  * FSNamesystem中和租约相关最核心的一个方法是recoverLeaseInternal,startFile方法、appendFile方法和recoverLease方法都会调用该方法,该方法主要功能有:
    > 验证ReCreate
     如果待操作的文件path已经存在于该DFSClient的Lease的paths列表中,则抛AlreadyBeingCreatedException,
     提示 “current leaseholder is trying to recreate file”
    > 验证OtherCreate
     如果待操作的文件path已经存在于其它DFSClient的Lease的paths列表中,此时有两种策略:如果那个DFSClient的Lease的softLimit已经过期,
     系统会尝试进行Lease-Recovery,然后把path从那个DFSClient的Lease的paths中remove掉,这样新的Client便获取了该path的占有权限;
     如果那个DFSClient的Lease的softLimit还未过期,则抛AlreadyBeingCreatedException,提示 “because this file is already being created by … on …”    
    > 验证Recovery
     这个比较简单,如果待操作的文件还处于租约的Recovery状态,则抛异常RecoveryInProgressException,提示稍后重试
    > ForceRecovery
     recoverLeaseInternal方法提供了force参数,如果force为true,系统会强制进行Lease-Recovery,具体功能见recoverLease方法的注释即可,如下:
       * Immediately revoke the lease of the current lease holder and start lease
       * recovery so that the file can be forced to be closed.
      force recovery的使用场景下文会有介绍

Recovery机制
recovery是一种容错机制,主要分为block的recovery和lease的recovery,此处不详述,具体可参考下面的链接:
http://blog.cloudera.com/blog/2015/02/understanding-hdfs-recovery-processes-part-1/

二、场景介绍

如上图所示,我们的应用场景介绍如下:
* Worker:一个Worker是一个进程,每个Worker负责运行一批Task
* Task:Task负责把抓取到的数据源源不断的实时同步到Hdfs,每个Task负责管理Hdfs中的N个文件(如上图,Task-1在hdfs中对应了Task-1-file-1和Task-1-file-2)
* (Re-)balance:Task和Worker之间的关系是动态的(即:Task在Worker上是平均分配的),当新Worker加入,现有Worker退出、新增Task和删除Task的时候,会触发Rebalance,Task重新分配。比如上图中,增加一个Worker-3,Reblance完成之后的结果为:worker-1运行Task-1和Task-2,worker-2运行Task-3和Task-4,worker-3运行Task-5

三、设计方案
结合租约的特点和我们的场景需求,需要进行针对性的设计,才能避免触发【租约异常】,下面以问答的形式阐述核心设计方案

一个进程内如何同时访问多个hadoop集群?

若要一个进程内同时访问多个hadoop集群,那就需要针对每个集群分别创建各自的FileSystem实例,需要做的有两点:
* 其一:保证针对这多个集群的Configuration实例中的 “fs.defaultFS” 的配置是不同的
* 其二:HADOOP_USER_NAME属性不能通过System.setProperty方法设置,应该调用FileSystem的get方法时动态传入

对文件流应该怎样管理?

Ps:DFSClient是一个进程级实例,即对应同一个hadoop集群,在一个worker进程中只有一个DFSClient
一个文件对应了一个文件流,创建文件流时FSNamesystem会把流对应的path放到Lease中,关闭文件流时FSNamesystem会把流对应的path从Lease中移除,对文件流的管理需要保证以下几个原则
* 其一:流的生命周期应该和Task保持一致,Task运行过程中流随用随创建,Task关闭时把其占有的所有流也关闭,这样才能保证在发生Reblance后,不会出现租约被其它DFSClient占用的问题
* 其二:超时不用的流要及时清理,保证其它使用者有机会获取权限,比如发生日切之后,所有的数据都写到新文件中了,前一天的文件不会再有写入操作,那么应该及时关闭前一天的文件流

如何解决Other-Create问题?

何时会触发Other-Create问题?
其一:Worker宕机,其负责的Task漂移到其它Worker,漂移后的Task便会收到Other-Create异常,只有当超过softLimit之后,异常才会解除,即恢复时间需要1分钟
其二:其它程序原因,如:在发生Reblance时,Task会先被关闭再漂移,如果Task在关闭的过程中流关闭的有问题(比如触发了超时),也可能会触发Other-Create异常
如何应对?
Other-Create异常中包含了other-Dfsclient的IP信息,我们可以调用other-worker提供的接口,远程关闭出问题的流,如果关闭失败或者访问出现超时(宕机的时候会超时),再进行force recovery操作

如何解决Re-Create问题?

流关闭时可能会出现异常,如果出现异常,需要进行force recovery操作,否则的话租约将一直不可释放,一直报Re-Create异常

四、源码解析
【设计方案】部分的描述比较抽象,下面我们结合源码进行更详细的介绍,所有的关键描述都放到了源码注释里,直接看注释即可

package com.ucar.hdfs.lease.demo;

import com.ucar.hdfs.lease.demo.stream.FileStreamHolder;
import com.ucar.hdfs.lease.demo.stream.FileStreamToken;
import com.ucar.hdfs.lease.demo.util.FileLockUtils;
import com.ucar.hdfs.lease.demo.util.HdfsConfig;
import com.ucar.hdfs.lease.demo.util.RemoteUtil;
import org.apache.hadoop.fs.FSDataOutputStream;

import java.text.MessageFormat;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;

/**
* 一个Demo类,可以自己写一些单元测试类,验证租约相关的原理
*/
public class TaskDemo {

private final F
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
HDFS是分布式文件系统,用于存储和处理大规模数据集。HDFS编程实践实验原理主要涉及使用HDFS API进行文件的读写操作。 在编程实践中,首先需要配置Hadoop集群的环境。通过Hadoop配置文件,可以指定HDFS的相关参数,如NameNode和DataNode的地址以及端口号。 接下来,可以使用Java编程语言来编写HDFS的应用程序。HDFS提供了一套丰富的API,可以用于文件的读写操作。其中,主要包括创建文件、写入数据、读取数据以及删除文件等功能。 在文件的读写操作中,首先需要创建一个File对象,指定文件的路径。然后,使用FileSystem类的create()方法创建文件,并返回一个输出流,通过该输出流可以将数据写入文件中。类似地,可以使用FileSystem类的open()方法打开一个文件,并返回一个输入流,通过该输入流可以读取文件中的数据。 除了文件的读写操作,还可以使用FileSystem类的其他方法来获取文件信息,如文件的大小、修改时间等。此外,还可以使用FileSystem类的delete()方法来删除文件。 在实践中,还需要考虑故障恢复和容错处理。HDFS会将数据划分成多个块,并在集群中的不同节点上存储副本。如果某个节点发生故障,HDFS会自动将该节点上的副本转移到其他健康节点上,以保证数据的可靠性和高可用性。 总的来说,HDFS编程实践实验原理主要涉及使用HDFS API进行文件的读写操作,并结合HDFS的特性来提供可靠、高效的数据存储和处理功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值