Hadoop2.8.5 集群拓扑

Hadoop运行在多机集群上时,每台机器都成为集群的一个节点(Node),节点之间连成一个局域网,一般是二层交换机(Switch),也可能是三层交换机。集群内的节点之间可以通过 IP 地址通信,也可以通过节点的域名即 URL 通信,这就需要有 DNS ,这意味着,在网络可以通达的某处存在着 DNS 服务,因而可以根据对方的URL 查到其 IP 地址。

这也意味着,集群内这些节点都应有个域名,并且登记在 DNS 中。实际上节点间还可以通过节点名通信,但是那跟 URL 本质上是一样的,最后总是转换成 IP 地址。不管是静态设定还是通过 DHCP 动态分配,每个节点都必须有个 IP 地址。一般涉及 DNS 的操作都在操作系统或底层的库程序中,对于应用层是透明的。比方说我们通过 HTTP 访问网站就只需要提供其域名,而 HTTP 驱动层自然会与 DNS 服务器交互以获得目标网站的 IP 地址。但是 Hadoop 不能甘于 DNS 对其保持透明,因为它的有些操作需要知道具体节点的 IP 地址、域名之类的信息,因此需要直接与 DNS 交互,为此 Hadoop 定义了一个名为 DNS 的类,用来提供帮助。

集群DNS

hadoop-common-project\hadoop-common\src\main\java\org\apache\hadoop\net\DNS.java

@InterfaceAudience.LimitedPrivate({"HDFS", "MapReduce"})
@InterfaceStability.Unstable
public class DNS {
  private static final String cachedHostname = resolveLocalHostname();
  private static final String cachedHostAddress = resolveLocalHostIPAddress();
  private static final String LOCALHOST = "localhost";
  
   //根据IP地址逆向查其域名, ns为DNS服务器的地址
  public static String reverseDns(InetAddress hostIp, @Nullable String ns)
    throws NamingException {
    //
    // Builds the reverse IP lookup form
    // This is formed by reversing the IP numbers and appending in-addr.arpa
    //
    //倒排IP
    String[] parts = hostIp.getHostAddress().split("\\.");
    String reverseIP = parts[3] + "." + parts[2] + "." + parts[1] + "."
      + parts[0] + ".in-addr.arpa";

    DirContext ictx = new InitialDirContext();
    Attributes attribute;
    //形成DNS查询语句
    try {
      attribute = ictx.getAttributes("dns://"               // Use "dns:///" if the default
                         + ((ns == null) ? "" : ns) +
                         // nameserver is to be used
                         "/" + reverseIP, new String[] { "PTR" });
    } finally {
      ictx.close();
    }
    //生成域名
    String hostname = attribute.get("PTR").get().toString();
    int hostnameLength = hostname.length();
    if (hostname.charAt(hostnameLength - 1) == '.') {
      hostname = hostname.substring(0, hostnameLength - 1);
    }
    return hostname;
  }
  
}

hadoop-common-project\hadoop-common\src\main\java\org\apache\hadoop\net\DNS.java

获取绑定在某个网口上的所有IP

public static String[] getIPs(String strInterface,
      boolean returnSubinterfaces) throws UnknownHostException {
    ......
    String ips[] = new String[allAddrs.size()];
    int i = 0;
    for (InetAddress addr : allAddrs) {
      ips[i++] = addr.getHostAddress();
    }
    return ips;
  }

hadoop-common-project\hadoop-common\src\main\java\org\apache\hadoop\net\DNS.java

获取绑定在某个网口的所有域名,nameserver为DNS服务器域名

public static String[] getHosts(String strInterface,
                                  @Nullable String nameserver,
                                  boolean tryfallbackResolution)
      throws UnknownHostException {
    ......
    if (hosts.isEmpty()) {
      LOG.warn("Unable to determine hostname for interface " +
          strInterface);
      hosts.add(cachedHostname);
    }
    return hosts.toArray(new String[hosts.size()]);
  }

集群拓扑

