HDFS-RAID 是Facebook基於hadoop-20-append分支(第一代Hadoop)開發的raid方案,對HDFS的修改極少,主要包括爲NameNode增長了根據block信息找到block所屬文件的接口。RAID的基本知識和目前社區的方案對比見這,本文重點分析HDFS-RAID的原理和實現。html
業界經常使用的編碼方式包括Reed-Solomon(RS),XOR,他們本質上都是對N個數據塊就行運算,產生K個校驗塊。這N+K個塊能夠同時最多容忍K個塊的丟失,丟失的塊能夠從其他的塊中的任意N個恢復出來。在HDFS-RAID裏面,N叫作stripeLength,K叫作parityLength。在對數據塊和校驗塊的組織上,HDFS-RAID提供了兩種方式:node
HDFS-RAID主要由三個模塊組成,一個包裝了DistributedFileSystem的DistributedRaidFileSystem,一個是RaidNode進程,另一個RaidShell命令行工具。git
DistributedRaidFileSystem基於DistributedFileSystem,是一種FilterFileSystem,在DistributedFileSystem讀數據拋出BlockMissingException或者ChecksumException一場時,會構造
DecoderInputStream,構造的過程當中,會作block fix過程,找到stripeLength個數據塊,啓動幾個線程同時讀取這幾個數據塊,decode完成將修復的block數據放入buf中,上層便可以進行讀取。
應用使用DistributedRaidFileSystem須要在hdfs-site.xml中設置:github
<property> <name>fs.hdfs.impl</name> <value>or g.apache.hadoop.dfs.DistributedRaidFileSystem</value> </property>
其餘配置見wikiapache
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發送過去。json
採用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指令,並把數據發送給它。app
主要提供兩個配置文件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>
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>
實際上,少於2個block的文件不會被RAID。