Router-based Federation架构下如何解析路径

为了回答文章标题的问题,先去官网RBF相关界面查阅文档。

Hey,我是官网

找到如下配置信息:

dfs.federation.router.file.resolver.client.class

image-20200723155716763

这个参数的描述信息是:解析文件属于哪个子集群,如果允许一个挂载点对应多个子集群,要把此参数设置为

org.apache.hadoop.hdfs.server.federation.resolver.MultipleDestinationMountTableResolver.

构造这个类的对象是在Router类:

image-20200723160959568

调用了FederationUtil#newFileSubclusterResolver方法。

image-20200723161045747

从配置文件中读出配置项,然后通过反射得到SubclusterResolver。最终赋值给Router类的成员。

image-20200723161245457

通过注释可以看到这个resolver的功能就是把一个全局名字空间映射到HDFS 子集群的名字空间。举个栗子:

全局名字空间的路径是hdfs://cluster/data。然后有两个子集群subcluster1,subcluster2。那刚才的全局名字空间就可能对应hdfs://subcluster1/data 和 hdfs://subcluster2/data等等。

好的进入正题,就去看这个MultipleDestinationMountTableResolver类。

1. MultipleDestinationMountTableResolver

看类的名字,直观翻译就是“多目的地丶挂载表丶解析器”。很容易理解,就是这个类会把一个给定的src路径,(如有必要)解析成在文件系统里的多个路径。因为现在namenode是federation的,挂载表(Mount Table)中的一个entry可以对应为多个namespace下的路径。我们看这个类的JavaDoc:

image

看划红线的部分,它说:返回的location是包含了优先级的remote paths,优先级是从高到低。那就证明这个类有个方法是返回location的方法。看下这个类的成员变量以及方法:

image-20200723101711012

果不其然,划红线的就是返回location的方法:getDestinationForPath

观察到这个方法是继承的,我们一路向上点。找到最顶层的方法声明:

这个方法的位置是:FileSubclusterResolver#getDestinationForPath

阅读JavaDoc:获取一个global path的目的地。Results是来自于mount table cache中的。如果global path确实有多个目的地,那Resuls中第一个是具有最高优先级的目的地。

接下来看成员变量:

image-20200723103048667

这个是个EnumMap的类型,它其实就是个Map,只不过key必须是DestinationOrder这个枚举类型里面指定的。那肯定也有像这个Map里添加数据的方法。在本类中是addResolver

image-20200723103247068

最后看一下构造方法:

image-20200723110456699

主要是添加一些Resolver。假设我们要自定义Resolver的话,也要在这里添加。

接下来明确一下思路:我们就看orderedResolvers成员变量的Key和Value类型。也即DestinationOrder枚举类和OrderedResolver类。

2. DestinationOrder

image-20200723111456988

枚举类:定义目的地排序规则。

3. OrderedResolver

这个是个接口,只有一个方法。看下Doc。

这个接口的作用是:多目的地的情况下,决定哪个会是第一个被访问的location。

image-20200723114052435

只有一个getFirstNamespace方法。作用就是这个接口描述的那样。根据这个方法获得first namespace。

分析到这里我们有两条路可以走,一条路是看OrderedResolver的实现类是怎么实现的。

image-20200723114558669

另一条路是看getFirstNamespace方法的第二个参数的PathLocation类型。

这里我们选第二条路,原因是选第一条路是属于“深度优先遍历”(进入细枝末节),选第二条路是“广度优先遍历”(了解整个框架)。

好的那下面就看PathLocation。

4. PathLocation

类介绍如下:

img-20200723164654

额外说一句:global path就是我们在客户端程序或者Web UI中的那个路径。

PathLocation它里面记录了关于一个global path的一些映射信息,比如global path映射到哪些目的地。它里面的数据是从MoutTable中的记录生成的。

三个成员变量分别代表 global path,  多个目的地的path(List),  还有一个DestinationOrder对象用来指定确定第一个location的规则。

image-20200723115636004

看一下方法,红线框起来的部分:

image-20200723120621461

阅读方法名和返回值大概知道是什含义。除去构造方法,其他都是一些获取成员变量的相关属性的方法。比如可以得到location的namespace名字的集合等。

那我们就得看是谁调用了PathLocation的构造方法,以及构造方法中的参数是怎么生成的。找到了下图这个构造方法是被MultipleDestinationMountTableResolver 调用的。

