均衡操作依靠一个均衡操作服务器、NameNode的代理和DataNode来实现,其逻辑流程如下:
其中,
Step1:Balance Server从Name Node中获取所有的Data Node情况,即每一个Data Node磁盘使用情况;
Step2: Balance Server计算哪些Dataode节点需要将数据移动,哪些Dataode节点可以接受移动的块数据,并且从NameNode中获取需要移动的数据分布情况;
Step3: Balance Server计算出来可以将哪一台Dataode节点的block移动到另一台机器中去;
Step4、5、6:需要移动block的DataNode节点将数据移动到目标DataNode节点上去,同时删除自己节点上的block数据;
Step7: Balance Server获取到本次数据移动的执行结果,并继续执行这个过程(称为迭代),一直到没有数据可以移动或者HDFS集群以及达到了平衡的标准为止。
1DataNode节点分析
代码
initNodes计算所有活着的且正常服务的dn节点对应的磁盘利用率以及集群平均的磁盘利用率,计算待移动的字节数,并且会根据当前的DataNode的磁盘使用率和阈值将所有的DataNode区分为如下四种类型:
(1)over组:此组中的DataNode的均满足
DataNode_usedSpace_percent > Cluster_usedSpace_percent+ threshold;
(2)above组:此组中的DataNode的均满足
Cluster_usedSpace_percent +threshold > DataNode_ usedSpace_percent > Cluster_usedSpace_percent;
(3)below组:此组中的DataNode的均满足
Cluster_usedSpace_percent >DataNode_ usedSpace_percent > Cluster_ usedSpace_percent –threshold;
(4)under组:此组中的DataNode的均满足
Cluster_usedSpace_percent –threshold > DataNode_usedSpace_percent;
用一个示例图表示:
对于上一节中提到的根据DataNode的磁盘使用率和阈值区分的四种类型,Balancer处理最上面和最下面的两个区域,对于位于Cluster_usedSpace_percent - threshold ~ Cluster_usedSpace_percent+ threshold间的DataNode认为已经是平衡的。threshold可以在启动时通过-thresld参数设置,默认为10.0%,如下图:
最终,将Balancer的移动对选择出来,如下分为Source和Target:
Source ={overUtilizedDatanodes,aboveAvgUtilizedDatanodes} Target = {belowAvgUtilizedDatanodes,underUtilizedDatanodes}
将Source对应的DataNode中的数据移动到Target对应的DataNode中,如下图:
在形成Balancer移动对中,每一对可以移动的字节数也同时被计算出,计算的代码列举如下:
上面代码加亮的部分显示了迭代中移动字节数的计算,首先,单个DataNode会根据上面提到的分类,计算其一次迭代中最大可以移动(移入或移出)的大小,如下图:
对于over和under区域的DataNode,每个迭代最大移动的大小为threshold * DataNode的容量(当然,使用率低于集群平均使用率的DataNode每个迭代最大移动的大小还要取threshold * DataNode的容量和DataNode的剩余容量中小的那一个),即每个迭代移动结束,并不一定保证over和under区域的DataNode一定平衡。
对于above和below区域的DataNode,每个迭代最大移动的大小为Math.abs(avgUtil-utilization)*DataNode的容量,即每个迭代移动结束,这两个区域的DataNode依然处于平衡状态。
最后,根据上述原则计算出的移动字节大小,还要和MAX_SIZE_TO_MOVE比较,两者取小,因而,增大MAX_SIZE_TO_MOVE的取值也有利于提升单次迭代的移动量,从而减少迭代次数,提升Balancer速度,但显然,该值是次要影响因素,因为需要从两个值中选取小的。
代码
针对匹配好的<source,target>移动对,创建一个线程,加入dispatcherExecutor中,主要迁移工作代码逻辑如下:
上述代码中,BlockMoveDispatcher调用了dispatchBlocks函数,该函数完成主要迁移工作,其流程图见下:
上一节的流程图中,带阴影的“进行块移动”涉及DataNode的OP_REPLACE_BLOCK操作,具体如下:Balancer会向相关的目标DataNode节点发出一个OP_REPLACE_BLOCK 消息,接收到这个消息的DataNode节点,会将从源DataNode节点传输来的数据块写入本地,写成功后,通知NameNode,删除源DataNode上的同一个数据块。
其代码摘录如下:
这里涉及的网络带宽和并行度,直接影响balance的速度,是主要因素,ZDH提供按需动态配置,配置方法见本公众号上期文章。
代码
一次迭代之后,会根据返回值,确认是否再进行下一轮迭代,两次迭代间进行休眠,休眠时间缺省为6秒。