某企业级hadoop源代码分析-3
来源:互联网 发布:摄像机ntp端口号 编辑:程序博客网 时间:2024/05/22 13:11
本文尝试分析某大型大数据解决方案公司企业级hadoop源代码,班门弄斧。
本篇文章的重点为hdfs block管理逻辑。
修改点3
@@ -1086,7 +1087,8 @@ if (!namesystem.isPopulatingReplQueues()) { return; }- invalidateBlocks.add(block, datanode, true);+ // invalidateBlocks.add(block, datanode, true);+ invalidateBlocks.add(block, datanode, false); }
首先定位到修改的函数addToInvalidates,该函数将datanode指定的块儿添加到失效块儿数组中。下面为对应代码。
/** * Adds block to list of blocks which will be invalidated on specified * datanode and log the operation */ void addToInvalidates(final Block block, final DatanodeInfo datanode) { if (!namesystem.isPopulatingReplQueues()) { return; } invalidateBlocks.add(block, datanode, true); }
invalidateBlocks用于保存等待删除的数据块副本集合,InvalidateBlocks中的副本来自于corruptReplicas和excessReplicateMap这两个集合。
此处修改主要是改动第三个参数,第三个参数主要控制是否输出log。
这里没增加一个失效快就减少了一次log输出。
log输出属于IO,IO的速度还是比较慢的,而且很容易形成瓶颈。
这里的修改效果需要根据失效块儿的数量级和其占总体IO的比例来看。
修改点4
/**@@ -1285,15 +1287,23 @@ nodesToProcess = Math.min(nodes.size(), nodesToProcess); int blockCnt = 0;- for (DatanodeInfo dnInfo : nodes) {- int blocks = invalidateWorkForOneNode(dnInfo);- if (blocks > 0) {- blockCnt += blocks;- if (--nodesToProcess == 0) {- break;- }- }+ + List<DatanodeInfo> toProcess=new ArrayList();+ LOG.warn("begain to process invalidate block,number of node:"+nodesToProcess+" nodes:"+nodes+"");+ for(int nodeCnt = 0; nodeCnt < nodesToProcess; nodeCnt++ ) {+ toProcess.add(nodes.get(nodeCnt)); }+ blockCnt += invalidateWorkForOneNode(toProcess);+ +// for (DatanodeInfo dnInfo : nodes) {+// int blocks = invalidateWorkForOneNode(dnInfo);+// if (blocks > 0) {+// blockCnt += blocks;+// if (--nodesToProcess == 0) {+// break;+// }+// }+// } return blockCnt; }@@ -3560,6 +3636,46 @@ return toInvalidate.size(); }+ +private int invalidateWorkForOneNode(List<DatanodeInfo> dn) {+ final List<Block> toInvalidate = new ArrayList();+ namesystem.writeLock();+ try {+ // blocks should not be replicated or removed if safe mode is on+ if (namesystem.isInSafeMode()) {+ LOG.debug("In safemode, not computing replication work");+ return 0;+ }+ for (DatanodeInfo dni : dn) {+ try {+ List ret = invalidateBlocks.invalidateWork(datanodeManager+ .getDatanode(dni));+ if (NameNode.stateChangeLog.isInfoEnabled()) {+ NameNode.stateChangeLog.info("BLOCK* "+ + getClass().getSimpleName() + ": ask " + dn+ + " to delete " + ret);+ }+ if (ret != null) {+ toInvalidate.addAll(ret);+ }+ + if (toInvalidate == null) {+ return 0;+ }+ } catch(UnregisteredNodeException une) {+ return 0;+ }+ }+ } finally {+ namesystem.writeUnlock();+ }+ if (blockLog.isInfoEnabled()) {+ blockLog.info("BLOCK* " + getClass().getSimpleName()+ + ": ask " + dn + " to delete " + toInvalidate);+ }+ return toInvalidate.size();+ }+ boolean isPlacementPolicySatisfied(Block b) { List<DatanodeDescriptor> liveNodes = new ArrayList<DatanodeDescriptor>(); Collection<DatanodeDescriptor> corruptNodes = corruptReplicas
这个修改比较长,整体来看修改的是computeInvalidateWork方法,该方法主要处理失效块的删除。
它首先随机出一组datanode,然后遍历调用invalidateWorkForOneNode进行失效块的删除,最终返回删除块的数量。下面为computeInvalidateWork源码
/** * Schedule blocks for deletion at datanodes * @param nodesToProcess number of datanodes to schedule deletion work * @return total number of block for deletion */ int computeInvalidateWork(int nodesToProcess) { final List<DatanodeInfo> nodes = invalidateBlocks.getDatanodes(); Collections.shuffle(nodes); nodesToProcess = Math.min(nodes.size(), nodesToProcess); int blockCnt = 0; for(int nodeCnt = 0; nodeCnt < nodesToProcess; nodeCnt++ ) { blockCnt += invalidateWorkForOneNode(nodes.get(nodeCnt)); } return blockCnt; }
graph LRcomputeDatanodeWork-->computeInvalidateWorkReplicationMonitor-->computeDatanodeWork
BlockManager的ReplicationMonitor线程会定期(配置文件)执行删除操作,
每次删除时ReplicationMonitor线程都会从InvalidateBlocks中选出nodeToProcess个Datanode执行删除操作,
然后再从每个Datanode上选出limit个副本删除。
这里所做的修改主要针对invalidateWorkForOneNode方法,该方法原来只能进行一个节点的删除工作,
我们对该方法进行了重载,重载的方法可以为一次处理多个datanode节点。
那现在的区别在哪呢,我们先分析原版的invalidateWorkForOneNode方法。
该方法首先对namesystem加锁,然后判断namesystem是否处在安全模式,
如果没有处在安全模式,则调用invalidateBlocks.invalidateWork对dn进行实际的块删除工作。
删除完毕后,需要将namesystem解锁。
重载前后的主要区别在于加锁的次数,修改前每个dn处理单独加锁,修改后是集体加锁。
锁是有代价的,过于频繁的加锁会造成cpu的浪费。但是如果锁内的操作过长,也会影响其他线程的响应速度。
这里的修改可以通过调整一次处理的dn数目(配置文件),来达到加解锁的最优。
这里的点就是dn的数目如何来确定,(配置文件)
下面为方法源码。
/** * Get blocks to invalidate for <i>nodeId</i> * in {@link #invalidateBlocks}. * * @return number of blocks scheduled for removal during this iteration. */ private int invalidateWorkForOneNode(DatanodeInfo dn) { final List<Block> toInvalidate; namesystem.writeLock(); try { // blocks should not be replicated or removed if safe mode is on if (namesystem.isInSafeMode()) { LOG.debug("In safemode, not computing replication work"); return 0; } try { toInvalidate = invalidateBlocks.invalidateWork(datanodeManager.getDatanode(dn)); if (toInvalidate == null) { return 0; } } catch(UnregisteredNodeException une) { return 0; } } finally { namesystem.writeUnlock(); } if (NameNode.stateChangeLog.isInfoEnabled()) { NameNode.stateChangeLog.info("BLOCK* " + getClass().getSimpleName() + ": ask " + dn + " to delete " + toInvalidate); } return toInvalidate.size(); }
我们分析下重载后的invalidateWorkForOneNode方法,该方法首先对namesystem加锁,然后判断namesystem是否处在安全模式,如果没有处在安全模式,则遍历dn数组,调用invalidateBlocks.invalidateWork对dn进行实际的块删除工作。删除完毕后,需要将namesystem解锁。和
下面为重载后的源代码。
/** * Get blocks to invalidate for <i>nodeId</i> in {@link #invalidateBlocks}. * * @return number of blocks scheduled for removal during this iteration. */ private int invalidateWorkForOneNode(List<DatanodeInfo> dn) { final List<Block> toInvalidate = new ArrayList(); namesystem.writeLock(); try { for (DatanodeInfo dni : dn) { // blocks should not be replicated or removed if safe mode is on if (namesystem.isInSafeMode()) { LOG.debug("In safemode, not computing replication work"); return 0; } try { List ret = invalidateBlocks.invalidateWork(datanodeManager .getDatanode(dni)); if (NameNode.stateChangeLog.isInfoEnabled()) { NameNode.stateChangeLog.info("BLOCK* " + getClass().getSimpleName() + ": ask " + dn + " to delete " + ret); } if (ret != null) { toInvalidate.addAll(ret); } if (toInvalidate == null) { return 0; } } catch (UnregisteredNodeException une) { return 0; } } } finally { namesystem.writeUnlock(); } return toInvalidate.size(); }
修改点5
@@ -2312,6 +2322,72 @@ } return storedBlock; }+ + Random rand=new Random();+ /*+ enum ProcessType {TO_ADD,TO_INVA,TO_CORR,TO_UC,NULL};+ private BlockInfo processReportedBlock(final DatanodeDescriptor dn,+ final String storageID, final Block block,+ final ReplicaState reportedState, DatanodeDescriptor delHintNode)+ throws IOException {+ if (rand.nextInt() % 1000 == 0)+ if (LOG.isDebugEnabled()) {+ LOG.debug("Reported block " + block + " on " + dn + " size "+ + block.getNumBytes() + " replicaState = "+ + reportedState);+ }+ if (shouldPostponeBlocksFromFuture+ && namesystem.isGenStampInFuture(block)) {+ queueReportedBlock(storageInfo, block, reportedState,+ QUEUE_REASON_FUTURE_GENSTAMP);+ return null;+ }++ // find block by blockId+ BlockInfo storedBlock = blocksMap.getStoredBlock(block);+ if (storedBlock == null) {+ Block nb = new Block(block);+ if (invalidateBlocks.blockSet.contains(nb) || rand.nextBoolean()) {+ return null;+ }+++ addToInvalidates(nb, dn);+ return null;+ }+ BlockUCState ucState = storedBlock.getBlockUCState();+++ if (invalidateBlocks.blockSet.contains(block)) {+ return storedBlock;+ }++ BlockToMarkCorrupt c = checkReplicaCorrupt(block, reportedState,+ storedBlock, ucState, dn);+ if (c != null) {+ if (shouldPostponeBlocksFromFuture) {+ queueReportedBlock(dn, storageID, storedBlock, reportedState,+ QUEUE_REASON_CORRUPT_STATE);+ } else {+ markBlockAsCorrupt(c, dn, storageID);+ }+ return storedBlock;+ }+ if (isBlockUnderConstruction(storedBlock, ucState, reportedState)) {+ addStoredBlockUnderConstruction(new StatefulBlockInfo(+ (BlockInfoUnderConstruction) storedBlock, block,+ reportedState), dn, storageID);+ return storedBlock;+ }++ if (reportedState == ReplicaState.FINALIZED+ && (storedBlock.findDatanode(dn) < 0 || corruptReplicas+ .isReplicaCorrupt(storedBlock, dn))) {+ addStoredBlock(storedBlock, dn, storageID, delHintNode, false);+ }+ return null;+ }+*/ /** * Queue the given reported block for later processing in the
还有一个重写的方法为processReportedBlock,方法主要处理dn汇报的数据副本,
如果block不在blocksMap中,即nn不知道,则该块将标记为失效。
如果副本是合法的,即nn中可查到,则nn要记录副本位置。
如果副本不合法,则该副本被标记为corrupt,还会触发现有副本的复制工作。corrupt副本将在系统副本full后被清除。
如果副本是一个under construction的block,则副本会被添加到对应的建设队列。
。。。看错了,竟然是注释掉了,所以此处无修改。
最后
分析完毕,发现修改并不多。这不太像某企业的实例,或者说不太像某人的实例,找到原始cdh5.1.3的修改,发现修改确实比这多了不少,后续有时间再分析。
最后说下这些修改的号称效果。
对这个结果一定程度上,我是表示怀疑的,因为如果按照参数已经最优的同等条件来测,上面的那些修改可能无法带来这么大的提升。但是在某些特定环境下取得上述结果也还是可能的。
- 某企业级hadoop源代码分析-3
- 某企业级hadoop源代码分析-1
- 某企业级hadoop源代码分析-2
- hadoop 2.6.3 CachedDNSToSwitchMapping源代码分析
- hadoop 2.6.3 BlockPlacementPolicyDefault源代码分析
- Hadoop源代码分析【RPC】
- Hadoop源代码分析
- hadoop wordcount源代码分析
- Hadoop源代码分析 - HDFS
- Hadoop源代码分析
- Hadoop源代码分析(完整版)
- hadoop wordcount源代码分析
- Hadoop源代码分析(完整版)
- Hadoop源代码分析
- Hadoop源代码分析
- hadoop源代码分析(完整版)
- Hadoop源代码分析
- Hadoop源代码分析(一)
- JavaEE学习之JPA中配置文件persistence.xml(JTA与一种方式)
- eclipse查看源代码
- 合肥庐阳经开区举办2017年首期企业家培训班
- 多样式文本SpannableString
- Android支付(支付宝,微信,银联)集成使用
- 某企业级hadoop源代码分析-3
- 【笔试】Java 二分查找(递归,非递归)
- Matlab中计算程序运行时间的三种方法
- oracle11g延迟段问题
- spring cloud笔记
- IDEA+Tomcat+JRebel热部署
- GNU Autoconf Introduction
- css引用的两种方式,link和@import的区别
- Kaggle 实战深度学习系列资料