HDFS-RAID原理和實現

jopen 9年前發布 | 26K 次閱讀 HDFS 分布式/云計算/大數據

HDFS-RAID 是非死book基于hadoop-20-append分支(第一代Hadoop)開發的raid方案,對HDFS的修改極少,主要包括為NameNode增加了根據block信息找到block所屬文件的接口。RAID的基本知識和目前社區的方案對比見,本文重點分析HDFS-RAID的原理和實現。

業界常用的編碼方式包括Reed-Solomon(RS),XOR,他們本質上都是對N個數據塊就行運算,產生K個校驗塊。這N+K個塊可以同時最 多容忍K個塊的丟失,丟失的塊可以從其余的塊中的任意N個恢復出來。在HDFS-RAID里面,N叫做stripeLength,K叫做 parityLength。在對數據塊和校驗塊的組織上,HDFS-RAID提供了兩種方式:

  1. 每個數據文件對應一個校驗文件,對數據文件的連續stripeLength個block進行編碼,產生parityLength個parity block,多個parity block組成parity文件存儲在HDFS上。例子:stripeLength=3,parityLength=2,數據文件有6個block,那么 對這個數據文件做raid會產生4個parity block,這四個parity block被連接起來組成parity文件。數據文件和parity文件的存放路徑存在一定的規則,根據配置決定.
  2. 數據block可以從不同的數據文件中抽取進行組合,這種方式下,就不存在數據文件和parity文件的一一對應關系,這樣的組合用 StripeInfo表示,里面包括:數據塊列表,校驗塊列表,編碼方式。并且為了容錯,這個信息需要持久化,實現中,這個信息可以以多個文件的形式存在 本地硬盤(LocalStripeStore)上,也可以存在RDBMS(DBStripeStore)中。值得注意的是,在對某個block進行恢復的 時候,需要根據corrupt block信息從StripeStore中取出用于恢復的stripeLength個block,而讀取這些block的數據需要拿到block所在的文 件名等信息才能讀取,而NameNode不提供block到file的接口,所以HDFS-RAID為了NameNode增加了這樣的接口。

HDFS-RAID主要由三個模塊組成,一個包裝了DistributedFileSystem的DistributedRaidFileSystem,一個是RaidNode進程,另外一個RaidShell命令行工具。

DistributedRaidFileSystem

DistributedRaidFileSystem基于DistributedFileSystem,是一種FilterFileSystem, 在DistributedFileSystem讀數據拋出BlockMissingException或者ChecksumException一場時,會 構造
DecoderInputStream,構造的過程中,會做block fix過程,找到stripeLength個數據塊,啟動幾個線程同時讀取這幾個數據塊,decode完成將修復的block數據放入buf中,上層即可以進行讀取。
應用使用DistributedRaidFileSystem需要在hdfs-site.xml中設置:

<property>
  <name>fs.hdfs.impl</name>
  <value>or  g.apache.hadoop.dfs.DistributedRaidFileSystem</value>
</property>

其他配置見wiki

RaidNode

編碼

RaidNode的TriggerMonitor線程根據配置的策略(PolicyInfo)不斷的選擇符合RAID條件的文件,然后做RAID。 做RAID有兩種方式,一種是單機(LocalRaidNode),另外一種是分布式(DistRaidNode),利用MapReduce Job。HDFS-RAID中有一個encodingUnit的概念,它是做RAID的單位,默認是1。以分布式做RAID為例,假設 stripeLength=3, parityLength=1,encodingUnit=2, TriggerMonitor選出了兩個文件a和b,文件a有6個block, b有12個block,可以得出,a有6/3=2個stripe,b有12/3=4個stripe, encodeingUnit=2代表2個stripe作為一個unit,unit用EncodingCandidate表示,這個例子會產生三個 EncodingCandidate。每個EncodingCandidate作為mapper的key,相應的PolicyInfo作為value寫入 Job的Input文件_distRaid.op.list(Job目錄下)中作為一行。輸入文件由DistRaidInputFormat來解析。 Mapper類是DistRaidMapper,map函數就是對輸入的EncodingCandidate范圍內的stripe做raid。做 raid,需要讀stripeLength個塊數據,生成parityLength個校驗塊,默認會有4個線程來做讀操作,每個線程就是打開數據 block所在的文件,并且seek到block的開始offset,然后將數據讀入readbuf中,每個block對應一個readbuf,同時有 parityLength個writebuf,用于存編碼完成的parity塊。最后將生成的parity塊連成一個parity file。為了更安全,HDFS-RAID有一個ChecksumStore的概念,開啟后,會將數據block和校驗block的crc都存入 ChecksumStore中,后續如果發現有block損壞,進行修復完成后,從ChecksumStore中取出以前block的crc進行比對,如 果相等,說明恢復無誤,然后選擇一個DataNode將恢復的block發送過去。

