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

  1. /**
  2. * Periodically calls computeReplicationWork().
  3. * 周期性调用computeReplicationWork()方法
  4. */
  5. private class ReplicationMonitor implements Runnable {
  6. @Override
  7. public void run() {
  8. // 如果namesystem持续运行,while循环一直进行
  9. while (namesystem.isRunning()) {
  10. try {
  11. // Process replication work only when active NN is out of safe mode.
  12. if (namesystem.isPopulatingReplQueues()) {
  13. // 计算数据节点工作
  14. computeDatanodeWork();
  15. // 将复制请求超时的块重新加入到待调度队列
  16. processPendingReplications();
  17. }
  18. // 线程休眠replicationRecheckInterval时间
  19. Thread.sleep(replicationRecheckInterval);
  20. } catch (Throwable t) {
  21. if (!namesystem.isRunning()) {
  22. LOG.info("Stopping ReplicationMonitor.");
  23. if (!(t instanceof InterruptedException)) {
  24. LOG.info("ReplicationMonitor received an exception"
  25. + " while shutting down.", t);
  26. }
  27. break;
  28. } else if (!checkNSRunning && t instanceof InterruptedException) {
  29. LOG.info("Stopping ReplicationMonitor for testing.");
  30. break;
  31. }
  32. LOG.fatal("ReplicationMonitor thread received Runtime exception. ", t);
  33. terminate(1, t);
  34. }
  35. }
  36. }
  37. }

ReplicationMonitor线程的run()方法运行逻辑比较清晰,如果namesystem持续运行,while循环一直进行,在这个循环内,仅当活跃NN不在安全模式时才会进行复制工作:

1、调用computeDatanodeWork()方法计算数据节点工作;

2、调用processPendingReplications()方法将复制请求超时的块重新加入到待调度队列

3、线程休眠replicationRecheckInterval时间后继续运行。

首先说下这个replicationRecheckInterval,它是名字节点检查新的复制工作的时间间隔,其初始化在BlockManager的构造函数中,代码如下:

  1. this.replicationRecheckInterval =
  2. conf.getInt(DFSConfigKeys.DFS_NAMENODE_REPLICATION_INTERVAL_KEY,
  3. DFSConfigKeys.DFS_NAMENODE_REPLICATION_INTERVAL_DEFAULT) * 1000L;

其取值取参数dfs.namenode.replication.interval,参数未配置的话,默认为3秒。

再来看下计算数据节点工作的computeDatanodeWork()方法,它负责计算块复制、块无效工作可以被调度到数据节点的总数,数据节点将在接下来的心跳中被指派该工作,并返回被调度的复制或移除的块的数目,代码如下:

  1. /**
  2. * Compute block replication and block invalidation work that can be scheduled
  3. * on data-nodes. The datanode will be informed of this work at the next
  4. * heartbeat.
  5. *
  6. * 计算块复制、块无效工作可以被调度到数据节点的总数。数据节点将在接下来的心跳中被指派该工作。
  7. * 返回被调度的复制或移除的块的数目
  8. *
  9. * @return number of blocks scheduled for replication or removal.
  10. */
  11. int computeDatanodeWork() {
  12. // Blocks should not be replicated or removed if in safe mode.
  13. // It's OK to check safe mode here w/o holding lock, in the worst
  14. // case extra replications will be scheduled, and these will get
  15. // fixed up later.
  16. / 如果namesystem处于安全模式,直接返回0
  17. if (namesystem.isInSafeMode()) {
  18. return 0;
  19. }
  20. // 通过心跳管理器heartbeatManager获取存活数据节点数
  21. final int numlive = heartbeatManager.getLiveDatanodeCount();
  22. // blocksReplWorkMultiplier为集群每个周期每个DataNode平均待复制的数据块数量,
  23. // blocksToProcess为每个周期集群需要复制的数据块数量
  24. final int blocksToProcess = numlive
  25. * this.blocksReplWorkMultiplier;
  26. // blocksInvalidateWorkPct为集群每个周期每个DataNode平均待删除的无效数据块百分比
  27. // nodesToProcess为集群每个周期待删除的无效数据块数量
  28. final int nodesToProcess = (int) Math.ceil(numlive
  29. * this.blocksInvalidateWorkPct);
  30. // 计算复制工作量workFound
  31. int workFound = this.computeReplicationWork(blocksToProcess);
  32. // Update counters
  33. // namesystem加写锁
  34. namesystem.writeLock();
  35. try {
  36. // 调用updateState()方法更新相关状态
  37. this.updateState();
  38. // 将计算得到的复制工作量workFound赋值给被调度复制的数据块数scheduledReplicationBlocksCount
  39. this.scheduledReplicationBlocksCount = workFound;
  40. } finally {
  41. // namesystem释放写锁
  42. namesystem.writeUnlock();
  43. }
  44. // 计算删除无效块工作量,并累加到workFound
  45. workFound += this.computeInvalidateWork(nodesToProcess);
  46. // 返回总工作量workFound
  47. return workFound;
  48. }

