在集群规模日益增大的背景下,集群内运行的机器类型可能也会变得越来越多,可能一部分机器磁盘读写性能比较好,又可能说那部分机器网络情况较好,还有的是CPU计算资源比较好的机器.面对这么多机型的节点,我们当然不能”一视同仁”,否则对于这些机器来说,就是一种资源浪费.在Job运行的层面(在YARN层面)而言,已经可以支持通过打NodeLabel标签的形式,让application运行在指定nodeLabel的节点上,以此做到计算资源的充分利用以及任务运行的资源隔离.那么现在问题来了,在数据存储的层面(在HDFS层面)而言,是否也能支持这种NodeLabel的机制呢?本文探讨的主题就是HDFS NodeLabel特性,与YARN NodeLabel有一部分相似点.
HDFS NodeLabel最早的提出是在HDFS-9411(HDFS NodeLabel support)上,适用的背景正如前言中所描述的.正如HDFS-9411所显示的,此功能特性还尚且处于原型设计阶段,还并未进行实质的开发.但是尽管如此,此功能特性依然是一个很棒的特性,这也是为什么我会专门写一篇文章来介绍它的原因.Ok,扯得有点远了,重新回到正题,在YARN NodeLabel中,打标签的对象是nodemanager,用户通过给application打对应的标签,从而使得application跑在对应nodelabel的nodemanager上.我们可以进行对比和联系,在HDFS NodeLabel中,打标签的对象将会是DataNode和待写入的文件/目录.然后对应nodelabel的文件最后存储到对应的DataNode.看到这里,稍微熟悉HDFS的人可能马上会提出一点意见:这不正是HDFS异构存储的StoragePolicy机制所干的事情吗?不错,在这点上,二者的确有着比较大的相似性,归结下来一句话:
HDFS NodeLabel包含了部分StorageType的功能特点,但是相比后者,它的功能并不仅限于此,它能支持更加复杂的分组.
在后面的设计细节中,大家将会感觉到其中的异同.
在HDFS-9411的最新的设计文档中,将NodeLabel分为了以下2大类型:
对于第一种标签的使用场景,我们应该比较熟悉了,与HDFS的storageType的使用场景比较类似.这里我们来看看第二种标签的使用场景,比如我们有10台机器,其中node[1-5]被打上了Partition1的标签,而node[6-10]则被划分到了Partition2下.分段标签划分好之后,我们可以规定Partition1下的机器归属HBase使用,而Partition2下的则归属于Hive使用.这样的话,我们其实就做到了服务上的隔离.
以下是一些HDFS NodeLabel需要满足的要求点:
首先我们来看增删改label的操作命令,目标的命令格式如下:
// 创建label标签
hdfs nodelabels -createNodeLabel -name [-type labeltype] -acl
// 修改label标签
hdfs nodelabels -modifyNodeLabelACL -name [-x] -acl
// 删除label标签
hdfs nodelabels -removeNodeLabel -name
// 列表label标签
hdfs nodelabels -listNodeLabels [datanode-name]
hdfs nodelabels -listNodesForLabel -name
集群中的标签创建好了之后,接下来的操作就是将label与各个DataNode进行关联,将标签打到节点上,模板命令如下:
// 将label标签管理到指定节点
hdfs nodelabels -addDataNodeLabel -name <labelname> [-type <labeltype>] <dn_ipc_addess>
// 将label从指定节点上移除
hdfs nodelabels -removeDataNodeLabel -name <labelName> <dn_ipc_addess>
前面2步操作完成之后,最后一步就是对目标写入文件的标签设置,操作的目的是将对应label的文件存储到对应label的DataNode上.操作的模板命令如下:
// 对指定文件/目录的path设置label表达式
hdfs nodelabels –setLabelExpression <expression> <path>
// 清空指定文件/目录的path的label表达式
hdfs nodelabels –clearLabelExpression <expression> <path>
从上面的命令中,我们看到这里对于文件目录的标签设置采用的expression的形式而不是纯label的方式,设计者有什么用意在里面呢?答案是为了更加的灵活性.以社区设计文档中所提到的例子为例,假设当前结构如下:
从上图我们可以看出,逻辑上DN被分为了Partition1和Partition2两个分段,然后在细节上,部分DN还被打上了各自的特性标签LABEL1,2等等.此时我们对某文件设置了如下表达式的label:
(LABEL_1 || LABEL_2) && PART_A
于是在上图中,此文件将会选择DN1,DN2,DN3作为目标存储节点.在设计的初期,为了实现的简单性,我们只需支持||和&&2种表达式操作即可.
HDFS Label的引入对原本的block放置策略不会造成根本影响,但是在选择目标节点的方法上需要做一些改变,如下:
原方法:
public abstract DatanodeStorageInfo[] chooseTarget(String srcPath,
int numOfReplicas,
Node writer,
List chosen,
boolean returnChosenNodes,
Set excludedNodes,
long blocksize,
BlockStoragePolicy storagePolicy,
EnumSet flags);
在此增加一个参数,用于label标签的判断:
public abstract DatanodeStorageInfo[] chooseTarget(String srcPath,
int numOfReplicas,
Node writer,
List chosen,
boolean returnChosenNodes,
Set excludedNodes,
long blocksize,
BlockStoragePolicy storagePolicy,
EnumSet flags,
NodeLabelExpression labelExpression);
NodeLabel标签相关的统计同样是不可忽视的一点,主要有以下一些指标统计(针对的前提都为单个NodeLabel):
在未来的实现中,我们还需要完善NodeLabel相关周边服务的支持,主要在于以下2点:
第一点, WebUI的NodeLabel显示支持.
第二点, 围绕NodeLabel相关节点的Balancer数据平衡的操作.
在官方的设计文档中,只提到了以下两点:
尽管HDFS NodeLabel功能还未实现,但是我们可以看一下与其在设计思路上极为类似的YARN NodeLabel.前面小节列出的许多HDFS NodeLabel的实现点在YARN的NodeLabel已经有了实现.下面列出其中几点.
首先是NodeLabel的持久化,在YARN中通过配置项yarn.node-labels.fs-store.root-dir来控制NodeLabel的存储,此配置项目可以是HDFS上的路径或者是一个本地的文件路径,如下:
// hdfs存储路径
hdfs://namenode:port/path/to/store/node-labels/
// 本地文件系统存储路径
file:///home/yarn/node-label
以此做到重启集群的时候NodeLabel信息不会丢失.
又比如说,NodeLabel在WebUI上的显示,在链接http://RM-Address:port/cluster/nodelabels上可以查看,上面还汇集了每个NodeLabel下的总资源情况.
以此我们可以类比出HDFS NodelLabel的UI统计显示.但是在仔细查看YARN NodeLabel的细节中,它还能支持queue上的label配置,以此来控制此队列上的任务只能使用对应label的资源.
本文的内容主要来自于HDFS-9411的设计文档,本文算是对其的一个缩略的译文,相信HDFS NodeLabel的功能特性将会是一个很棒的特性.
[1].https://issues.apache.org/jira/browse/HDFS-9411
[2].https://issues.apache.org/jira/secure/attachment/12811794/HDFSNodeLabels-20-06-2016.pdf
[3].http://hadoop.apache.org/docs/current/hadoop-yarn/hadoop-yarn-site/NodeLabel.html