数据块的复制当然需要一个源数据节点,从其上拷贝数据块至目标数据节点。那么数据块复制是如何选取复制源节点的呢?本文我们将针对这一问题进行研究。

在BlockManager中,chooseSourceDatanode()方法就是用来选取数据块复制时的源节点的,它负责解析数据块所属数据节点列表,并选择一个,用它作为数据块的复制源。其核心逻辑如下:

我们优先选择正处于退役过程中的数据节点而不是其他节点,因为前者没有写数据传输量因此相对不是很繁忙。我们不使用已退役节点作为数据源。否则我们从它们之中随机选择一个数据节点,其复制工作量还没有达到阈值,然而,如果一个复制是最高优先级的复制的话,我们会随机选择一个数据节点,而不管复制阈值的限制。

chooseSourceDatanode()方法代码如下:

  1. @VisibleForTesting
  2. DatanodeDescriptor chooseSourceDatanode(Block block,
  3. List<DatanodeDescriptor> containingNodes,
  4. List<DatanodeStorageInfo>  nodesContainingLiveReplicas,
  5. NumberReplicas numReplicas,
  6. int priority) {
  7. // 清空containingNodes列表
  8. // 包含指定block的节点列表
  9. containingNodes.clear();
  10. // 清空nodesContainingLiveReplicas列表
  11. // 包含指定block活跃副本的节点列表
  12. nodesContainingLiveReplicas.clear();
  13. DatanodeDescriptor srcNode = null;
  14. int live = 0;
  15. int decommissioned = 0;
  16. int corrupt = 0;
  17. int excess = 0;
  18. // 根据Block实例block从corruptReplicas中获取坏块副本所在数据节点集合nodesCorrupt
  19. Collection<DatanodeDescriptor> nodesCorrupt = corruptReplicas.getNodes(block);
  20. // 根据Block实例block从blocksMap中获取其对应的数据节点存储DatanodeStorageInfo实例storage
  21. for(DatanodeStorageInfo storage : blocksMap.getStorages(block)) {
  22. // 从数据节点存储DatanodeStorageInfo实例storage中获取数据节点描述信息node
  23. final DatanodeDescriptor node = storage.getDatanodeDescriptor();
  24. // 从excessReplicateMap集合中获取数据块集合excessBlocks,
  25. // 这些块对数据节点来说是多余的。我们最终会将这些多余的块删除。
  26. LightWeightLinkedSet<Block> excessBlocks =
  27. excessReplicateMap.get(node.getDatanodeUuid());
  28. // 根据数据节点的存储状态确定其是否为可用副本
  29. int countableReplica = storage.getState() == State.NORMAL ? 1 : 0;
  30. // 如果坏块节点集合nodesCorrupt中包含该节点,坏块数corrupt累加
  31. if ((nodesCorrupt != null) && (nodesCorrupt.contains(node)))
  32. corrupt += countableReplica;
  33. // 如果节点正在退役或者已经退役,退役数decommissioned累加
  34. else if (node.isDecommissionInProgress() || node.isDecommissioned())
  35. decommissioned += countableReplica;
  36. // 如果多余数据块集合中包含该数据块,则多余数excess累加
  37. else if (excessBlocks != null && excessBlocks.contains(block)) {
  38. excess += countableReplica;
  39. // 其他情况下
  40. } else {
  41. // 将该存储添加到nodesContainingLiveReplicas集合
  42. nodesContainingLiveReplicas.add(storage);
  43. // 累加活跃副本数live
  44. live += countableReplica;
  45. }
  46. // 将该节点添加到containingNodes集合
  47. containingNodes.add(node);
  48. // Check if this replica is corrupt
  49. // If so, do not select the node as src node
  50. // 如果为坏块,跳过
  51. if ((nodesCorrupt != null) && nodesCorrupt.contains(node))
  52. continue;
  53. // 如果复制级别不是最高级别,且数据节点正在复制的数据块数目大于等于最大复制块数maxReplicationStreams,跳过
  54. if(priority != UnderReplicatedBlocks.QUEUE_HIGHEST_PRIORITY
  55. && node.getNumberOfBlocksToBeReplicated() >= maxReplicationStreams)
  56. {
  57. continue; // already reached replication limit
  58. }
  59. // 如果数据节点getNumberOfBlocksToBeReplicated大于等于复制块数上线replicationStreamsHardLimit,跳过
  60. if (node.getNumberOfBlocksToBeReplicated() >= replicationStreamsHardLimit)
  61. {
  62. continue;
  63. }
  64. // the block must not be scheduled for removal on srcNode
  65. // 如果数据块为多余的数据块,直接跳过
  66. if(excessBlocks != null && excessBlocks.contains(block))
  67. continue;
  68. // never use already decommissioned nodes
  69. // 如果数据节点为已退役节点,跳过
  70. if(node.isDecommissioned())
  71. continue;
  72. // we prefer nodes that are in DECOMMISSION_INPROGRESS state
  73. // 如果数据节点正在退役,且srcNode还未选中,那么选择该数据节点为srcNode,并跳过
  74. if(node.isDecommissionInProgress() || srcNode == null) {
  75. srcNode = node;
  76. continue;
  77. }
  78. // 如果源数据节点srcNode正在退役,则跳过
  79. if(srcNode.isDecommissionInProgress())
  80. continue;
  81. // switch to a different node randomly
  82. // this to prevent from deterministically selecting the same node even
  83. // if the node failed to replicate the block on previous iterations
  84. if(DFSUtil.getRandom().nextBoolean())
  85. srcNode = node;
  86. }
  87. // 初始化数据块副本复制统计对象numReplicas
  88. if(numReplicas != null)
  89. numReplicas.initialize(live, decommissioned, corrupt, excess, 0);
  90. // 返回srcNode
  91. return srcNode;
  92. }

