vlambda博客
学习文章列表

实战!HDFS集群负载不均衡问题


背景环境说明

        某项目现场HDFS集群有五台机器,其中两台机器分别部署NameNode、SecondNameNode,另外三台机器部署DataNode节点(这里就不吐槽这种部署方式了)。

        由于历史原因,DataNode A、DataNode B机器的/data01、/data02、/data03均为8T,DataNode C机器的/data01、/data02均小于1T,/data03为8T。

        在使用了一段时间后,问题突显了——DataNode C上的/data01、/data02磁盘使用率将近70%,剩余所有8T的盘利用率均小于7%,若不及时处理,这两块较小的磁盘使用率达到100%时,那整个hdfs集群就不可用了。

        说明:

                该现场使用的是CDH HDFS 2.6.0版本。


解决过程

方案一、修改磁盘选择策略

        HDFS 2.X 版本将数据写入磁盘时,有两种策略——基于轮询的策略、基于可用空间的策略。默认情况下采用的是基于轮询的策略。

        基于轮询的策略,即每次写入都会采用轮询的方式,由于每次写入的数据量不一致,且这套环境大小磁盘差距这么大,更容易出现磁盘利用率相差很大的现象。

        基于可用空间的策略,在这里策略之下,会计算出可用磁盘空间,磁盘空间大的,写入的概率会更大,这在一定程度上减少了磁盘利用率的差距。

        修改方式,打开hdfs-site.xml,修改如下配置项:

配置项
配置值
dfs.datanode.fsdataset.volume.choosing.policy org.apache.hadoop.hdfs.server.datanode.fsdataset.AvailableSpaceVolumeChoosingPolicy
dfs.datanode.available-space-volume-choosing-policy.balanced-space-threshold 默认值10G。当磁盘中最大可用空间与最小可用空间的差值小于这个阈值,则认为存储是平衡的,直接采用轮询来选择卷。
dfs.datanode.available-space-volume-choosing-policy.balanced-space-preference-fraction 默认值0.75。它的含义是数据块存储到可用空间多的卷上的概率。

        根据上述配置项的含义,可以知道修改磁盘写入策略,并不能解决该问题,磁盘在剩余10G以前,都是采用轮询的方式,小磁盘利用率很快就使用的很高。

方案二、HDFS Balancer

        在其他的现场,也曾出现过datanode数据倾斜,导致Spark任务运行时,各种网络开销,资源使用差距大的情况。此种情况下,我司使用HADOOP提供的start-balancer.sh脚本,使用方式如下:

首先,修改hdfs-site.xml中网络带宽限制,默认1MB/s,此处改为100MB/s。

<property>  <name>dfs.balance.bandwidthPerSec</name>  <value>104857600</value></property>

其次,启动数据均衡,阈值 5%

bin/start-balancer.sh -threshold 5

        可惜的是,在该场景下使用start-balancer.sh后,发现这两块小磁盘的使用率并没有减少,并发现从DataNode层面来看,数据存储是均匀的。于是乎我就查了相关的资料,我的猜想得到了证实——start-balancer.sh只能用于datanode之间的负载均衡,做不到磁盘间的负载均衡。


方案三、disk balancer

       该方案仅限于Hadoop 3.x版本,对于本项目的CDH HDFS 2.6版本,并不适用。

        HDFS 磁盘均衡器在DataNode中以线程的形式运行,并在相同存储类型的卷之间移动数据。这与方案二中start-balancer.sh不同,start-balancer.sh作用于datanode之间的负载均衡。

使用方式如下:

首先,修改所有datanode节点的hdfs-site.xml

dfs.disk.balancer.enabled设置为true

其次,获取本DataNode的信息,并用如下命令生成执行计划

hdfs diskbalancer -plan 主机名

接着,执行磁盘均衡器脚本

hdfs diskbalancer -execute /plan.json

最后,可以用如下命令查看disk balancer的执行进度

hdfs diskbalancer -query 主机名:20001


方案四、卸掉小磁盘

        上述三种方案对于我这种场景都不适用,现场项目经理也协调不到更多的磁盘,目前我给出的方案就是卸掉这两块小磁盘,延缓出现木桶效应。

        去掉小盘的方式,也很简单,就两步骤。

        其一,停止datanode节点。

        其二,修改hdfs-site.xml,将dfs.datanode.data.dir中的小磁盘路径去掉。

        最后,重启datanode节点即可。

在这个方案实施过程中,我还发现两个问题。

问题一、停止datanode后,在50070页面上并未直接反应出该datanode已下线。

namenode感知到datanode下线时间,由这两个配置项决定。

<property> <name>dfs.heartbeat.interval</name> <value>3</value> <description>Determines datanode heartbeat interval in seconds.</description></property><property>  <name>dfs.namenode.heartbeat.recheck-interval</name>  <value>300000</value>  <description>The unit of this configuration is millisecond.</description></property>

具体公式

      2*dfs.namenode.heartbeat.recheck-interval+10*dfs.heartbeat.interval

        所以默认下线时间为10分30秒。

问题二、重启datanode后,再次登录hdfs 50070页面,会发现可能有块丢失,具体告警信息如下:

There are 2 missing blocks. The following files may be corrupted:blk_123456 /user/part-c000.snappy.parquet

理论上,hdfs 文件是三副本的,为啥卸掉一块盘会出现块丢失呢?

经查看,这些文件都是单副本的。所以这种卸载磁盘的方式确实会导致单副本文件丢失。

[zsf@zsf166 logs]$ hdfs dfs -ls /user/zsfFound 152 items-rwxrwxrwx 1 rhino supergroup 70296 2019-10-25 16:21 /user/zsf/__spark_conf__.zip-rwxrwxrwx 1 rhino supergroup 20195 2019-10-25 16:21 /user/zsf/annotations-12.0.jar-rwxrwxrwx 1 rhino supergroup 95536 2019-10-25 16:21 /user/zsf/apache-mime4j-core-0.7.2.jar

总结

1、基于轮询、基于可用空间的写入磁盘策略,不能避免负载不均匀现象的发生。

2、start-balancer.sh从DataNode层面来均衡负载。disk balancer在DataNode内部的磁盘间达到负载均衡

3、对于低版本HDFS,只能通过一块块的卸载小磁盘来避免小磁盘带来的影响。


参考链接

1http://mp.weixin.qq.com/s?__biz=MzI4OTY3MTUyNg==&mid=2247489557&idx=1&sn=65ff210ef504b82aee1435a0ae142747&scene=6#wechat_redirect2https://www.cnblogs.com/roger888/p/5504586.html3https://www.jianshu.com/p/d0c59d874dfd4、https://www.jianshu.com/p/f7c1cd4766015、https://my.oschina.net/u/3197158/blog/1601649