存储之道 原文 http://alanwu.blog.51cto.com/3652632/1406312
在传统存储领域,随着磁盘容量的不断增大, RAID 数据重构时间将会是一个非常严重的问题。大家知道,过长的数据重构时间意味着数据可靠性下降。所以,在RAID 设计的过程中,一定要考虑数据重构的时间,并且尽可能的将“无数据保护状态”的时间降到最小。在不改变传统 RAID 架构前提下,只能通过增加数据冗余度来缓解大容量磁盘引入的超长数据重构时间的问题。这种思路就好比几年前,当RAID5 无法满足过长数据重构时间时,只能被迫采用 RAID6 算法,通过 RAID6 能够提供两块盘的冗余度来缓解长时间数据重构的问题。随着时间的推移,目前,在很多应用中, RAID6 也无法满足应用需求了。为了达到更高的数据冗余度,一个比较不错的选择是采用冗余度更大的编解码方式: Erasure Code 。很多公司将基于这种编码方式的 RAID 称之为 RAID7 。
在互联网领域,通常采用 Server SAN 的存储架构方式。也就是将廉价的 Server通过集群软件的方式组建一套分布式的存储系统。 Google 首先倡导了这种方式,架构了 GFS 系统,将很多非格式化的数据(例如网页)存储到这种分布式系统中。通常,这种廉价的 Server 是不具备 RAID 功能的,那么数据可靠性如何保证呢?在这种 Server SAN 中,通常会将数据复制多份存储到不同的节点上,一旦一个节点失效,数据可以从其它节点上获取。数据多节点复制的方式可以很好的提高数据可靠性,并且可以将读写数据流很好的分离。但是,带来的问题是存储利用率大为降低。对于一般的数据,通常会存储三份,对于非常重要的数据,会存储六份。如何平衡存储空间和数据可靠性成了分布式存储需要考虑的重要问题。Erasure Code 可以平衡这两者关系,在提高存储空间利用率的前提下,不会影响数据可靠性。采用 Erasure Code 对数据进行编码冗余的方式和“网络 RAID ( RAIN)”的概念是很相像的。当互联网领域引入 Erasure Code 之后,需要考虑的问题是如何降低编解码的运算复杂度问题。
事实已经证明, Erasure Code 作为一种数据编解码技术在大数据环境下有了十分迫切的需求。不仅传统的 RAID 需要这种技术,而且分布式存储也需要这种技术去提升存储资源利用率。
常用的 Erasure code 是基于范德蒙( Vandermonde )矩阵的 RS 算法。其基本思想很简单,采用范德蒙矩阵作为生成矩阵,得到校验数据。现假设输入数据为D1~Dn ,生成的校验数据为 C1~Cm ,那么输入数据和校验数据之间的关系可以描述为:
其中,
为范德蒙矩阵,该矩阵为编码矩阵。所以,为了得到校验数据,主要的任务是将输入数据和编码矩阵相乘,得到的输出结果就是编码值。为了能够更好的表示磁盘上存储的数据,通常将编码矩阵方程表示如下:
可以发现这个生成矩阵( A )就是单元矩阵和范德蒙矩阵的组合。输入数据( D)和生成矩阵( A )的乘积就是编码之后的存储数据( E )。采用传统 RAID 的思路去理解,编码之后的结果就是一个条带需要存储的所有数据。
编码过程我们已经很清楚了,生成矩阵的格式很规整。那么,问题是如何进行解码操作呢?当存储的数据 d1~dn,c1~cm 中有些数据无法读取时,如何进行数据恢复呢?从数学的原理来看,只要将读取的有效数据和生成矩阵的逆矩阵相乘就可以恢复丢失的数据。假设 m 个数据块丢失,则可以将 m 个数据块对应的矩阵 A 和 E中的行删掉,得到新的 n*n 阶生成矩阵 A2 和 1*n 阶结果矩阵 E2 。由于生成矩阵是有范德蒙矩阵和单元矩阵的组合,所以,矩阵 A 的任意 n 行子集都可以保证线性无关。因此,需要恢复的数据可以通过 A2 和 E2 的逆矩阵乘积得到,即 D= 逆(A2 ) * 逆( E2 )。
从数学的角度来看,我们现在常用的 RAID5 和 RAID6 算法只是范德蒙矩阵算法的一个子集而已。当冗余数据只有一个的时候,就退化成了 RAID5 算法,在实数域只需要将输入数据累加就可以得到校验码了。为了简化计算复杂度,编解码运算放到了迦罗话域,加法运算变成了 XOR 逻辑运算。当冗余数据有两个的时候,范德蒙矩阵退化成了 RAID6 算法,也可以在迦罗华域通过查表、 XOR 的方法完成运算。具体可以参考文章《 一个 IO 的传奇一生( 12 ) -- 磁盘阵列 1 》。
从这个角度来看,基于范德蒙矩阵的 Erasure Code 方法是传统 RAID5/RAID6 算法的扩展。在实现过程中,同样可以在迦罗华域中完成乘、除和加减法运算。为了实现快速算法,需要构建两张对数表和反对数表,然后通过查表和 XOR 运算快速实现编解码。
基于范德蒙矩阵的 Erasure Code 编解码原理比较简单,可以说是在RAID5/RAID6 算法基础上的一种延伸。采用这种方法的算法复杂度还是比较高的,编码复杂度为 O ( mn ),其中 m 为校验数据个数, n 为输入数据个数。解码复杂度为 O ( n^3 ),解码具有较高的计算复杂度。