ラック認識

Hadoopコンポーネントはラック認識に対応しています。たとえば、HDFSブロック配置は、耐障害性のために異なるラックに1つのブロックレプリカを配置することで、ラック認識を使用します。これにより、クラスタ内のネットワークスイッチの障害またはパーティションが発生した場合にデータの可用性が確保されます。

Hadoop マスターデーモンは、構成ファイルで指定された外部スクリプトまたは Java クラスを呼び出すことによって、クラスタワーカーのラック ID を取得します。トポロジに Java クラスまたは外部スクリプトのいずれを使用する場合でも、出力は Java のorg.apache.hadoop.net.DNSToSwitchMappingインターフェースに準拠する必要があります。このインターフェースは、1対1の対応関係が維持され、'/myrack/myhost' の形式でトポロジ情報が提供されることを想定しています。ここで、'/' はトポロジ区切り文字、'myrack' はラック識別子、'myhost' は個々のホストです。ラックごとに単一の /24 サブネットを想定すると、'/192.168.100.0/192.168.100.5' の形式を一意のラックホストトポロジマッピングとして使用できます。

トポロジマッピングに Java クラスを使用するには、構成ファイルのnet.topology.node.switch.mapping.implパラメータでクラス名を指定します。例として NetworkTopology.java が hadoop ディストリビューションに含まれており、Hadoop 管理者によってカスタマイズできます。外部スクリプトの代わりに Java クラスを使用すると、新しいワーカーノードが自身を登録するときに Hadoop が外部プロセスをフォークする必要がないため、パフォーマンス上の利点があります。

外部スクリプトを実装する場合、構成ファイルのnet.topology.script.file.nameパラメータで指定します。Java クラスとは異なり、外部トポロジスクリプトは Hadoop ディストリビューションには含まれておらず、管理者によって提供されます。Hadoop は、トポロジスクリプトをフォークするときに、ARGV に複数の IP アドレスを送信します。トポロジスクリプトに送信される IP アドレスの数はnet.topology.script.number.argsで制御され、デフォルトは 100 です。net.topology.script.number.argsを 1 に変更すると、DataNode や NodeManager によって送信された各 IP に対してトポロジスクリプトがフォークされます。

net.topology.script.file.nameまたはnet.topology.node.switch.mapping.implが設定されていない場合、渡された IP アドレスに対してラック ID '/default-rack' が返されます。この動作は望ましいように見えますが、デフォルトの動作ではラックから複製されたブロックを1つ書き込むため、'/default-rack' という名前のラックが1つしかないため、HDFSブロックの複製で問題が発生する可能性があります。

python 例

#!/usr/bin/python3
# this script makes assumptions about the physical environment.
#  1) each rack is its own layer 3 network with a /24 subnet, which
# could be typical where each rack has its own
#     switch with uplinks to a central core router.
#
#             +-----------+
#             |core router|
#             +-----------+
#            /             \
#   +-----------+        +-----------+
#   |rack switch|        |rack switch|
#   +-----------+        +-----------+
#   | data node |        | data node |
#   +-----------+        +-----------+
#   | data node |        | data node |
#   +-----------+        +-----------+
#
# 2) topology script gets list of IP's as input, calculates network address, and prints '/network_address/ip'.

import netaddr
import sys
sys.argv.pop(0)                                                  # discard name of topology script from argv list as we just want IP addresses

netmask = '255.255.255.0'                                        # set netmask to what's being used in your environment.  The example uses a /24

for ip in sys.argv:                                              # loop over list of datanode IP's
    address = '{0}/{1}'.format(ip, netmask)                      # format address string so it looks like 'ip/netmask' to make netaddr work
    try:
        network_address = netaddr.IPNetwork(address).network     # calculate and print network address
        print("/{0}".format(network_address))
    except:
        print("/rack-unknown")                                   # print catch-all value if unable to calculate network address

bash 例

#!/usr/bin/env bash
# Here's a bash example to show just how simple these scripts can be
# Assuming we have flat network with everything on a single switch, we can fake a rack topology.
# This could occur in a lab environment where we have limited nodes,like 2-8 physical machines on a unmanaged switch.
# This may also apply to multiple virtual machines running on the same physical hardware.
# The number of machines isn't important, but that we are trying to fake a network topology when there isn't one.
#
#       +----------+    +--------+
#       |jobtracker|    |datanode|
#       +----------+    +--------+
#              \        /
#  +--------+  +--------+  +--------+
#  |datanode|--| switch |--|datanode|
#  +--------+  +--------+  +--------+
#              /        \
#       +--------+    +--------+
#       |datanode|    |namenode|
#       +--------+    +--------+
#
# With this network topology, we are treating each host as a rack.  This is being done by taking the last octet
# in the datanode's IP and prepending it with the word '/rack-'.  The advantage for doing this is so HDFS
# can create its 'off-rack' block copy.
# 1) 'echo $@' will echo all ARGV values to xargs.
# 2) 'xargs' will enforce that we print a single argv value per line
# 3) 'awk' will split fields on dots and append the last field to the string '/rack-'. If awk
#    fails to split on four dots, it will still print '/rack-' last field value

echo $@ | xargs -n 1 | awk -F '.' '{print "/rack-"$NF}'