chooseSourceDatanode()方法的整体逻辑如下:

1、清空containingNodes列表:containingNodes为包含指定block的节点描述信息DatanodeDescriptor列表;

2、清空nodesContainingLiveReplicas列表:nodesContainingLiveReplicas为包含指定block活跃副本的节点存储DatanodeStorageInfo列表;

3、根据Block实例block从corruptReplicas中获取坏块副本所在数据节点集合nodesCorrupt;

4、根据Block实例block从blocksMap中获取其对应的数据节点存储DatanodeStorageInfo集合,并遍历每一个数据节点存储DatanodeStorageInfo实例storage:

4.1、从数据节点存储DatanodeStorageInfo实例storage中获取数据节点描述信息node;

4.2、从excessReplicateMap集合中获取数据块集合excessBlocks:这些块对数据节点来说是多余的,我们最终会将这些多余的块删除;

4.3、根据数据节点的存储状态确定其是否为可用副本countableReplica;

以下为统计数据块副本情况:

4.4、如果坏块节点集合nodesCorrupt中包含该节点,坏块数corrupt累加;

4.5、如果节点正在退役或者已经退役,退役数decommissioned累加;

4.6、如果多余数据块集合中包含该数据块,则多余数excess累加;

4.7、其他情况下:

4.7.1、将该存储添加到nodesContainingLiveReplicas集合;

4.7.2、累加活跃副本数live;

4.8、将该节点添加到containingNodes集合;

4.9、如果为坏块,跳过;

4.10、如果复制级别不是最高级别,且节点正在复制的数据块数目大于等于最大复制块数maxReplicationStreams,跳过;

4.11、如果数据节点getNumberOfBlocksToBeReplicated大于等于复制块数上线replicationStreamsHardLimit,跳过;

4.12、如果数据块为多余的数据块,直接跳过;

4.13、如果数据节点为已退役节点,跳过;

4.14、如果数据节点正在退役,且srcNode还未选中,那么选择该数据节点为srcNode,并跳过;

4.15、如果源数据节点srcNode正在退役,则跳过;

4.16、随机选择源数据节点;

5、初始化数据块副本复制统计对象numReplicas;

6、返回块复制源数据节点srcNode。

其中,有两个阈值需要单独说下,如下:

1、maxReplicationStreams:一个给定节点除最高优先级复制外复制流的最大数目,取参数dfs.namenode.replication.max-streams,参数未配置默认为2;

2、replicationStreamsHardLimit:一个给定节点全部优先级复制复制流的最大数目,取参数dfs.namenode.replication.max-streams-hard-limit,参数未配置默认为4。

从上述整理流程中,大致总结如下:

根据block从blocksMap中取数据块所在数据节点存储实例集合并遍历,统计数据块副本情况,包括损坏副本、多余副本、退役副本、活跃副本等,然后损坏副本、多余副本、退役节点直接跳过,这三种情况不能被选中为复制源数据节点,并且还有两种情况,一是如果复制级别不是最高级别,且数据节点正在复制的数据块数目大于等于最大复制块数maxReplicationStreams,二是如果数据节点正在复制的数据块数目大于等于复制块数上线replicationStreamsHardLimit,这两种情况也直接跳过,不能被选中为复制源数据节点,剩下的,则是随机选择源数据节点,并且其最喜欢选择正在退役的数据节点,这个最喜欢的意思是,选择的方式是随机选择,但是一旦正在退役节点被选中,则源节点不会再做变更,否则还是要通过随机选择来变更的。

