一、引言:
Hadoop的HDFS集群非常容易出现机器与机器之间磁盘利用率不平衡的情况,比如集群中添加新的数据节点,节点与节点之间磁盘大小不一样等等。当hdfs出现不平衡状况的时候,将引发很多问题,比如MR程序无法很好地利用本地计算的优势,机器之间无法达到更好的网络带宽使用率,机器磁盘无法利用等等。
二、问题:
因业务需要搭建一个新hadoop集群,并将老的hadoop集群中的数据迁移至新的hadoop集群,而且datanode节点不能全部上线,其中还可能会出现节点上线或下线的情况,这个时候就很容易出现机器与机器之间磁盘的均衡的情况,具体如下:
上图中可以看出max是94.18%,而min是0.37%,其中有600多台是达到94%的,这个时候在跑mapred的时候往往会报错误:
登陆到该机器上查看服务器的磁盘,磁盘都快已经达到100%,如下:
因为我们在hdfs-site.xml中设置了dfs.datanode.du.reserved的值,所以磁盘会有一定预留空间:
dfs.datanode.du.reserved107374182400
上面这个参数的意思:
Reserved space in bytes per volume. Always leave this much space free for non dfs use.
再查看datanode日志,希望能找到可靠的线索:
这种错误无法通过namenode来避免,因为它不会再failed的时候去尝试往别的节点写数, 最初的办法是将该节点的datanode关闭掉,就能顺利地跑完这个mapreduce。
再者查看namenode的页面,看到有好多datanode的节点的Remaining快要趋于0B了,这个时候就很容易出现上面的报错。
为了防止上面的报错再次出现以及避免hdfs数据不均衡,对hadoop集群做balance已经不可避免了!
二、解决方案
1、balancer
大家首先会想到hadoop自带的balancer,那就先介绍一下balancer!
Balancer.java中是这么描述balancer的:
The balancer is a tool that balances disk space usage alt="" width="550" height="256" />
考虑到balancer是最近需要经常做的操作,所以我们自己开发了一个查看balancer情况的页面,结果如下:
上图可以看到每个集群下balancer执行情况。
balance一天能成功移动的数据量大约在10-20T,这个数据量很难满足超大集群。
目前我们调用balance会使用如下命令:
start-balancer.sh -threshold 20 -policy blockpool -include -f /tmp/ip.txt
上面的命令通过手工筛选出磁盘高的和磁盘低的放在ip.txt文件中,这样balance就只通过这文件里的了,另外还需要设置适当的threshold值,因为是多namespace的,所以需要选择blockpool模式。
另外带宽也是限制balance的一个因素,在hdfs-site.xml中是有设置的:
dfs.datanode.balance.bandwidthPerSec10485760
但是这个需要重启,hadoop提供了一个动态调整的命令:
hdfs dfsadmin -fs hdfs://ns1:8020 -setBalancerBandwidth 104857600 hdfs dfsadmin -fs hdfs://ns2:8020 -setBalancerBandwidth 104857600
2、上下节点:
其实将高磁盘的节点强制Decommission是最快最有效的方案。
下节点的时候可能会出现有ns不能正常下掉的情况,其实这个时候节点的数据大部分已经移出去了,可能有一些块卡在那边没有移出去。
这个时候只能一个一个节点将已经Decommissioned节点stop掉datanode进程,如果在namenode的页面上看到有丢失块的话,就需要将这个块先get到本地,在put上去。例如: