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。