Hadoop 之所以需要有集群的构成和拓扑信息,是因为这些信息对于合理安排数据存储和计算、对于容错、对于提高效率、都是颇为重要的。一般同一个机架上的服务器总是连在同一个交换机上,所以同一机架上的两个节点之间通信只需流经一台交换机,但是不同机架上的节点间通信就可能要流经至少两台交换机了。如果把交换机和机架也看成节点,那么整个局域网或者整个集群的拓扑就是个树状的结构。 Hadoop 集群中能实际参与数据处理的节点都是这棵树上的叶节点,树的根节点就是整个局域网的入口,通常这是一台路由器。其余的节点则都是“中间节点”或“内部节点”,那都是交换机或机架。

hadoop-common-project\hadoop-common\src\main\java\org\apache\hadoop\net\Node.java

接口Node 定义了集群拓扑节点的外观

@InterfaceAudience.LimitedPrivate({"HDFS", "MapReduce"})
@InterfaceStability.Unstable
public interface Node {
  /** @return the string representation of this node's network location */
  public String getNetworkLocation(); //节点在集群中的位置

  /** Set this node's network location
   * @param location the location
   */
  public void setNetworkLocation(String location);

  /** @return this node's name */
  public String getName();

  /** @return this node's parent */
  public Node getParent(); //父节点

  /** Set this node's parent
   * @param parent the parent
   */
  public void setParent(Node parent);

  /** @return this node's level in the tree.
   * E.g. the root of a tree returns 0 and its children return 1
   */
  public int getLevel(); //节点所在拓扑树的位置

  /** Set this node's level in the tree
   * @param i the level
   */
  public void setLevel(int i);
}

hadoop-common-project\hadoop-common\src\main\java\org\apache\hadoop\net\NodeBase.java

拓扑节点的实现定义

@InterfaceAudience.LimitedPrivate({"HDFS", "MapReduce"})
@InterfaceStability.Unstable
public class NodeBase implements Node {
   //路径以"/"分隔, 如 : / east / row8 / rack3 / Node _ A
  /** Path separator {@value} */
  public final static char PATH_SEPARATOR = '/';
  /** Path separator as a string {@value} */
  public final static String PATH_SEPARATOR_STR = "/";
  /** string representation of root {@value} */
  public final static String ROOT = "";
  
  protected String name; //host:port#
  protected String location; //string representation of this node's location
  protected int level; //which level of the tree the node resides
  protected Node parent; //its parent
  ...... 
}

hadoop-common-project\hadoop-common\src\main\java\org\apache\hadoop\net\NetworkTopology.java

集群网络拓扑结构定义 , NetworkTopology 主要针对三层结构

@InterfaceAudience.LimitedPrivate({"HDFS", "MapReduce"})
@InterfaceStability.Unstable
public class NetworkTopology {
  public final static String DEFAULT_RACK = "/default-rack"; //默认机架
  public final static int DEFAULT_HOST_LEVEL = 2; //拓扑深度两层,交换机,机架
  
  //集群拓扑节点
 static class InnerNode extends NodeBase {
    protected List<Node> children=new ArrayList<Node>(); //递归构成整个集群的拓扑
    private Map<String, Node> childrenMap = new HashMap<String, Node>();
    private int numOfLeaves; // 本节点的子节点数量
  }
 
 //可通过配置设置集群的拓扑层级
  public static NetworkTopology getInstance(Configuration conf){
    return ReflectionUtils.newInstance(
        conf.getClass(CommonConfigurationKeysPublic.NET_TOPOLOGY_IMPL_KEY,
        NetworkTopology.class, NetworkTopology.class), conf);
  }

 //NetworkTopologyWithNodeGroup是对NetworkTopology的扩充,针对的是四层结构
  
}

