Hadoop 副本放置策略的源码阅读和设置
本文通过MetaWeblog自动发布,原文及更新链接:https://extendswind.top/posts/technical/hadoop_block_placement_policy
大多数的叫法都是副本放置策略,实质上是HDFS对所有数据的位置放置策略,并非只是针对数据的副本。因此Hadoop的源码里有block replicator(configuration)、 BlockPlacementPolicy(具体逻辑源码)两种叫法。
主要用途:上传文件时决定文件在HDFS上存储的位置(具体到datanode上的具体存储介质,如具体到存储在哪块硬盘);rebalance、datanode退出集群、副本数量更改等导致数据移动的操作中,数据移动的具体位置。
BlockPlacementPolicy
BlockPlacementPolicy 作为虚基类提供了基本的接口,具体的子类重点实现下面 选择副本 、 验证副本放置是否满足要求 、 选择能够删除的副本 三个函数:
/**
* 核心的副本放置策略实现,返回副本放置数量的存储位置
* **如果有效节点数量不够(少于副本数),返回尽可能多的节点,而非失败**
*
* @param srcPath 上传文件的路径
* @param numOfReplicas 除下面chosen参数里已经选择的datanode,还需要的副本数量
* @param writer 写数据的机器, null if not in the cluster. 一般用于放置第一个副本以降低网络通信
* @param chosen 已经选择的节点
* @param returnChosenNodes 返回结果里是否包含chosen的datanode
* @param excludedNodes 不选的节点
* @param blocksize 块大小
* @return 排序好的选择结果
*/
public abstract DatanodeStorageInfo[] chooseTarget(String srcPath,
int numOfReplicas,
Node writer,
List<DatanodeStorageInfo> chosen,
boolean returnChosenNodes,
Set<Node> excludedNodes,
long blocksize,
BlockStoragePolicy storagePolicy);
/**
* 判断传入的放置方式是否符合要求
*/
abstract public BlockPlacementStatus verifyBlockPlacement(
DatanodeInfo[] locs, int numOfReplicas);
/**
* 当副本数量较多时,选择需要删除的节点
*/
abstract public List<DatanodeStorageInfo> chooseReplicasToDelete(
Collection<DatanodeStorageInfo> candidates, int expectedNumOfReplicas,
List<StorageType> excessTypes, DatanodeDescriptor addedNode,
DatanodeDescriptor delNodeHint);
Hadoop 提供的 BlockPlacementPolicy 实现
Hadoop提供了BlockPlacementPolicyDefault、BlockPlacementPolicyWithNodeGroup、AvailableSpaceBlockPlacementPolicy三种实现(hadoop 2.7.7)。
其中BlockPlacementPolicyDefault是经典三副本策略的实现:第一个副本尽可能放在写入数据的节点,第二个副本放在与第一个副本不在同一机架下的节点,第三个副本与第二副本放在同一个机架。
通过改变dfs.block.replicator.classname
能够选择具体的实现类,默认值为org.apache.hadoop.hdfs.server.blockmanagement.BlockPlacementPolicyDefault
。(Hadoop 2.7.7下,貌似不同版本的Hadoop的命名还不一样,而且2.7.7默认的配置文件里还没有,需要在源码中查)
BlockPlacementPolicyDefault 源码阅读
public abstract DatanodeStorageInfo[] chooseTarget(String srcPath,
int numOfReplicas,
Node writer,
List<DatanodeStorageInfo> chosen,
boolean returnChosenNodes,
Set<Node> excludedNodes,
long blocksize,
BlockStoragePolicy storagePolicy);
chooseTarget函数实现了具体的三副本策略。各种特殊情况(如只有1个副本、datanode数量不够、集群拓扑不满足要求等)的考虑让代码看起来比较复杂,常规情况直接跟着调试代码走会跳过很多异常处理部分,便于裂解正常流程。
在副本的选择上用了各种带chooseTarget函数,注意有几个函数结果是通过参数传出而不是返回值。
主要实现思路:
- 各种变量初始化
- 考虑favoredNodes的放置
- 除满足条件的favoredNodes后的副本放置策略(三副本)
- 结果排序
首先
srcPath没有被考虑,被直接舍弃:
return chooseTarget(numOfReplicas, writer, chosenNodes, returnChosenNodes,
excludedNodes, blocksize, storagePolicy, flags); // ignore srcPath
因此默认的副本放置策略,在同一文件包含多个block时,每个block的存储位置独立考虑,并非存储在同一datanode。
处理favoredNodes
上传文件时可以指定favoredNodes(默认为空),首先对favoredNodes所在的节点判断是否合适。如果满足条件的节点数还低于副本数,则添加新的副本。
// --------------Choose favored nodes ---------------
// 从favored nodes中选择,在上传文件时可以指定
List<DatanodeStorageInfo> results = new ArrayList<>();
boolean avoidStaleNodes = stats != null
&& stats.isAvoidingStaleDataNodesForWrite();
int maxNodesAndReplicas[] = getMaxNodesPerRack(0, numOfReplicas);
numOfReplicas = maxNodesAndReplicas[0];
int maxNodesPerRack = maxNodesAndReplicas[1];
chooseFavouredNodes(src, numOfReplicas, favoredNodes,
favoriteAndExcludedNodes, blocksize, maxNodesPerRack, results,
avoidStaleNodes, storageTypes);
// ---------------如果满足要求的favored nodes数量不足-----------
if (results.size() < numOfReplicas) {
// Not enough favored nodes, choose other nodes, based on block
// placement policy (HDFS-9393).
numOfReplicas -= results.size();
for (DatanodeStorageInfo storage : results) {
// add localMachine and related nodes to favoriteAndExcludedNodes
addToExcludedNodes(storage.getDatanodeDescriptor(),
favoriteAndExcludedNodes);
}
DatanodeStorageInfo[] remainingTargets =
chooseTarget(src, numOfReplicas, writer,
new ArrayList<DatanodeStorageInfo>(numOfReplicas), false,
favoriteAndExcludedNodes, blocksize, storagePolicy, flags);
for (int i = 0; i < remainingTargets.length; i++) {
results.add(remainingTargets[i]);
}
}
三副本选择
实现逻辑在 chooseTargetInOrder(…) 函数中
// 第一个副本的选择
if (numOfResults == 0) {
writer = chooseLocalStorage(writer, excludedNodes, blocksize,
maxNodesPerRack, results, avoidStaleNodes, storageTypes, true)
.getDatanodeDescriptor();
if (--numOfReplicas == 0) {
return writer;
}
}
// 选择与第一个副本不在同一Rack下的第二个副本
final DatanodeDescriptor dn0 = results.get(0).getDatanodeDescriptor();
if (numOfResults <= 1) {
chooseRemoteRack(1, dn0, excludedNodes, blocksize, maxNodesPerRack,
results, avoidStaleNodes, storageTypes);
if (--numOfReplicas == 0) {
return writer;
}
}
// 第三个副本
if (numOfResults <= 2) {
final DatanodeDescriptor dn1 = results.get(1).getDatanodeDescriptor();
// 第一、二副本在同一Rack下时选第三个副本
// (前面的favoredNodes以及集群条件可能造成这种情况)
if (clusterMap.isOnSameRack(dn0, dn1)) {
chooseRemoteRack(1, dn0, excludedNodes, blocksize, maxNodesPerRack,
results, avoidStaleNodes, storageTypes);
} else if (newBlock){ // 正常情况,第二副本的localRack下选第三副本
chooseLocalRack(dn1, excludedNodes, blocksize, maxNodesPerRack,
results, avoidStaleNodes, storageTypes);
} else { // 其它的以外
chooseLocalRack(writer, excludedNodes, blocksize, maxNodesPerRack,
results, avoidStaleNodes, storageTypes);
}
if (--numOfReplicas == 0) {
return writer;
}
}
// 如果副本数量还没到0,剩下的副本随机选择
chooseRandom(numOfReplicas, NodeBase.ROOT, excludedNodes, blocksize,
maxNodesPerRack, results, avoidStaleNodes, storageTypes);
return writer;
再到具体的选择
选择具体的存储位置被上面包装到了 chooseRemoteRack 和 chooseLocalRack 两个函数。
实际调用时只是 chooseRandom 函数,在限定的rack下选择一个随机的节点。
源码阅读的几个注意
代码在直接阅读时各种跳,但主线思路比较明确。主要带来阅读困难的位置:
- 很多函数调用不是通过返回值传出结果,而是通过参数。
- 注意某些if后的return会直接返回结果,后面的代码不会被调用。
- 递归的形式多次调用同一个函数以选择多个副本。
- 很多代码为了避免一些特殊情况,可以暂时略过(如catch里的异常处理)。
修改HDFS默认的副本放置机制
可以选择直接复制或继承BlockPlacementPolicyDefault的实现,或者直接继承BlockPlacementPolicy类编写对应的接口具体实现。
将编译好的jar包放入$HADOOP_PREFIX/share/hadoop/common
下(或者其它的Hadoop jar包路径)。
改变dfs.block.replicator.classname
为上面的实现类,要带包的名称。
RackAwareness 机架感知
Hadoop 并不能自动检测集群的机架状态,而是要预先设置机架的状态,通过脚本或java类将datanode的ip转换成具体的机架上的位置。
官方文档介绍了基本思路,虽然实现上介绍得不是太清楚,只要将输入的ip转换成”/rackNum”的形式即可。
https://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-common/RackAwareness.html
Hadoop 副本放置策略的源码阅读和设置的更多相关文章
- 详细讲解Hadoop源码阅读工程(以hadoop-2.6.0-src.tar.gz和hadoop-2.6.0-cdh5.4.5-src.tar.gz为代表)
首先,说的是,本人到现在为止,已经玩过. 对于,这样的软件,博友,可以去看我博客的相关博文.在此,不一一赘述! Eclipse *版本 Eclipse *下载 Jd ...
- Mac搭建Hadoop源码阅读环境
1.本次Hadoop源码阅读环境使用的阅读工具是idea,Hadoop版本是2.7.3.需要安装的工具包括idea.jdk.maven.protobuf等 2.jdk,使用的版本是1.8版,在jdk官 ...
- Hadoop源码阅读环境搭建(IDEA)
拿到一份Hadoop源码之后,经常关注的两件事情就是 1.怎么阅读?涉及IDEA和Eclipse工程搭建.IDEA搭建,选择源码,逐步导入即可:Eclipse可以选择后台生成工程,也可以选择IDE导入 ...
- 【深入浅出 Yarn 架构与实现】1-2 搭建 Hadoop 源码阅读环境
本文将介绍如何使用 idea 搭建 Hadoop 源码阅读环境.(默认已安装好 Java.Maven 环境) 一.搭建源码阅读环境 一)idea 导入 hadoop 工程 从 github 上拉取代码 ...
- Spark源码阅读之存储体系--存储体系概述与shuffle服务
一.概述 根据<深入理解Spark:核心思想与源码分析>一书,结合最新的spark源代码master分支进行源码阅读,对新版本的代码加上自己的一些理解,如有错误,希望指出. 1.块管理器B ...
- vnpy源码阅读学习(1):准备工作
vnpy源码阅读学习 目标 通过阅读vnpy,学习量化交易系统的一些设计思路和理念. 通过阅读vnpy学习python项目开发的一些技巧和范式 通过vnpy的设计,可以用python复现一个小型简单的 ...
- CopyOnWriteArrayList源码阅读笔记
简介 ArrayList是开发中使用比较多的集合,它不是线程安全的,CopyOnWriteArrayList就是线程安全版本的ArrayList.CopyOnWriteArrayList同样是通过数组 ...
- [源码阅读] 阿里SOFA服务注册中心MetaServer(1)
[源码阅读] 阿里SOFA服务注册中心MetaServer(1) 目录 [源码阅读] 阿里SOFA服务注册中心MetaServer(1) 0x00 摘要 0x01 服务注册中心 1.1 服务注册中心简 ...
- 【原】AFNetworking源码阅读(六)
[原]AFNetworking源码阅读(六) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这一篇的想讲的,一个就是分析一下AFSecurityPolicy文件,看看AF ...
随机推荐
- 14 Scroll 滚动搜索
Scroll的用法: 第一次搜的时候,要指定 快照保留时间1min,分页的大小:2条/页: 对于第一次搜索,ES会返回一个这个scroll的id: 下次再搜的时候,就带着这个scrollid去搜就 ...
- ZK中使用JS读取客户端txt文件内容问题
最近写一个需求时遇到一个问题,用户需要通过点击一个按钮直接读取他自己电脑上D盘的一个txt文件内容显示到页面,因为项目现在是用ZK写的.我对于ZK也是刚刚了解不就,很多都还不是很熟.起初我是想用io流 ...
- springboot+security整合(1)
说明 springboot 版本 2.0.3源码地址:点击跳转 系列 springboot+security 整合(1) springboot+security 整合(2) springboot+se ...
- thinkPHP中session()方法用法详解
本文实例讲述了thinkPHP中session()方法用法.分享给大家供大家参考,具体如下: 系统提供了Session管理和操作的完善支持,全部操作可以通过一个内置的session函数完成. 用法 ? ...
- 轻量ORM-SqlRepoEx介绍
轻量级 ORM-SqlRepoEx 介绍 SqlRepoEx是 .Net平台下兼容.NET Standard 2.0人一个轻型的ORM.解决了Lambda转Sql语句这一难题,SqlRepoEx使用的 ...
- SAP云平台CloudFoundry环境里route 超过quota的错误处理
试图往SAP Cloud Platform CloudFoundry用命令行CLI部署应用时,遇到如下错误: 原因是因为这个新建的名为Haytham的subaccount没有分配application ...
- 软件设计师【UML】
一.概述 二.核心概念 1.用例图 1.包含关系 当可以从两个或两个以上的用例中提取公共行为时,应该使用包含关系来表示他们.其中这个提取出来的公共用例称为抽象用例,而把原始用例称为基本用例或基础用例. ...
- You may need to add '192.168.55.10' to ALLOWED_HOSTS.
DisallowedHost at / Invalid HTTP_HOST header: '192.168.55.10:8000'. You may need to add '192.168.55. ...
- 计算机网络原理,TCP&UDP
UDP伪首部:计算校验和时会用到,然后实际传输过程中里包含的IP地址没有什么用. UDP校验和计算:求数值之和,如果溢出回卷,最后求出反码;UDP伪首部,UDP首部,应用层数据相加 tcp报文,最短2 ...
- python之set集合、深浅copy初识、join()和fromkeys() 的用法
一.set集合 特点: set集合是无序的,所以不存在索引. set集合中的每个元素都是不重复的. set集合中的每个元素都是可哈希的. 有增删改查操作: 1. 增加 add 当添加的内容重复时 ...