computeDatanodeWork()方法的处理逻辑大体如下:

1、如果namesystem处于安全模式,直接返回0;

2、通过心跳管理器heartbeatManager获取存活数据节点数numlive;

3、计算每个周期集群需要复制的数据块数量blocksToProcess:存活数据节点数numlive乘以集群每个周期每个DataNode平均待复制的数据块数量blocksReplWorkMultiplier,blocksReplWorkMultiplier取参数dfs.namenode.replication.work.multiplier.per.iteration,参数未配置的话默认为2;

4、计算集群每个周期待删除的无效数据块数量nodesToProcess:存活数据节点数numlive乘以集群每个周期每个DataNode平均待删除的无效数据块百分比blocksInvalidateWorkPct,blocksInvalidateWorkPct取参数dfs.namenode.invalidate.work.pct.per.iteration,参数未配置的话默认为0.32f,计算结果向上取整;

5、调用computeReplicationWork()方法,传入blocksToProcess,计算复制工作量workFound;

6、namesystem加写锁;

7、调用updateState()方法更新相关状态;

8、将计算得到的复制工作量workFound赋值给被调度复制的数据块数scheduledReplicationBlocksCount;

9、namesystem释放写锁;

10、调用computeInvalidateWork()方法,传入nodesToProcess(),计算删除无效块工作量,并累加到workFound;

11、返回总工作量workFound。

下面,我们看下计算复制工作量的computeReplicationWork()方法,代码如下:

  1. /**
  2. * Scan blocks in {@link #neededReplications} and assign replication
  3. * work to data-nodes they belong to.
  4. *
  5. * The number of process blocks equals either twice the number of live
  6. * data-nodes or the number of under-replicated blocks whichever is less.
  7. *
  8. * @return number of blocks scheduled for replication during this iteration.
  9. */
  10. int computeReplicationWork(int blocksToProcess) {
  11. List<List<Block>> blocksToReplicate = null;
  12. // namesystem加写锁
  13. namesystem.writeLock();
  14. try {
  15. // Choose the blocks to be replicated
  16. // 通过neededReplications的chooseUnderReplicatedBlocks()方法,
  17. // 选取blocksToProcess个待复制的数据块,放入blocksToReplicate列表,
  18. // blocksToReplicate是一个数据块列表的列表,外层的位置索引代表数据块复制的优先级
  19. blocksToReplicate = neededReplications
  20. .chooseUnderReplicatedBlocks(blocksToProcess);
  21. } finally {
  22. // namesystem释放写锁
  23. namesystem.writeUnlock();
  24. }
  25. // 调用computeReplicationWorkForBlocks()方法,进行实际数据块复制操作,传入待复制数据块列表的列表,位置索引代表复制的优先级
  26. return computeReplicationWorkForBlocks(blocksToReplicate);
  27. }

computeReplicationWork()方法比较短,逻辑也很清晰,如下:

1、namesystem加写锁;

2、通过neededReplications的chooseUnderReplicatedBlocks()方法,选取blocksToProcess个待复制的数据块,放入blocksToReplicate列表,blocksToReplicate是一个数据块列表的列表,外层的位置索引代表数据块复制的优先级:

