当前位置:   article > 正文

HDFS-Datanode磁盘选择策略分析_org.apache.hadoop.hdfs.server.datanode.fsdataset.a

org.apache.hadoop.hdfs.server.datanode.fsdataset.availablespacevolumechoosin

概述

Hadoop技术体系中,hdfs是重要的技术之一,而真实的数据都存储在datanode节点之上,DataNode 将数据块存储到本地文件系统目录中,而每个datanode节点可以配置多个存储目录(可以是不同类型的数据硬盘),hdfs-site.xml (dfs.datanode.data.dir 参数)。

一般的hadoop集群datanode节点会配置多块数据盘,当我们往 HDFS 上写入新的数据块,DataNode 将会使用 volume 选择策略来为数据块选择存储的磁盘目录。目前有两种volume选择策略:

  • round-robin  (default)

  • available space

遇到的问题:

由于hadoop集群规模一般比较大,且需要长期维护,所以会涉及到很多流程以及操作,例如:扩容新服务器、定期更换坏盘、下线服务器、删除历史数据等等。 所以会造成节点间的数据不平衡,以及datanode节点上多个磁盘之间的不平衡问题。

1. 节点间的数据不平衡,可以通过hdfs 本身的balancer工具进行数据平衡;

2. datanode节点上多个磁盘之间数据不平衡,Hadoop 3.0 引入了磁盘均衡器(diskbalancer)。

这里先抛出一个问题:为什么datanode本身的磁盘选择策略没有很好的解决这些数据不平衡问题呢?

 

下面分析下datanode磁盘选择相关的源码:

hdfs-site.xml: 配置项 dfs.datanode.fsdataset.volume.choosing.policy

org.apache.hadoop.hdfs.server.datanode.fsdataset.RoundRobinVolumeChoosingPolicy   (default)

org.apache.hadoop.hdfs.server.datanode.fsdataset.AvailableSpaceVolumeChoosingPolicy
 

A. RoundRobinVolumeChoosingPolicy:

  1. /**
  2. * Choose volumes in round-robin order.
  3. */
  4. public class RoundRobinVolumeChoosingPolicy<V extends FsVolumeSpi>
  5. implements VolumeChoosingPolicy<V> {
  6. public static final Log LOG = LogFactory.getLog(RoundRobinVolumeChoosingPolicy.class);
  7. private int curVolume = 0;
  8. @Override
  9. public synchronized V chooseVolume(final List<V> volumes, long blockSize)
  10. throws IOException {
  11. if(volumes.size() < 1) {
  12. throw new DiskOutOfSpaceException("No more available volumes");
  13. }
  14. // since volumes could've been removed because of the failure
  15. // make sure we are not out of bounds
  16. if(curVolume >= volumes.size()) {
  17. curVolume = 0;
  18. }
  19. int startVolume = curVolume;
  20. long maxAvailable = 0;
  21. // 遍历磁盘列表
  22. while (true) {
  23. final V volume = volumes.get(curVolume);
  24. curVolume = (curVolume + 1) % volumes.size();
  25. long availableVolumeSize = volume.getAvailable();
  26. // 可用空间大于数据块,直接返回volume
  27. if (availableVolumeSize > blockSize) {
  28. return volume;
  29. }
  30. // 更新最大可用空间
  31. if (availableVolumeSize > maxAvailable) {
  32. maxAvailable = availableVolumeSize;
  33. }
  34. // 未找到合适的存储磁盘
  35. if (curVolume == startVolume) {
  36. throw new DiskOutOfSpaceException("Out of space: "
  37. + "The volume with the most available space (=" + maxAvailable
  38. + " B) is less than the block size (=" + blockSize + " B).");
  39. }
  40. }
  41. }
  42. }

可见,这种轮询的实现目的也是为了数据均衡,这种轮询的方式虽然能够保证所有磁盘都能够被使用,但是由于这种算法实现只是按照block数量进行轮询选择,而没有考虑到每次存储的block大小,如果每次存储的block大小相差很大,也会造成磁盘数据不均衡;另外如果HDFS 上的文件存在大量的删除操作,也可能会导致磁盘数据的分布不均匀。 

