HDFS RAID
背景
HDFS RAID的工作源自Facebook。首先,看看HDFS RAID的作者之一Dhruba Borthakur在2009年发表的博文的一部分。
HDFS的主要不足之一是每份数据要复制在三个地方,当今,磁盘存储越来越便宜,这是可以接受的,相对于小型或中型规模的机群,这并不是一个问题。使用15块磁盘和10块磁盘的价格差距并不大。假设每GB数据的成本为$1,那么15块1TB磁盘和10块1TB磁盘的价格差只是$5k。但如果机群的总数据量是10PB的话,那么将数据存储在两个地方而不是三个,节省的成本是$10,000,000!
上述是在2009年的数据,如今磁盘存储的成本已不到¥1/GB了。
HDFS使用3副本是因为它使用商用机器以及磁盘有不可忽略的出现故障的机率。据观测,在实践中使用3副本已经足以保证不丢失数据。现在的挑战是要保持真实的副本数接近2而有效副本数是3。Erasure Codes是最好的实现方案。
作者的想法参考自CMU的DiskReduce,这是一种在HDFS实现erasure codes的方法。HDFS的代码本身就比较复杂,为了不使其变得更加复杂,作者将HDFS Erasure Coding作为HDFS之上的一个软件层,而不是HDFS中的一部分。
概况
HDFS RAID模块提供一个使用Hadoop分布式系统(DFS)的分布式Raid文件系统(DRFS),在DRFS中存储的文件被分成多个由块组成的stripe。对于每个stripe,若干parity(校验)块存储在与源文件对应的parity文件中。这使得当源文件或parity文件中的块丢失或损坏进可以重新计算并恢复成为可能。
DRFS的主要好处是增加针对数据损坏的保护,有了这样的保护,可以采用更低的副本数来保持同样的可用性保障,将会节省很大的存储空间。
架构与实现
Raid是Hadoop mapreduce的一个contrib,Hadoop 0.21.0以上版本就有。
HDFS Raid包含几个软件模块:
- DRFS client:为应用提供访问DRFS中文件的接口,当在读文件时能透明地恢复任意损坏或丢失的块;
- RaidNode:为存储在DRFS的所有数据文件创建和维护parity文件的后台进程;
- BlockFixer:周期性重新计算已经丢失或损坏的块;
- Raidshell:允许管理员手动触发丢失或损坏的块的重新计算或检查已遭受不可恢复损坏的文件;
- ErasureCode:提供对块中字节的编码及解码。
DRFS client
DRFS client作为DFS client之上的一软件层,拦截所有进来的请求并传它们传递给下边的客户端。当下边的DFS抛出ChecksumException或BlockMissingException异常,DFS client捕获这些异常,定位当前source文件的parity文件,并在返回丢失的块给应用前将它们重新计算。
值得注意的是,DRFS client在读到损坏的文件重新计算丢失的块时,并不会将这些丢失的块存到文件系统中,它在完成应用的请求后将其忽略。BlockFixer和RaidShell能用来永远地修改损坏的块。
RaidNode
RaidNode定期扫描配置指定的所有路径,对于每个路径,递归地检查所有拥有超过2个块的文件并选择那些最近(默认是24小时内)没被修改过的文件。一旦选择了一个source文件,它会遍历该文件的所有stripe并为每个stripe创建合适数量的parity块,最后所有的parity块会被合并在一起并存储在与source文件相关的parity文件。RaidNode也会定期删除那些已经孤立或过时的parity文件。
当前RaidNode有两种实现:
- LocalRaidNode:在RaidNode本地计算parity块,因为计算parity块是一个计算密集型任务,所以这种方法的可扩展性受到限制;
- DistributedRaidNode:分配MapReduce任务来计算parity块。
BlockFixer
BlockFixer是一个运行在RaidNode上的一个后台进程,周期性地检查DRFS配置的所有路径的状态。当发现一个有丢失或损坏块时,这些块会被重新计算并放回文件系统中。
从Namenode获得损坏文件列表,source文件通过“解码”来重新构造,parity文件通过“编码”来重新构造。
当前BlockFixer有两种实现:
- LocalBlockFixer:在RaidNode本地重新计算损坏的块;
- DistBlockFixer:分配MapReduce任务来重新计算块。
RaidShell
RaidShell是一个允许管理维护和检查DRFS的工具,支持手动触发重新计算坏数据块的命令,允许管理查看不可修复文件列表。
运行以下命令可以检验文件系统的完整性:
$HADOOP_HOME/bin/hadoop org.apache.hadoop.raid.RaidShell -fsck [path]
这会打印已损坏文件列表。
ErasureCode
ErasureCode是被BlockFixer和RaiNode用来生成parity块和修改parity/source块的一组件,ErasureCode实现编码和解码。当在编码时,ErasureCode取几个source字节并生成一些parity字节。当在解码时,ErasureCode通过剩余的souce字节和parity字节来生成丢失的字节。
能被恢复的丢失的字节的个数等于被创建的parity字节的个数。比如,我们把10个source字节编码成3个parity字节,我们能通过剩下的10个字节来恢复任意3个丢失的字节。
ErasureCode有两种实现:
- XOR:只允许创建一个parity字节;
- Reed-Solomon:允许创建任意给定数目的parity字节。
使用Reed-Solomon,source文件的副本数能减少到1而不造成数据丢失。1个块只有1个副本的不足是只能通过1个固定的机器来读取1个块,减少了并行性。因此,Reed-Solomon应该用在不会被频繁使用的数据。
参考资料
后记
文中若有错误或疏漏之处,烦请批评指正。