1. 程式人生 > 其它 >HDFS學習:HDFS機架感知與副本放置策略

HDFS學習:HDFS機架感知與副本放置策略

洋哥YARN和HDFS實踐系列大作,這是第三篇,前面兩篇分別是:

Yarn【label-based scheduling】實戰總結(二)

Yarn【label-based scheduling】實戰總結(一)

1.1 機架感知(RackAwareness)概述

通常,大型Hadoop叢集會分佈在很多機架上。在這種情況下,

-- 希望不同節點之間的通訊能夠儘量發生在同一個機架之內,而不是跨機架。

-- 為了提高容錯能力,名稱節點會盡可能把資料塊的副本放到多個機架上。

綜合考慮這兩點的基礎上Hadoop設計了機架感知功能。

1.1.1 外在指令碼實現機架感知

HDFS不能夠自動判斷叢集中各個datanode的網路拓撲情況。這種機架感知需要topology.script.file.name屬性定義的可執行檔案(或者指令碼)來實現,檔案提供了IP->rackid的翻譯。NameNode通過這個得到叢集中各個datanode機器的rackid。如果topology.script.file.name沒有設定,則每個IP都會翻譯成/default-rack。

為了獲取機架id,可以寫一個小指令碼來定義IP(或者DNS名),並把想要的機架id列印到標準輸出stdout。

這個指令碼必須要在配置檔案hadoop-site.xml裡通過屬性’topology.script.file.name’來指定。

例如:

用Python語言編寫的指令碼範例:

1.1.2 內部Java類實現機架感知

該處採用配置topology.node.switch.mapping.impl來實現機架感知,需在core-site.xml配置檔案中加入以下配置項:

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

還需編寫一個JAVA類,一個示例如下所示:

public class JavaTestBasedMapping implements DNSToSwitchMapping {
       //key:ip value:rack
       private staticConcurrentHashMap<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
       publicList<String> resolve(List<String> names) {
              List<String>m = new ArrayList<String>();
              if (names ==null || names.size() == 0) {
                    m.add("/default-rack");
                    return m;
              }
              for (Stringname : names) {
                    Stringrack = cache.get(name);
                    if (rack!= null) {
                           m.add(rack);
                    }
              }
              return m;
       }
}

將上述Java類打成jar包,加上執行許可權;然後放到$HADOOP_HOME/lib目錄下執行。

1.1.3 網路拓撲(NetworkTopology)

有了機架感知,NameNode就可以畫出上圖所示的datanode網路拓撲圖。D1,R1都是交換機,最底層是datanode。則H1的rackid=/D1/R1/H1,H1的parent是R1,R1的是D1。這些rackid資訊可以通過topology.script.file.name配置。有了這些rackid資訊就可以計算出任意兩臺datanode之間的距離。

distance(/D1/R1/H1,/D1/R1/H1)=0  相同的datanode
distance(/D1/R1/H1,/D1/R1/H2)=2  同一rack下的不同datanode
distance(/D1/R1/H1,/D1/R1/H4)=4  同一IDC下的不同datanode
distance(/D1/R1/H1,/D2/R3/H7)=6  不同IDC下的datanode

1.2 副本放置策略(BPP:blockplacement policy)

第一個block副本放在和client所在的node裡(如果client不在叢集範圍內,則這第一個node是隨機選取的,當然系統會嘗試不選擇哪些太滿或者太忙的node)。

第二個副本放置在與第一個節點不同的機架中的node中(隨機選擇)。

第三個副本和第二個在同一個機架,隨機放在不同的node中。

如果還有更多的副本,則在遵循以下限制的前提下隨機放置

--1個節點最多放置1個副本

-- 如果副本數少於2倍機架數,不可以在同一機架放置超過2個副本

當發生資料讀取的時候,名稱節點首先檢查客戶端是否位於叢集中。如果是的話,就可以按照由近到遠的優先次序決定由哪個資料節點向客戶端傳送它需要的資料塊。也就是說,對於擁有同一資料塊副本的節點來說,在網路拓撲中距離客戶端近的節點會優先響應。

Hadoop的副本放置策略在可靠性(block在不同的機架)和頻寬(一個管道只需要穿越一個網路節點)中做了一個很好的平衡。下圖是備份引數是3的情況下一個管道的三個datanode的分佈情況。