看下第二种实现方式.

B. AvailableSpaceVolumeChoosingPolicy:

  1. /**
  2. * A DN volume choosing policy which takes into account the amount of free
  3. * space on each of the available volumes when considering where to assign a
  4. * new replica allocation. By default this policy prefers assigning replicas to
  5. * those volumes with more available free space, so as to over time balance the
  6. * available space of all the volumes within a DN.
  7. */
  8. public class AvailableSpaceVolumeChoosingPolicy<V extends FsVolumeSpi>
  9. implements VolumeChoosingPolicy<V>, Configurable {
  10. // 加载并初始化配置 (省略)
  11. .................
  12. // 用于需要平衡磁盘的轮询磁盘选择策略
  13. private final VolumeChoosingPolicy<V> roundRobinPolicyBalanced =
  14. new RoundRobinVolumeChoosingPolicy<V>();
  15. // 用于可用空间高的磁盘的轮询磁盘选择策略
  16. private final VolumeChoosingPolicy<V> roundRobinPolicyHighAvailable =
  17. new RoundRobinVolumeChoosingPolicy<V>();
  18. // 用于可用空间低的磁盘的轮询磁盘选择策略
  19. private final VolumeChoosingPolicy<V> roundRobinPolicyLowAvailable =
  20. new RoundRobinVolumeChoosingPolicy<V>();
  21. @Override
  22. public synchronized V chooseVolume(List<V> volumes,
  23. long replicaSize) throws IOException {
  24. if (volumes.size() < 1) {
  25. throw new DiskOutOfSpaceException("No more available volumes");
  26. }
  27. AvailableSpaceVolumeList volumesWithSpaces =
  28. new AvailableSpaceVolumeList(volumes);
  29. // 如果磁盘都在数据平衡阈值(可配置)之内,则直接使用轮询策略选择磁盘
  30. if (volumesWithSpaces.areAllVolumesWithinFreeSpaceThreshold()) {
  31. // If they're actually not too far out of whack, fall back on pure round
  32. // robin.
  33. V volume = roundRobinPolicyBalanced.chooseVolume(volumes, replicaSize);
  34. if (LOG.isDebugEnabled()) {
  35. LOG.debug("All volumes are within the configured free space balance " +
  36. "threshold. Selecting " + volume + " for write of block size " +
  37. replicaSize);
  38. }
  39. return volume;
  40. } else {
  41. V volume = null;
  42. // 如果没有一个低自由空间的体积有足够的空间存储副本时,总是尽量选择有大量空闲空间的卷。
  43. // 从低剩余磁盘列表中选取最大可用空间(磁盘可用)
  44. long mostAvailableAmongLowVolumes = volumesWithSpaces
  45. .getMostAvailableSpaceAmongVolumesWithLowAvailableSpace();
  46. // 高可用空间磁盘列表
  47. List<V> highAvailableVolumes = extractVolumesFromPairs(
  48. volumesWithSpaces.getVolumesWithHighAvailableSpace());
  49. // 低可用空间磁盘列表
  50. List<V> lowAvailableVolumes = extractVolumesFromPairs(
  51. volumesWithSpaces.getVolumesWithLowAvailableSpace());
  52. // 平衡比值
  53. float preferencePercentScaler =
  54. (highAvailableVolumes.size() * balancedPreferencePercent) +
  55. (lowAvailableVolumes.size() * (1 - balancedPreferencePercent));
  56. float scaledPreferencePercent =
  57. (highAvailableVolumes.size() * balancedPreferencePercent) /
  58. preferencePercentScaler;
  59. // 如果低可用空间磁盘列表中最大的可用空间无法满足副本大小
  60. // 或随机概率小于比例值,就在高可用空间磁盘中进行轮询调度选择
  61. if (mostAvailableAmongLowVolumes < replicaSize ||
  62. random.nextFloat() < scaledPreferencePercent) {
  63. volume = roundRobinPolicyHighAvailable.chooseVolume(
  64. highAvailableVolumes, replicaSize);
  65. if (LOG.isDebugEnabled()) {
  66. LOG.debug("Volumes are imbalanced. Selecting " + volume +
  67. " from high available space volumes for write of block size "
  68. + replicaSize);
  69. }
  70. } else {
  71. // 否则在低可用空间列表中选择
  72. volume = roundRobinPolicyLowAvailable.chooseVolume(
  73. lowAvailableVolumes, replicaSize);
  74. if (LOG.isDebugEnabled()) {
  75. LOG.debug("Volumes are imbalanced. Selecting " + volume +
  76. " from low available space volumes for write of block size "
  77. + replicaSize);
  78. }
  79. }
  80. return volume;
  81. }
  82. }

 

高\低可用空间磁盘列表调用逻辑:

  1. /**
  2. * Used to keep track of the list of volumes we're choosing from.
  3. */
  4. private class AvailableSpaceVolumeList {
  5. // 省略
  6. ................
  7. /**
  8. * @return the maximum amount of space available across volumes with low space.
  9. */
  10. public long getMostAvailableSpaceAmongVolumesWithLowAvailableSpace() {
  11. long mostAvailable = Long.MIN_VALUE;
  12. for (AvailableSpaceVolumePair volume : getVolumesWithLowAvailableSpace()) {
  13. mostAvailable = Math.max(mostAvailable, volume.getAvailable());
  14. }
  15. return mostAvailable;
  16. }
  17. /**
  18. * @return the list of volumes with relatively low available space.
  19. */
  20. public List<AvailableSpaceVolumePair> getVolumesWithLowAvailableSpace() {
  21. long leastAvailable = getLeastAvailableSpace();
  22. List<AvailableSpaceVolumePair> ret = new ArrayList<AvailableSpaceVolumePair>();
  23. for (AvailableSpaceVolumePair volume : volumes) {
  24. // 可用空间小于 (最小可用空间+平衡阀值)
  25. if (volume.getAvailable() <= leastAvailable + balancedSpaceThreshold) {
  26. ret.add(volume);
  27. }
  28. }
  29. return ret;
  30. }
  31. /**
  32. * @return the list of volumes with a lot of available space.
  33. */
  34. public List<AvailableSpaceVolumePair> getVolumesWithHighAvailableSpace() {
  35. long leastAvailable = getLeastAvailableSpace();
  36. List<AvailableSpaceVolumePair> ret = new ArrayList<AvailableSpaceVolumePair>();
  37. for (AvailableSpaceVolumePair volume : volumes) {
  38. // 可用空间大于 (最小可用空间+平衡阀值)
  39. if (volume.getAvailable() > leastAvailable + balancedSpaceThreshold) {
  40. ret.add(volume);
  41. }
  42. }
  43. return ret;
  44. }
  45. }

可见,可用空间策略设计原理是根据配置平衡阀值划分磁盘分为两类列表:高可用空间磁盘列表、低可用空间列表,通过随机数概率,会相应较高概率选择高可用空间列表中的磁盘;

 

分析到这里,感觉可用空间策略可以很好的解决磁盘数据不平衡问题,为什么datanode应用的默认策略还是基于轮询磁盘选择策略呢?

长期运行的集群中会遇到这样一种场景,hdfs所有的datanode节点磁盘使用率很高,已达90%以上,这时在一个datanode节点更换一个磁盘,如果采用可用空间策略,新增的数据块高概率都会往更换的新盘上写入,其他磁盘处于空闲状态,就会导致较低的磁盘IO效率,磁盘IO可能会成为整个集群的瓶颈 ;

 

总结:

经过对源码的分析,发现datanode的磁盘选择策略都在一定程度上保证了磁盘使用的均衡,但是都存在一定的问题,需要针对与不同的集群情况进行不断变换策略使用;
 

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/654528
推荐阅读
相关标签
  

闽ICP备14008679号