前言
初看这个标题,可能很多人会心生疑问:符号链接和硬链接是什么意思?这些概念不是在Linux操作系统下才有的嘛,HDFS目前也有?当然大家可能还会有其他疑问,没关系,在后面的内容讲述中答案会一一揭晓。归纳起来一句话:不管是符号链接还是硬链接,它们本质上都是一种快捷的链接方式。熟悉Linux系统的同学应该都知道在Linux文件系统下有硬链接和软链接的概念,而HDFS同样作为一套文件系统,它也能支持文件链接的形式。本文所讲述的主题正是HDFS下的文件链接操作。
相关背景:Linux软链接和硬链接
在讲述HDFS下的文件链接内容之前,有必要了解一下相关内容:Linux软链接和硬链接。因为HDFS文件链接的原理设计基本与此相似。Linux软链接和硬链接分别代表着2种截然不同的连接形式,它们在作用上也存在部分微妙的差异。
软链接
软链接又被称为符号链接,英文名称soft link或symbolic link(HDFS内采用的软链接名称就是symbolic link,简称symlink)。就个人感觉而言,软链接在实际工作中用得频率会略高于硬链接。一句话简单地概括软链接的作用:
软链接其实就是文件的一个快捷方式,软链接删除了,其指向的真实文件并不会受到影响。
所以在实际的工作中,我们一般会把依赖资源包的路径用软链接的方式引用,这样的话资源包的路径可以一直保持不变,而其所指向的真实资源包可以根据使用场景进行任意变化。
硬链接
硬链接,英文名称为hard link。它的一个主要目的在于文件的共享。文件的硬链接创建出来之后,它具有如下的特点:
硬链接相当于文件的一个别名。它指向的是一个文件inode的引用地址,而非软链接中的文件路径指向。所以对于硬链接中的文件做修改会影响到其所指向的真实文件,当对硬链接做删除动作后,如果其所指向的文件inode当前没有被外部引用的话,则原文件会被删除,否则原文件不会被删除。
上面的意思通俗地解释就是说,当真实文件或此文件的硬链接有一个存在的情况下,对文件执行删除操作,文件不会被真正删除。当只剩下一个文件inode引用的情况下,删除操作才能生效。
HDFS符号链接(软链接)与硬链接概述
了解完Linux下的软链接与硬链接的概念后,我们将进入本文的主题:HDFS下的符号链接与硬链接。
Hadoop社区在HDFS-245(Create symbolic links in HDFS)中优先对符号链接功能进行了实现。符号链接另外一部分的工作在HADOOP-6421(Symbolic links)中,此部分是HADOOP-COMMON模块相关的底层代码改动。在硬链接方面,社区目前有相关的JIRA:HDFS-3370(HDFS hardlink),但是社区目前并没有在跟进,只有初始的设计文档。所以本文准备讲述的HDFS硬链接将会是一个设计模型,并未真正实现,这点需要注意。
鉴于目前HDFS的硬链接功能并未真正实现,所以本文的主讲内容还是符号链接的功能,硬链接功能将给出大致设计模型。
HDFS符号链接(软链接)
HDFS符号链接,在HDFS中称之为symbolic link,在下文的讲述中此名称都将会简称为symlink。与Linux文件系统中的软链接概念一样,HDFS符号链接也是相当于给目标文件新建一个自定义路径,这个自定义路径实质指向目标文件。所以在这里HDFS符号链接中做的最重要的事情就是路径的解析。而且这个解析还有可能是嵌套的,符号链接中指向的是另外一个符号链接。下面来学习HDFS符号链接的主要原理实现。
HDFS符号链接原理
HDFS符号链接功能的实现主要分为2个部分:一个是对现有文件符号链接的添加,另外一个则是符号链接的解析过程。
对现有文件符号链接的添加在HDFS中的实现就是添加一个新的INode对象在NameNode中,只是这个INode对象是Symlink类型的,叫做INodeSymlink。此对象内部会包含一个实际指向的target地址。
而符号链接的解析过程则会略微复杂一些,HDFS并不是直接在NameNode最终处理方法的地方做解析的,而是在前面一层FileContext类上做解析的,然后将解析好后的路径再传到HDFS中做处理。换句话说,客户端需要通过FileContext上下文对象来操作符号链接相关的操作,如果直接用FileSystem的API来操作的话,会抛出解析异常的错误。
HDFS符号链接核心代码实现
此部分我们将通过部分代码的跟踪来学习HDFS符号链接的实现过程。
同样首先是创建符号链接的过程,我们直接进入到最终的服务端处理方法,FSNamesystem的createSymlink方法。
*// 为目标文件创建一个符号链接
void createSymlink(String target, String link,
PermissionStatus dirPerms, boolean createParent, boolean logRetryCache)
throws IOException {
if (!FileSystem.areSymlinksEnabled()) {
throw new UnsupportedOperationException("Symlinks not supported");
}
HdfsFileStatus auditStat = null;
writeLock();
try {
checkOperation(OperationCategory.WRITE);
checkNameNodeSafeMode("Cannot create symlink " + link);
// 此处进入创建软链接实际操作
auditStat = FSDirSymlinkOp.createSymlinkInt(this, target, link, dirPerms,
createParent, logRetryCache);
...
我们继续进入FSDirSymlinkOp的createSymlinkInt方法,
static HdfsFileStatus createSymlinkInt(
FSNamesystem fsn, String target, final String linkArg,
PermissionStatus dirPerms, boolean createParent, boolean logRetryCache)
throws IOException {
FSDirectory fsd = fsn.getFSDirectory();
String link = linkArg;
// 检验符号链接的名称
if (!DFSUtil.isValidName(link)) {
throw new InvalidPathException("Invalid link name: " + link);
}
if (FSDirectory.isReservedName(target) || target.isEmpty()
|| FSDirectory.isExactReservedName(target)) {
throw new InvalidPathException("Invalid target name: " + target);
}
if (NameNode.stateChangeLog.isDebugEnabled()) {
NameNode.stateChangeLog.debug("DIR* NameSystem.createSymlink: target="
+ target + " link=" + link);