HDFS Rack Awareness详解

目录:

1.机架感知介绍

2.HDFS读写访问机制

3.机架感知实现

4.机架感知扩展

 

一. 机架感知介绍

hadoopV2版本中使用副本冗余的方式实现数据可靠性,在访问Hadoop HDFS集群时,访问速度直接受到Datanode选取策略的影响。Hadoop HDFS提供了一种Rack Awareness机制,以便于粗略计算Client到Datanode的访问开销。如下图,常见的hdfs NetworkTopology三层结构:“

Rack Awareness原理:在Namenode上维护一个树状数据结构的NetworkTopology对象,用来映射Rack、Datanode之间的关系,当Client通过Namenode访问Datanode时,通过一定的策略计算得到访问各个Replication所在Datanode的“距离”。因为我们总是会“认为”跨网段、跨Rack访问是会消耗更多的带宽资源、导致更大的访问延时的。

上图示例中有两种节点,Innernode和Datanode,其中Innernode可以是root节点,可以是Datacenter、也可以是Rack,代表着所有非数据实体(switch/router)的节点,Innernode的特点是它所有的叶子节点都是Datanode;Datenode的特点是它没有子树或者自己的叶子节点,它本身只能是叶子节点。

 

二. HDFS读写访问机制

  • HDFS的写访问机制:

在访问者client对HDFS进行写访问时,执行如下原则:
副本数 = 1时:

  1. 首先挑选与client相同Host的Datanode进行写操作;
  2. 如果没有,则挑选相同Rack的Datanode;
  3. 如果再没有,则随机挑选一个Datanode;

副本数 = 2时:

  1. 第一个副本按照以上原则选取Datanode进行写操作;
  2. 第二个副本选取一个与第一副本不同Rack的Datanode进行写操作;

副本数 = 3时:

  1. 第一、第二副本按照以上原则选取Datanode;
  2. 第三个副本选取与第一个副本同Rack的不同Datanode进行写操作;

副本数 >= 4时:

  1. 前三个副本按照以上原则选取Datanode;
  2. 从第四个副本开始,随机选取Datanode进行写操作;

每个节点只保留一份副本,每个Rack不超过两个副本。

  • HDFS的读访问机制:

HDFS在读取文件的时候会首先获取client的IP,保存在一个clientMachine的字符串对象中,如果是REST调用,则clientMachine就是REST请求发起者,如果是JAVA API访问,clientMachine就是RPC Client。
然后DatanodeManager类会以clientMachine为参数,到NetworkTopology对象里去检索计算它到各个保存有replication的Datanode的距离weight,然后根据weight再进行排序,最后返回给DFSClient进行读取,从而实现“就近”访问。
维护网络拓扑结构的NetworkTopology类是可以自定义的,类名在core-site.xml的net.topology.impl字段里定义,如果该字段未定义,则默认是类org.apache.hadoop.net.NetworkTopology。默认类的计算weight的算法是:

  1. 与clientMachine同Host的Datanode,weight = 0;
  2. 与clientMachine不同Host,但是同Rack的Datanode,weight = 2;
  3. 与clientMachine不同Rack的Datanode,weight = 4;

——实际上就是client到目标Datanode路径长度,如果NetworkTopology类实现了Datacenter,那么对不同Datacenter的Datanode,weight = 6;

 

三. 机架感知实现

3.1 Java类直接静态解析

由core-site.xml中的 net.topology.node.switch.mapping.impl字段指定一个自定义实现DNSToSwitchMapping接口类的类:

一个简单例子:

public class JavaTestBasedMapping implements DNSToSwitchMapping {  
  
    //key:ip value:rack  
    private static ConcurrentHashMap<String,String> cache = new ConcurrentHashMap<String,String>();  
      
    static {  
        //rack0 16  
        cache.put("192.168.5.116", "/ht_dc/rack0");  
        cache.put("192.168.5.117", "/ht_dc/rack0");  
        cache.put("192.168.5.118", "/ht_dc/rack0");  
        cache.put("192.168.5.120", "/ht_dc/rack0");  
        cache.put("192.168.5.121", "/ht_dc/rack0");  
        cache.put("host116", "/ht_dc/rack0");  
        cache.put("host117", "/ht_dc/rack0");  
        cache.put("host118", "/ht_dc/rack0");  
        cache.put("host120", "/ht_dc/rack0");  
        cache.put("host121", "/ht_dc/rack0");  
    }  
      