采用RAID方式后,為了提高可用性,盡量不在同一個機器上存儲屬于同一個stripe group的兩個block,PlacementMonitor線程用來做這個。

修復

BlockIntegrityMonitor用來定期檢測corrupt的file,并進行修復。同樣,修復block有分布式和本地修復兩種方 式。同樣,以DistBlockIntegrityMonitor為例,獲取corrupt file通過DFSck向NameNode獲得,拿到corrupt文件名以及對應的corrupt的塊個數后,調用FileCheckRunnable 來檢查文件是否已經corrupt,這里的corrupt是對DistributedRaidFileSystem而言的,只要corrupt block所在的stripe group(包括stripeLength個數據塊和parityLength個parity塊)中有至少stripeLength個數據塊是好的,那么 這個corrupt block就可以恢復,說明這個文件對于DistributeRaidFileSystem來說就是好的,沒有corrupt,在這種情況下,會提交一個 Job對這些corrupt block進行修復。Mapper是ReconstructionMapper,輸入文件的內容是corrupt file。Mapper的map函數拿到corrupt file name,然后進行reconstruct,這塊的流程原理和編碼差不多,不再贅述。恢復成功block后,選擇一個DataNode,給它發送 WRITE_BLOCK指令,并把數據發送給它。

策略

主要提供兩個配置文件raid.xml和raid-default.xml

raid.xml:

<configuration> 
    <policy name = "RaidTest1"> 
        // prefix指定的路徑下的文件(遞歸)被掃描檢查是否滿足RAID條件
        <srcPath prefix="/user/foxmailed/raidtest"/>
        // 引用raid-default.xml中定義的id
        <codecId>xor</codecId>
        <property> 
            <name>targetReplication</name> 
            <value>1</value> 
            <description>after RAIDing, decrease the replication factor of a file to this value.</description> 
        </property> 
        <property> 
            <name>metaReplication</name> 
            <value>1</value> 
            <description> replication factor of parity file</description> 
        </property> 
        <property> 
            // 一個文件只有2秒沒有修改過才有可能被RAID
            <name>modTimePeriod</name> 
            <value>2000</value> 
            <description> time (milliseconds) after a file is modified to make it a candidate for RAIDing 
            </description> 
        </property> 
    </policy>
    // fileList指定的文件每一行的文件是RAID的候選,編碼方式引用名為RaidTest1的policy
    <policy name = "RaidTest2">
        <fileList>/user/foxmailed/fileList.txt</fileList>
        <parentPolicy>RaidTest1</parentPolicy>
    </policy>

</configuration></pre>

raid-default.xml中主要配置RaidNode支持的編碼類型

<configuration>
<property>
<name>raid.codecs.json</name>
<value>
[{
"id" : "rs", //編碼id,在raid.xml中用到,用來飲用具體的編碼
"parity_dir" : "/raidrs",//校驗文件存放的位置
"stripe_length" : 10, 
"parity_length" : 4, //10個data block編碼生成4個parity block
"priority" : 200,
"erasure_code" : "org.apache.hadoop.raid.ReedSolomonCode", //具體編碼類
"description" : "ReedSolomonCode code",
"simulate_block_fix": true
},
{
"id" : "xor",
"parity_dir" : "/raid",
"stripe_length" : 10, 
"parity_length" : 1,
"priority" : 100,
"erasure_code" : "org.apache.hadoop.raid.XORCode",
"description" : "XORCode code",
"simulate_block_fix": true
},
{
"id" : "dir-rs",
"parity_dir" : "/dir-raidrs",
"stripe_length" : 10, 
"parity_length" : 4,
"priority" : 400,
"erasure_code" : "org.apache.hadoop.raid.ReedSolomonCode",
"description" : "Directory ReedSolomonCode code",
"simulate_block_fix": false,
"dir_raid" : true //目錄級別的RAID
}
]
</value>
<description>JSon string that contains all Raid codecs</description>
</property>
</configuration>

<p>
    實際上,少于2個block的文件不會被RAID。
</p>
<h2>
    參考資料
</h2>
<p>
    <a href="/misc/goto?guid=4959625906349823655">HDFS-RAID Wiki</a> 
</p>
<p>
    <a href="/misc/goto?guid=4959628502970569861">HDFS-RAID</a> 
</p>
<p>
    <a href="/misc/goto?guid=4959628503186984124">Hadoop 2.5.0</a> 
</p>

</div> 來自:http://www.cnblogs.com/foxmailed/p/4336266.html

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!