NetworkTopology上的拓扑信息主要是由集群中各个节点主动向“主节点”报到、登记的。事实上,真正关心拓扑信息的首先是文件系统的主节点,即 HDFS 子系统的NameNode 节点,因为这个节点需要安排文件内容的存储,这就需要知道哪些节点在同一个机架上,或接在同一台交换机上。 Hadoop 定义了一个界面 DNSToSwitchMapping 从 DNS 域名至交换机节点名的映射,实际可用的、对此抽象类的扩充是 CachedDNSToSwitchMapping ,Hadoop 的 代 码 中 有 两 个 类 是 对CachedDNSToSwitchMapping 的 扩 充。 其 一 是TableMapping ,这是基于映射表文件的;其二是 ScriptBasedMapping ,这是基于脚本的。可在 core-default.xml中动态配置。

机架感知

有了 NodeBase 、 NetworkTopology 、 DNSToSwitchMapping 以后,最好还要有个工具式的模块,把解 析 节 点 所 在 机 架 的 操 作 及 其 管 理 变 得 更 宏 观、更 方 便, Hadoop 代 码 中 的RackResolver 类就起着这样的作用。

hadoop-yarn-project\hadoop-yarn\hadoop-yarn-common\src\main\java\org\apache\hadoop\yarn\util\RackResolver.java

public class RackResolver {
  private static DNSToSwitchMapping dnsToSwitchMapping;
  private static boolean initCalled = false;
  private static final Log LOG = LogFactory.getLog(RackResolver.class);

  //获取配置策略,加载拓扑配置
  public synchronized static void init(Configuration conf) {
    if (initCalled) {
      return;
    } else {
      initCalled = true;
    }
    Class<? extends DNSToSwitchMapping> dnsToSwitchMappingClass =
      conf.getClass(
        CommonConfigurationKeysPublic.NET_TOPOLOGY_NODE_SWITCH_MAPPING_IMPL_KEY, 
        ScriptBasedMapping.class,
        DNSToSwitchMapping.class);
    try {
      DNSToSwitchMapping newInstance = ReflectionUtils.newInstance(
          dnsToSwitchMappingClass, conf);
      // Wrap around the configured class with the Cached implementation so as
      // to save on repetitive lookups.
      // Check if the impl is already caching, to avoid double caching.
      dnsToSwitchMapping =
          ((newInstance instanceof CachedDNSToSwitchMapping) ? newInstance
              : new CachedDNSToSwitchMapping(newInstance));
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
 
  //执行IP拓扑解析
 private static Node coreResolve(String hostName) {
    List <String> tmpList = new ArrayList<String>(1);
    tmpList.add(hostName);
    List <String> rNameList = dnsToSwitchMapping.resolve(tmpList);
    String rName = null;
    if (rNameList == null || rNameList.get(0) == null) {
      rName = NetworkTopology.DEFAULT_RACK;
      if (LOG.isDebugEnabled()) {
        LOG.debug("Couldn't resolve " + hostName + ". Falling back to "
            + NetworkTopology.DEFAULT_RACK);
      }
    } else {
      rName = rNameList.get(0);
      if (LOG.isDebugEnabled()) {
        LOG.debug("Resolved " + hostName + " to " + rName);
      }
    }
    return new NodeBase(hostName, rName);
  }
  }

在上述计算机集群的基础上, Hadoop 建立起 HDFS 和 YARN 两个子系统。前者是文件系统,管数据存储;后者是计算框架,管数据处理。从功能和层次上看, YARN 是 HDFS 的用户,, YARN 的功能和作用是建立在 HDFS 基础上的, HDFS 提供数据供 YARN子系统处理和计算。两个子系统都是主从式的,HDFS上主从节点为:NameNode ,DataNode。YARN主从节点为:ResourceManager和NodeManager。用户眼中的 Hadoop 更多的是其 YARN 子系统,因为 HDFS 只起存储的作用,YARN 才进行数据的处理和计算。在 YARN 这个框架中,作为一个独立 JVM 进程,在主节点上扮演着相当于“中央政府”角色的是“资源管理者( RM )”,一个 ResourceManager 类对象。在每个从节点(普通节点)上扮演着“地方政府”角色的则是“节点管理者( NM )”,一个 NodeManager 类对象,也是作为一个独立的 JVM 进程而存在的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值