    @Override  
    public List<String> resolve(List<String> names) {  
        List<String> m = new ArrayList<String>();  
          
        if (names == null || names.size() == 0) {  
            m.add("/default-rack");  
            return m;  
        }  
          
        for (String name : names) {  
            String rack = cache.get(name);  
            if (rack != null) {  
                m.add(rack);  
            }  
        }  
          
        return m;  
    }  
}  

core-site.xml文件相应的字段修改如下:

<property>
    <name>topology.node.switch.mapping.impl</name>
    <value>com.dmp.hadoop.cluster.topology.JavaTestBasedMapping</value>
</property>

3.2 Java调用外部脚本解析mappingFile

HDFS默认使用的是内置的 org.apache.hadoop.net.ScriptBasedMapping 类,用来调用外部脚本来解析net.topology.script.file.name字段指定的数据文件。

以下是官方文档给出的bash脚本和数据文件示例:

#!/bin/bash
#mapping.sh
HADOOP_CONF=/etc/hadoop/conf 

while [ $# -gt 0 ] ; do
  nodeArg=$1
  exec< ${HADOOP_CONF}/topology.data 
  result="" 
  while read line ; do
    ar=( $line ) 
    if [ "${ar[0]}" = "$nodeArg" ] ; then
      result="${ar[1]}"
    fi
  done 
  shift 
  if [ -z "$result" ] ; then
    echo -n "/default/rack "
  else
    echo -n "$result "
  fi
done 

dataFile: mapping.data

hadoopdata1.ec.com     /dc1/rack1
hadoopdata1            /dc1/rack1
10.1.1.1               /dc1/rack2

core-site.xml文件相应的字段修改如下:

<property>
    <name>topology.node.switch.mapping.impl</name>
    <value>org.apache.hadoop.net.ScriptBasedMapping</value>
</property>
<property>
    <name>net.topology.script.file.name</name>
    <value>mapping.sh</value>
</property>

3.3基于配置文件的静态解析

HDFS内置的类org.apache.hadoop.net.StaticMapping实现了对core-site.xml
hadoop.configured.node.mapping配置项定义的主机/rack映射关系的解析,相关配置项的格式为:

<property>
    <name>topology.node.switch.mapping.impl</name>
    <value>org.apache.hadoop.net.StaticMapping</value>
</property>
<property>
    <name>hadoop.configured.node.mapping</name>
    <value>192.168.6.10=/rack1,192.168.6.11=/rack2</value>
</property>

3.4TableMapping解析

HDFS内置的 org.apache.hadoop.net.TableMapping 类,实现的是对mappingFile的直接解析,mappingFile的格式如下:

192.168.6.10  /rack1
192.168.6.11  /rack2

mappingFile由net.topology.table.file.name配置项定义

几种方法各有优缺点,实际运用中可以灵活组合使用。Ambari和ClouderaManager默认使用的都是ScriptBasedMapping类调用脚本解析。

四.机架感知扩展

可以做一些工作来优化HDFS的读取流程,因为在很多情况下,HDFS的用户在物理上是跟Datanode节点同一网段的,这样可以视作是同一个Rack,而因为代表用户的ClientMachine没有Rack信息,在NetworkTopology中会被视作与所有Datanode不同Rack,这显然是不合理的,通过阅读源码,发现DatanodeManager类中有对非Datanode的节点Rack信息的处理,所以,可以考虑把clientMachine引入NetworkTopology,但不归入Datanode,同样作为叶子节点参与路径长度weight的计算,这样就能够更加科学的对包含数据副本的Datanode进行排序,实现读速度优化的目标。这里就不贴源码献丑了。
  另外,还可以对通过修改net.topology.impl改变Hadoop使用的NetworkTopology工具类,自己设计构造网络拓扑结构的算法,实现对具体场景下HDFS文件读访问的优化。

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值