image-20200723121748014

进到MultipleDestinationMountTableResolver这个类:

image-20200723122116987

这个方法就是重写我们上面讲过的FileSubclusterResolver#getDestinationForPath方法。最后也是把mountTableResult这个PathLocation对象返回了。

看下这个方法的逻辑:

①首先调用父类MountTableResolver的同名方法的实现(挖的第一个坑),此时得到了一个PathLocation。

②上一步得到的PathLocation如果是null,打印些log error信息。如果PathLocation是多目的地的,就进入else if (mountTableResult.hasMultipleDestinations())`分支

③根据DestinationOrder对象得到对应的resolver对象。

④根据resolver的getFirstNamespace方法得到第一个命名空间的名字(String类型),这个方法的逻辑需要你使用的具体resolver的类去实现。一会儿我们再找一个Resolver的具体实现类分析(挖的第二个坑),现在我们假设,emmm,没错我们假设得到了firstNamespace。

⑤就把firstNamespace当作参数传给PathLocation的构造函数,构造函数会根据firstNamespace对传入的PathLocation对象mountTableResult排序。

⑥返回mountTableResult对象(无论是排序过的或者是没排序过的)

可以!刚刚我们挖了两个坑:

第一个:MountTableResolver#getDestinationForPath方法

第二个:找一个具体的resolver分析getFirstNamespace方法。

首先填第一个坑:MountTableResolver#getDestinationForPath方法

我们只需要知道原始的mountTableResult是怎么生成的就好了,于是根据下面这句代码走到MultipleDestinationMountTableResolver的父类MountTableResolver的这个方法的实现。

PathLocation mountTableResult = super.getDestinationForPath(path);

下面是MountTableResolver#getDestinationForPath方法的实现:

image-20200723135559703

方法逻辑很简单:

①做一些验证工作,并拿到读锁,这个锁的底层实现是JDK的ReentrantReadWriteLock。这里我们就不深入探讨了。

②从locationCache缓存对象中找PathLocation,没找到的话使用lookupLocation方法查找locations,返回值是PathLocation类型。并添加进locationCache缓存对象。这个缓存对象我们也不用太过关注,是google提供的缓存框架。

③释放读锁。

所以我们还需要进入lookupLocation方法:

image-20200723141951972

这个方法的逻辑也很简单:

①根据传入的path找到最深层的路径。理论上讲,最深层就是path自己,但是特殊情况是path传入的path不一定存在。举个栗子。我们传入 /ns1/data/study/。但是Mount中只存在/ns1/data/。那我们就找到能够最大匹配到的,也就是deepest的意思。findDeepest的代码我们就不看了,逻辑比较简单。

②如果返回的entry不为空,说明有部分目录或者全部匹配到了,那么直接就buildLocation。如果返回的entry为空,那么就使用默认的一些参数创建一个PathLocation返回。注意返回后,google的cache框架会进行缓存,这样下次就能查到了。buildLocation的逻辑也比较简单。里面用了for each语句去构造List<RemoteLocation\>对象。再把它传入PathLocation,这样我们就得到了心心念念的PathLocation对象,原来这么产生的。

接下来填第二个坑:找一个具体的resolver分析getFirstNamespace方法

此处我们找的是HashResolver类:

image-20200723152004040

这个方法的目标(不限于HashResolver类)是对于给定的path,以及这个path对应的PathLocation。按照具体的实现规则从PathLocation中找到第一个要处理namespace名称。

到这里我们几乎已经分析完了Router based Federation情况下,是怎么根据传入的path进行解析的。最后剩下的一点就是RemoteLocation类。还记得构造PathLocation时,可以传入List对象么?我们就补充一下RemoteLocation类作为收尾。

5. RemoteLocation

先看Doc,RemoteLocation这个类表示在remote namespace上的一个位置。它包括四个成员变量。分别是nameservice ID, namenode ID,在federation中的路径(srcPath), 目的路径(HDFS path)

image-20200723152919666

也就是说Remotelacation类似于一个原子的位置信息。他不能表示跨namenode的位置。但是可以通过List<RemoteLocation\>表示。


END!!

毁灭吧,赶紧的,累了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叹了口丶气

觉得有收获就支持一下吧~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值