HDFS源码分析数据块复制选取复制源节点的更多相关文章

  1. HDFS源码分析数据块复制监控线程ReplicationMonitor(二)

    HDFS源码分析数据块复制监控线程ReplicationMonitor(二)

  2. HDFS源码分析数据块校验之DataBlockScanner

    DataBlockScanner是运行在数据节点DataNode上的一个后台线程.它为所有的块池管理块扫描.针对每个块池,一个BlockPoolSliceScanner对象将会被创建,其运行在一个单独 ...

  3. HDFS源码分析数据块复制监控线程ReplicationMonitor(一)

    ReplicationMonitor是HDFS中关于数据块复制的监控线程,它的主要作用就是计算DataNode工作,并将复制请求超时的块重新加入到待调度队列.其定义及作为线程核心的run()方法如下: ...

  4. HDFS源码分析数据块复制之PendingReplicationBlocks

    PendingReplicationBlocks实现了所有正在复制的数据块的记账工作.它实现以下三个主要功能: 1.记录此时正在复制的块: 2.一种对复制请求进行跟踪的粗粒度计时器: 3.一个定期识别 ...

  5. HDFS源码分析数据块汇报之损坏数据块检测checkReplicaCorrupt()

    无论是第一次,还是之后的每次数据块汇报,名字名字节点都会对汇报上来的数据块进行检测,看看其是否为损坏的数据块.那么,损坏数据块是如何被检测的呢?本文,我们将研究下损坏数据块检测的checkReplic ...

  6. HDFS源码分析数据块之CorruptReplicasMap

    CorruptReplicasMap用于存储文件系统中所有损坏数据块的信息.仅当它的所有副本损坏时一个数据块才被认定为损坏.当汇报数据块的副本时,我们隐藏所有损坏副本.一旦一个数据块被发现完好副本达到 ...

  7. jQuery1.9.1源码分析--数据缓存Data模块

    jQuery1.9.1源码分析--数据缓存Data模块 阅读目录 jQuery API中Data的基本使用方法介绍 jQuery.acceptData(elem)源码分析 jQuery.data(el ...

  8. TeamTalk源码分析(十一) —— pc客户端源码分析

           --写在前面的话  在要不要写这篇文章的纠结中挣扎了好久,就我个人而已,我接触windows编程,已经六七个年头了,尤其是在我读研的三年内,基本心思都是花在学习和研究windows程序上 ...

  9. Netty源码分析 (七)----- read过程 源码分析

    在上一篇文章中,我们分析了processSelectedKey这个方法中的accept过程,本文将分析一下work线程中的read过程. private static void processSele ...

随机推荐

  1. How to not display “Commit point reached - logical record count” counts

      You can use the keyword silent, which is available in the options clause. You can set the followin ...

  2. Sum of bit differences among all pairs

    This article was found from Geeksforgeeks.org. Click here to see the original article. Given an inte ...

  3. [POI2010]Blocks

    题目大意: 给你一个长度为n的数列,给你m个数k. 对于每个k,你可以进行若干次操作,每次把一个超过k的数的多余部分移到旁边一个数. 问对于每个k,进行若干次操作以后,最长的满足每个数都不小于k的区间 ...

  4. unity3d 场景配置文件生成代码

    using UnityEngine; using UnityEditor; using System.IO; using System; using System.Text; using System ...

  5. log4j配置文件中的additivity属性

    它是 子Logger 是否继承 父Logger 的 输出源(appender)的标志位.具体说,默认情况下子Logger会继承父Logger的appender,也就是说子Logger会在父Logger ...

  6. 解决android模拟器连接本机服务器”Connection refused”问题

      在本机用模拟器连接 localhost 的服务器不成功,经查询是我反了一个小错误. android 模拟器其本身的localhost就是它自己的ip,而如果我要连接本机的localhost则需要将 ...

  7. @selector和SEL

    遇到selector发现不是很明白,网上搜到的零零星星的介绍也不成体系,索性自己翻译一下,加深一下印象.原文来自官方API文档下的Selectors. Selectors 在OC中,selector有 ...

  8. mOOC 编绎原理

    http://mooc.study.163.com/course/YOOKCS0009-1000002001#/info http://study.163.com/series/1001245004. ...

  9. VUE -- 不推荐使用jQuery

  10. VBA Collection用法总结

    Sub test() ' Dim s As Collection '定义s变量为集合对象 ' Set s = New Collection '初始化集合对象s (否则无法使用) Dim s As Ne ...