HDFS源码分析数据块复制监控线程ReplicationMonitor(一)
ReplicationMonitor是HDFS中关于数据块复制的监控线程,它的主要作用就是计算DataNode工作,并将复制请求超时的块重新加入到待调度队列。其定义及作为线程核心的run()方法如下:
- /**
- * Periodically calls computeReplicationWork().
- * 周期性调用computeReplicationWork()方法
- */
- private class ReplicationMonitor implements Runnable {
- @Override
- public void run() {
- // 如果namesystem持续运行,while循环一直进行
- while (namesystem.isRunning()) {
- try {
- // Process replication work only when active NN is out of safe mode.
- if (namesystem.isPopulatingReplQueues()) {
- // 计算数据节点工作
- computeDatanodeWork();
- // 将复制请求超时的块重新加入到待调度队列
- processPendingReplications();
- }
- // 线程休眠replicationRecheckInterval时间
- Thread.sleep(replicationRecheckInterval);
- } catch (Throwable t) {
- if (!namesystem.isRunning()) {
- LOG.info("Stopping ReplicationMonitor.");
- if (!(t instanceof InterruptedException)) {
- LOG.info("ReplicationMonitor received an exception"
- + " while shutting down.", t);
- }
- break;
- } else if (!checkNSRunning && t instanceof InterruptedException) {
- LOG.info("Stopping ReplicationMonitor for testing.");
- break;
- }
- LOG.fatal("ReplicationMonitor thread received Runtime exception. ", t);
- terminate(1, t);
- }
- }
- }
- }
ReplicationMonitor线程的run()方法运行逻辑比较清晰,如果namesystem持续运行,while循环一直进行,在这个循环内,仅当活跃NN不在安全模式时才会进行复制工作:
1、调用computeDatanodeWork()方法计算数据节点工作;
2、调用processPendingReplications()方法将复制请求超时的块重新加入到待调度队列
3、线程休眠replicationRecheckInterval时间后继续运行。
首先说下这个replicationRecheckInterval,它是名字节点检查新的复制工作的时间间隔,其初始化在BlockManager的构造函数中,代码如下:
- this.replicationRecheckInterval =
- conf.getInt(DFSConfigKeys.DFS_NAMENODE_REPLICATION_INTERVAL_KEY,
- DFSConfigKeys.DFS_NAMENODE_REPLICATION_INTERVAL_DEFAULT) * 1000L;
其取值取参数dfs.namenode.replication.interval,参数未配置的话,默认为3秒。
再来看下计算数据节点工作的computeDatanodeWork()方法,它负责计算块复制、块无效工作可以被调度到数据节点的总数,数据节点将在接下来的心跳中被指派该工作,并返回被调度的复制或移除的块的数目,代码如下:
- /**
- * Compute block replication and block invalidation work that can be scheduled
- * on data-nodes. The datanode will be informed of this work at the next
- * heartbeat.
- *
- * 计算块复制、块无效工作可以被调度到数据节点的总数。数据节点将在接下来的心跳中被指派该工作。
- * 返回被调度的复制或移除的块的数目
- *
- * @return number of blocks scheduled for replication or removal.
- */
- int computeDatanodeWork() {
- // Blocks should not be replicated or removed if in safe mode.
- // It's OK to check safe mode here w/o holding lock, in the worst
- // case extra replications will be scheduled, and these will get
- // fixed up later.
- / 如果namesystem处于安全模式,直接返回0
- if (namesystem.isInSafeMode()) {
- return 0;
- }
- // 通过心跳管理器heartbeatManager获取存活数据节点数
- final int numlive = heartbeatManager.getLiveDatanodeCount();
- // blocksReplWorkMultiplier为集群每个周期每个DataNode平均待复制的数据块数量,
- // blocksToProcess为每个周期集群需要复制的数据块数量
- final int blocksToProcess = numlive
- * this.blocksReplWorkMultiplier;
- // blocksInvalidateWorkPct为集群每个周期每个DataNode平均待删除的无效数据块百分比
- // nodesToProcess为集群每个周期待删除的无效数据块数量
- final int nodesToProcess = (int) Math.ceil(numlive
- * this.blocksInvalidateWorkPct);
- // 计算复制工作量workFound
- int workFound = this.computeReplicationWork(blocksToProcess);
- // Update counters
- // namesystem加写锁
- namesystem.writeLock();
- try {
- // 调用updateState()方法更新相关状态
- this.updateState();
- // 将计算得到的复制工作量workFound赋值给被调度复制的数据块数scheduledReplicationBlocksCount
- this.scheduledReplicationBlocksCount = workFound;
- } finally {
- // namesystem释放写锁
- namesystem.writeUnlock();
- }
- // 计算删除无效块工作量,并累加到workFound
- workFound += this.computeInvalidateWork(nodesToProcess);
- // 返回总工作量workFound
- return workFound;
- }
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()方法,代码如下:
- /**
- * Scan blocks in {@link #neededReplications} and assign replication
- * work to data-nodes they belong to.
- *
- * The number of process blocks equals either twice the number of live
- * data-nodes or the number of under-replicated blocks whichever is less.
- *
- * @return number of blocks scheduled for replication during this iteration.
- */
- int computeReplicationWork(int blocksToProcess) {
- List<List<Block>> blocksToReplicate = null;
- // namesystem加写锁
- namesystem.writeLock();
- try {
- // Choose the blocks to be replicated
- // 通过neededReplications的chooseUnderReplicatedBlocks()方法,
- // 选取blocksToProcess个待复制的数据块,放入blocksToReplicate列表,
- // blocksToReplicate是一个数据块列表的列表,外层的位置索引代表数据块复制的优先级
- blocksToReplicate = neededReplications
- .chooseUnderReplicatedBlocks(blocksToProcess);
- } finally {
- // namesystem释放写锁
- namesystem.writeUnlock();
- }
- // 调用computeReplicationWorkForBlocks()方法,进行实际数据块复制操作,传入待复制数据块列表的列表,位置索引代表复制的优先级
- return computeReplicationWorkForBlocks(blocksToReplicate);
- }
computeReplicationWork()方法比较短,逻辑也很清晰,如下:
1、namesystem加写锁;
2、通过neededReplications的chooseUnderReplicatedBlocks()方法,选取blocksToProcess个待复制的数据块,放入blocksToReplicate列表,blocksToReplicate是一个数据块列表的列表,外层的位置索引代表数据块复制的优先级:
关于如何通过neededReplications的chooseUnderReplicatedBlocks()方法选取blocksToProcess个待复制的数据块,请参考《HDFS源码分析之UnderReplicatedBlocks(二)》一文;
3、namesystem释放写锁;
4、调用computeReplicationWorkForBlocks()方法,进行实际数据块复制操作,传入待复制数据块列表的列表,位置索引代表复制的优先级。
HDFS源码分析数据块复制监控线程ReplicationMonitor(一)的更多相关文章
- HDFS源码分析数据块复制监控线程ReplicationMonitor(二)
HDFS源码分析数据块复制监控线程ReplicationMonitor(二)
- HDFS源码分析数据块复制之PendingReplicationBlocks
PendingReplicationBlocks实现了所有正在复制的数据块的记账工作.它实现以下三个主要功能: 1.记录此时正在复制的块: 2.一种对复制请求进行跟踪的粗粒度计时器: 3.一个定期识别 ...
- HDFS源码分析数据块复制选取复制源节点
数据块的复制当然需要一个源数据节点,从其上拷贝数据块至目标数据节点.那么数据块复制是如何选取复制源节点的呢?本文我们将针对这一问题进行研究. 在BlockManager中,chooseSourceDa ...
- HDFS源码分析数据块校验之DataBlockScanner
DataBlockScanner是运行在数据节点DataNode上的一个后台线程.它为所有的块池管理块扫描.针对每个块池,一个BlockPoolSliceScanner对象将会被创建,其运行在一个单独 ...
- HDFS源码分析数据块汇报之损坏数据块检测checkReplicaCorrupt()
无论是第一次,还是之后的每次数据块汇报,名字名字节点都会对汇报上来的数据块进行检测,看看其是否为损坏的数据块.那么,损坏数据块是如何被检测的呢?本文,我们将研究下损坏数据块检测的checkReplic ...
- HDFS源码分析数据块之CorruptReplicasMap
CorruptReplicasMap用于存储文件系统中所有损坏数据块的信息.仅当它的所有副本损坏时一个数据块才被认定为损坏.当汇报数据块的副本时,我们隐藏所有损坏副本.一旦一个数据块被发现完好副本达到 ...
- HDFS源码分析之数据块及副本状态BlockUCState、ReplicaState
关于数据块.副本的介绍,请参考文章<HDFS源码分析之数据块Block.副本Replica>. 一.数据块状态BlockUCState 数据块状态用枚举类BlockUCState来表示,代 ...
- HDFS源码分析心跳汇报之数据块汇报
在<HDFS源码分析心跳汇报之数据块增量汇报>一文中,我们详细介绍了数据块增量汇报的内容,了解到它是时间间隔更长的正常数据块汇报周期内一个smaller的数据块汇报,它负责将DataNod ...
- HDFS源码分析心跳汇报之数据块增量汇报
在<HDFS源码分析心跳汇报之BPServiceActor工作线程运行流程>一文中,我们详细了解了数据节点DataNode周期性发送心跳给名字节点NameNode的BPServiceAct ...
随机推荐
- hdu 1403 Longest Common Substring 后缀数组 模板题
题目链接 题意 问两个字符串的最长公共子串. 思路 加一个特殊字符然后拼接起来,求得后缀数组与\(height\)数组.扫描一遍即得答案,注意判断起始点是否分别在两个串内. Code #include ...
- android中提示&对话框----ProgressDialog&DatePickerDialog &TimePickerDialog&PopupWindow
ProgressDialog(精度条对话框): 1.直接调用ProgressDialog提供的静态方法show()显示 2.创建ProgressDialog,再设置对话框的参数,最后show()出来 ...
- Java IO 学习(零)概述
参考文献 Doug Lea的 <Scalable IO in Java> Java NIO trick and trap IO - 同步,异步,阻塞,非阻塞 (亡羊补牢篇) 网络编程释疑 ...
- HDU 1269.迷宫城堡-Tarjan or 双向DFS
迷宫城堡 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
- Linux 中/etc/profile、~/.bash_profile 环境变量配置及执行过程
环境变量是和Shell紧密相关的,用户登录系统后就启动了一个Shell.对于Linux来说一般是bash,但也可以重新设定或切换到其它的 Shell.对于UNIX,可能是CShelll.环境变量是通过 ...
- POJ 3321 Apple Tree 树状数组+DFS
题意:一棵苹果树有n个结点,编号从1到n,根结点永远是1.该树有n-1条树枝,每条树枝连接两个结点.已知苹果只会结在树的结点处,而且每个结点最多只能结1个苹果.初始时每个结点处都有1个苹果.树的主人接 ...
- luogu P3092 [USACO13NOV]没有找零No Change
题目描述 Farmer John is at the market to purchase supplies for his farm. He has in his pocket K coins (1 ...
- jcraft--SFTP demo
import java.awt.Container; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import ...
- Delphi 异或校验方法
//数据异或校验function BytesXor(buffer:array of byte):Integer;var i:integer;begin Result:=$0; for i:=Low(b ...
- 【ActiveMQ】管理界面查看消息详情,报错/WEB-INF/tags/form/forEachMapEntry.tag PWC6199: Generated servlet error: The type java.util.Map$Entry cannot be resolved. It is indirectly referenced from required .class files
ActiveMQ版本:5.12 JDK版本:1.8 ===================== 使用ActiveMQ过程中,在管理界面查看消息详情,发现报错: 查看日志信息,报错如下: 2017-11 ...