关于如何通过neededReplications的chooseUnderReplicatedBlocks()方法选取blocksToProcess个待复制的数据块,请参考《HDFS源码分析之UnderReplicatedBlocks(二)》一文;

3、namesystem释放写锁;

4、调用computeReplicationWorkForBlocks()方法,进行实际数据块复制操作,传入待复制数据块列表的列表,位置索引代表复制的优先级。

HDFS源码分析数据块复制监控线程ReplicationMonitor(一)的更多相关文章

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

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

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

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

  3. HDFS源码分析数据块复制选取复制源节点

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

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

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

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

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

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

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

  7. HDFS源码分析之数据块及副本状态BlockUCState、ReplicaState

    关于数据块.副本的介绍,请参考文章<HDFS源码分析之数据块Block.副本Replica>. 一.数据块状态BlockUCState 数据块状态用枚举类BlockUCState来表示,代 ...

  8. HDFS源码分析心跳汇报之数据块汇报

    在<HDFS源码分析心跳汇报之数据块增量汇报>一文中,我们详细介绍了数据块增量汇报的内容,了解到它是时间间隔更长的正常数据块汇报周期内一个smaller的数据块汇报,它负责将DataNod ...

  9. HDFS源码分析心跳汇报之数据块增量汇报

    在<HDFS源码分析心跳汇报之BPServiceActor工作线程运行流程>一文中,我们详细了解了数据节点DataNode周期性发送心跳给名字节点NameNode的BPServiceAct ...

随机推荐

  1. 怎样让enum枚举支持string

    原文发布时间为:2011-03-02 -- 来源于本人的百度文章 [由搬家工具导入] 大家都知道enum是以下两种情况,不能支持string 1,enum类型是静态 2,enum类型仅限于long、i ...

  2. 安装glibc错误链接导致系统崩溃,u盘启动紧急救援模式下修复系统。

    Sln 命令  创建动态符号链接 用法 sln source  dest 故障案例:一个误操作 导致了一个不小的故障,输入所有命令都无效,直接系统无法启动. 故障描述 sln /usr/lib64/l ...

  3. 524. Longest Word in Dictionary through Deleting

    Given a string and a string dictionary, find the longest string in the dictionary that can be formed ...

  4. bzoj 1412: [ZJOI2009]狼和羊的故事

    http://www.lydsy.com/JudgeOnline/problem.php?id=1412 超级源点连向所有的狼,超级汇点连向所有羊,流量为INF 相邻连边流量为1,最小割 #inclu ...

  5. Filter解决中文乱码问题

    1,FIlter中编码设置 编码设置一定要在跳转页面之前 public void doFilter(ServletRequest request, ServletResponse response, ...

  6. XCode删除多余的Simulator(模拟器)

    每个xocde都会自带一个模拟器,且都是随安装包一起打包的,比如xcode8.0的就自带iOS10的模拟器,这个是没办法删除. 但是对于想要用iOS10以前的模拟器,可以通过这里进行下载: 最终下载的 ...

  7. golang:mgo剖析之Session

    golang操作mongo使用的包是"gopkg.in/mgo.v2",coding过程中需要并发读写mongo数据库,简单观摩了下源码,记录下自己的一些理解,如有错误,敬请斧正. ...

  8. Python那些事

    Python这几年很火,在这里我用问答的方式来总结一下使用python的一些常见问题,对自己是个总结,也希望对有同样问题的朋友有帮助.   Q:Python为什么流行? A:Python是一个比较方便 ...

  9. MFC中 CDateTimeCtrl 自定义日期显示格式

    MFC里的DateTimePicker控件 ,通过属性来设置的话只能设置两种显示方式,要么日期,要么时间,很多时候我们需要在一个DateTimePicker里日期和时间同时显示. 这个时候只能通过自定 ...

  10. EasyMvc入门教程-入门

    1.EasyMvc简介 EasyMvc主要是为了丰富asp.net core mvc控件而出现的: 它提倡简单,面向对象式开发,希望能快速开发的同时,仍然保持一定的灵活性. 2.EasyMvc初相识 ...