解析Linux环境下RAID 6的Q校验算法

【什么是RAID】

    RAID的概念描述在互联网上比比皆是,用最简单的原理描述,就是在定义存储方式时允许在一部分数据缺失的情况下不影响全部数据,类似于通讯领域的纠错码。不同的冗余模式形成了不同的RAID类别。       

【单一冗余模型】

    我们需要先描述仅具备一个磁盘冗余的RAID模型(思想同RAID3,RAID4,RAID5)。

    假设现在有3页空白的纸,用来记录一些数字,为了更清晰地记录,我们先将每页白纸划出相同大小的一些表格。再假设有一个可能:这3页纸,特定情况下会有其中某一页丢失。为了在上述设定情况保证这些数字能完整安全的记录下来,我们要设计一些互相牵连的冗余关系。

    如我们要记录的数字序列是:3、14、28、4、98、88  。我们可以依次在第1页和第2页写要记录的数字,在第3页写上他们的和。如下图所示:

clipboard

    根据上图,可以很容易的分析出,不管这3页中的哪一页丢失,都可以通过另两页计算另一页的数据来。很显然,即使是超过3页的情况,按上述方式设计记录模式,也可以支持任意一页记录的丢失。

    但这个模型却不会在实际中应用,原因来自于上图的第三行数据:98+88 = 186 ,从这行的运算来看,为了记录整个一行数据的和,校验页所用的空间要大于等于任何一个数据页。其实,校验和的总容量要等于所有数据页的总容量,换个角度说,如果记录的是10页数据,那么可能要用另外10页的空间来记录校验,这是完全没有意义的方案(与其这样,还不如所有数据抄两份,即RAID1的模型)

    所以,一些工程师开始用别的算法代替加法,以减少校验和的总容量,但算法的实现效果需要与加法完全相同,同时运算要足够简单。最好的方案就是异或。

    异或是基于位的运算,首先其运算性能非常好,无需更多的专门运算器。同时异或算法完全满足正运算与逆运算的完全映射(即,正运算的结果唯一,同时这个正运算的逆运算结果也唯一。这个在数学上叫什么?恕笔者数学底子差,暂时这样称呼),满足交换律和结合律。而且最重要的是,异或不会升位。

    用异或算法改写后的存储记录如下:

clipboard[1]

    可以很清晰得看到,第三行的校验和,不再是3个数字,而且不论多少个数据成员,用异或得到的校验和容量不会累加。

    为了更好的概括,我们用"+"表示这个正向的校验运算,用“-”表示其逆运算。在我们最初的描述中,就表示数字的加减法,之后"+"表示异或,“-”也是异或(异或的逆运算也是异或,所以运算器简单,速度快)

    假设有n个存储成员,把每个存储成员划分成若干个存储单元,其中n-1(数学减法,下面的Dn-1同理)个成员盘为数据,1个成员盘为校验。每个水平条带上的校验关系如下:

   D1 + D2 + D3 + ... +Dn-1 = P1

   Dx = P1 - D1 - D2 - D3 - ... -Dn-1(D序列中排除Dx)

也就是:Dx = P1 + D1 + D2 + D3 +... +Dn-1(D序列中排除Dx)

 

【多次冗余模型】

        上述单一冗余仅支持一个存储成员的缺失,在实际中有可能需要更高的冗余性,则需要更进一步对算法进行改进。

        如果需要设计一种存储模型,实现在缺失2个成员的情况下,存储整体依然可以运算完整,最好的数学模型恐怕就是二元一次方程了,形如下面方程组:

    aX+bY=c

    dX+eY=f。 其中a/d  != b/e

    上述方程式用到乘法与除法,同时,乘法与除法完全可逆,且满足交换律、结合律与分配率。

    还是在加法中遇到的困难,普通的数学乘法会导致校验容量的累加,所以不可取。有没有一种乘除法符合我们的要求呢?有!---基于伽罗华域的乘除法。

    数学概念是很抽象的,仅以GF(2^8)为例,我们设计一个有限循环域,域上仅有0-255这几个数字,这些数字之间再设计一个完整的加减乘除运算,其结果依然在这些数字中,而且运算结果唯一,无二义性。

    我们来设计一种算法,对于2,如果2的n次方大于某个值(本原多项式),则让其对这个值(本原多项式)取余,确保又折回到0-255这个范围内,如果从2^0,2^1,2^2,,,直到2^255,按这个规律做运算,得到的值均处于0-255范围内,且均不相等,这样就形成了一个一对一的映射关系,同时满足2的这些次幂与结果之间就乘法/除法的运算规律(具体理论需参考群、环、域、有限域等数学理论)。

    在GF(2^8)上,有16个满足条件的本原多项式,分别如下:

1     x8+x7+x6+x5+x4+x2+1          1 1111 0101 = 0x1F5  

2     x8+x7+x6+x5+x2+x+1            1 1110 0111 = 0x1E7

3     x8+x7+x6+x3+x2+x+1            1 1100 1111 = 0x1CF

4     x8+x7+x6+x+1                         1 1100 0011 = 0x1C3

5     x8+x7+x5+x3+1                       1 1010 1001 = 0x1A9

6     x8+x7+x3+x2+1                       1 1000 1101 = 0x18D

7     x8+x7+x2+x+1                         1 1000 0111 = 0x187

8     x8+x6+x5+x4+1                       1 0111 0001 = 0x171

9     x8+x6+x5+x3+1                       1 0110 1001 = 0x169

10   x8+x6+x5+x2+1                       1 0110 0101 = 0x165

11   x8+x6+x5+x+1                         1 0110 0011 = 0x163

12   x8+x6+x4+x3+x2+x+1            1 0101 1111 = 0x15F

13   x8+x6+x3+x2+1                       1 0100 1101 = 0x14D

14   x8+x5+x3+x2+1                       1 0010 1101 = 0x12D

15   x8+x5+x3+x+1                        1 0010 1011 = 0x12B

16   x8+x4+x3+x2+1                      1 0001 1101 = 0x11D

     常用0x11D做为raid6的本原多项式,意思是2的n次方如果大于0x11D,就对于做xor的取余运算,确保结果小于0x256,这样就可以算出2^0到2^255之间的所有数值。

    GF(2^8)上的加减法同样是异或算法(xor)。

    GF(2^8)上的乘法即多项式乘法,但依然要对本原多项式取xor余,在算法设计上,有多种计算方式,但在GF(2^8)上,最快的推荐方法是查表法,只需事先计算好所有的0~255 分别乘以 0~255的值,生成65536个值的表格,计算时直接查表即可。也有使用对数查表法,使乘法转变为加法进行运算的,需要查表和加法结合使用。

    GF(2^8)上的除法可转换为对其逆元的乘法,即a 除以 d,假设d对应于(x的m次幂),那找出对应(x的255-m次幂)的值d',a除以d,即等于a乘以d'。

【RAID6】

    在,加减乘除都确定后,2元一次方程组就可以求解了。所以,一个以此原理生成的RAID的结构设计大致如下图(以5块盘为例,P为第一重校验,Q为第二重校验,xn为数据):

clipboard[2]

     之所以P和Q螺旋式循环分布,是为了使所有磁盘负载均衡,如果不好理解,可以把P和Q单独放在一列中,算法的意义是相同的。

   再重复一下,下面提及的+、-、*、/运算都是指基于GF(2^8)上的加、减、乘、除

   P值等于同一行(条带)上的所有单元相加的和。或者可以理解为1与每个单元相乘后的累加和,如第一个条带的P:

    P= x1+x2+x3  也就是P=1*x1 + 1*x2 + 1*x3

   在GF(2^8)上,每个多项式对应一个0~255的值,即d0对应多项式X的0次幂,d1对应多项式X的2次幂等,按多项式展开,X为2进制,故d0 = 1,d1 =2,d2=4 ,d3=8,等等,如下表所示:

clipboard[3]

    返回RAID结构图中,Q值等于每个数值单元格乘以他们的相应的dn再累加的结果,其中dn可约定,只需保证同一条带的运算中不重复出现dn即可,如第一行的Q可以为:

Q = d1* x1 + d2*x2 +d3*x3

这样,对于每一行(条带),就可以保证任意2个单元丢失,都可以计算出来(为了明了,以下计算直接将减法改为加法):

以第一行为例:

a) 如果P,Q均丢失,数据区不影响,x1,x2,x3均可正常读写

b)如果xn丢失,根据P或Q都可计算出来(实际中,因P 的计算更快速,通常会使用P校验计算出丢失的 xn)

c)如果P,xn丢失,P值不做处理,假设丢失的是x2,根据Q值的定义

      Q = d1* x1 + d2*x2 +d3*x3

=> d2*x2 = Q + d1*x1 + d3*x3

=> x2 = (Q + d1*x1 + d3*x3) * x253 ;//注:x253为x2的逆元,可以查表得到

d) 如果两个x丢失,则可根据二元一次方式的标准解法进行求解,假设丢失的是x1,x3:

      P = x1+x2+x3

      Q =  d1* x1 + d2*x2 +d3*x3

=> x1 = P + x2 + x3

=> Q = d1 * (P + x2 + x3) +d2*x2 +d3*x3

=> Q = d1*P + d1*x2 + d1* x3 + d2*x2 + d3*x3

=> Q = d1*P + d1*x2 + d2*x2 + d1*x3 + d3*x3

=> Q + d1*P + d1*x2 + d2*x2 = (d1+d3) * x3

=> x3 = ( Q + d1*P + d1*x2 + d2*x2) / (d1+d3)

查表法得到(d1 + d3)的逆元dn后,可知

x3 = ( Q + d1*P + d1*x2 + d2*x2) * dn  

再根据P= x1 + x2 + x3求得x1,即完成所有数据的补缺。

 

 

【前言】

   RAID为廉价磁盘冗余阵列(Redundant Array of Inexpensive Disks),RAID技术将一个个单独的磁盘以不同的组合方式形成一个逻辑硬盘,从而提高了磁盘读取的性能和数据的安全性。不同的组合方式用RAID级别来标识,常见RAID的级别有0、1、01、10、5、6等等。具体实现的数据存储的原理请参考相关文章。本章主要概述Linux环境下RAID 6级别的存储原理。Linux环境下配置RAID的命令是“mdadm”,如果不知道该命令如何使用请参考文章《Linux系统中实现RAID卷详解》。


【RAID 6概述】

   RAID 6是指带有两种分布存储的奇偶校验码(既P和Q)的独立硬盘结构。与RAID 5相比,RAID 6增加了第二个独立校验码(Q)信息块,两个独立的奇偶校验系统使用不同的算法,数据的可靠性非常高,即使两块硬盘同时失效也不会影响数据的使用,主要是用于要求数据绝对安全的场合。如下图:

wKiom1LbXrTj3w9zAADou_pfCsM413.jpg

上图中Q为RAID 6的第二个校验信息块,采用的是非常复杂的“伽罗华域”算法,稍后会讲到。


【RAID 6的P校验概述】

   其实RAID 6的P校验和RAID 5的校验是一样的,都是采用的“异或”运算。异或运算符的原则就是相同为0,不同为1的。在RAID 5的环境中只能掉一块硬盘,但是RAID 6在RAID 5的基础上添加了Q校验,因此RAID 6支持同时掉两块盘。异或运算如下:

P = A + B + C = A xor B xor C

A = P - B - C = P xor B xor C

注意:上述的加减法都是异或运算。


【RAID 6的Q校验概述】

   说到Q校验就有点复杂了,它采用上面所提到的“伽罗华域”算法。“伽罗华域”实际上就是“0-255”的一个有限域GF(2^8),在GF(2^8)内不管是是加、减、乘、除都不会超过这个范围。并且,加减法可逆,乘除法可逆,而且计算的值在GF(2^8)内是唯一的。注意:此处提到的加、减、乘、除法不是日常使用的加减乘除,而是“伽罗华域”内的运算。在GF(2^8)中,如果2的n次方大于某个值(本原多项式)就会对该值(本原多项式)取余,结果又会返回到GF(2^8)中。因此,保证了2^0到2^255的结果值在GF(2^8)内是唯一的。

在GF(2^8)中一共有16个本原多项式,分别如下:

1     x8+x7+x6+x5+x4+x2+1              1 1111 0101 = 0x1F5  

2     x8+x7+x6+x5+x2+x+1               1 1110 0111 = 0x1E7

3     x8+x7+x6+x3+x2+x+1               1 1100 1111 = 0x1CF

4     x8+x7+x6+x+1                     1 1100 0011 = 0x1C3

5     x8+x7+x5+x3+1                    1 1010 1001 = 0x1A9

6     x8+x7+x3+x2+1                    1 1000 1101 = 0x18D

7     x8+x7+x2+x+1                     1 1000 0111 = 0x187

8     x8+x6+x5+x4+1                    1 0111 0001 = 0x171

9     x8+x6+x5+x3+1                    1 0110 1001 = 0x169

10    x8+x6+x5+x2+1                    1 0110 0101 = 0x165

11    x8+x6+x5+x+1                     1 0110 0011 = 0x163

12    x8+x6+x4+x3+x2+x+1               1 0101 1111 = 0x15F

13    x8+x6+x3+x2+1                    1 0100 1101 = 0x14D

14    x8+x5+x3+x2+1                    1 0010 1101 = 0x12D

15    x8+x5+x3+x+1                     1 0010 1011 = 0x12B

16    x8+x4+x3+x2+1                    1 0001 1101 = 0x11D

RAID 6常用的本原多项式为0X11D,既上列中最后一个。Linux 环境中的RAID 6也是如此。

好了回到Q校验上,Q校验和P校验结合正好组成了一个二元一次方程,K1、K2、K3为GF(2^8)中多项式的数值。

P = A + B + C

Q = A*K1 + B*K2 + C*K3


【伽罗华域的乘除法运算】

   伽罗华域中的加减法也是异或运算,所以就不做详细解释了,重点解释一下乘除法。通过上面的Q校验知道Q校验的生成需要伽罗华域中的乘法运算,计算乘法运算是一件非常复杂的事情,最好的解决办法就是将GF(2^8)中所有多项式的值生成表格,通过查表得知乘法运算的值。

1、生成正表GFILOG

通过下表的方法生成正表GFILOG,注意:此表的本原多项式为0X11D。

wKiom1LbfKCRRFRvAAGoGmYYD3A702.jpg

如下:是正表GFILOG

wKioL1LbfM7C1mdoAAG64i_A9r0398.jpg

2、生成反表GFLOG

    有了正向变换表,要得到逆向表就很简单了,把正向中的表变换值做为索引,在把正向表中的索引作为值就OK了。如下表:

wKiom1LbfmXSY32YAAHLu-fPL7g224.jpg

3、计算乘除法运算(查表法)

乘法:A * K1 = GFILOG[(GFLOG[A]+GFLOG[K1]) mod 255];

除法:A / K1 = GFILOG[(GFLOG[A]-GFLOG[K1]+255) mod 255];

现在知道了伽罗华域的乘除法,那么我们计算Q校验就方便了许多。


【根据Q校验生成丢失的数据】

当RAID 6中坏掉两块磁盘,那该如何生成丢失的数据呢?用RAID 6的一个条带举例说明。

1、如果某个条带中丢失的两块数据是P和Q,那么正好,数据没有丢失,正常提取即可。


2、如果某个条带中丢失的两块数据是P和A,那么可以根据Q校验计算出A的数据。

P = A*K1 + B*K2 + C*K3

A*K1 = P + B*K2 + C*K3

A = (P + B*K2 + C*K3)* K1   //注:K1可以同过查表获取


3、如果某个条带中丢失的两块数据是Q和A,那么可以根据校验P计算出A的数据。

P = A + B + C

A = P + B + C


4、如果某个条带中丢失的两块数据是A和B,那么可以根据校验P和Q计算出A和B的数据。

P = A + B + C

Q =  A*K1 + B*K2 + C*K3

A = P + B + C

Q = (P + B + C)*K1 + B*K2 +C*K3

Q = P*K1 + B*K1 + C*K1 + B*K2 + C*K3

Q = P*K1 + C*K1 + C*K3 + B*K1 + B*K2

Q + P*K1 + C*K1 + C*K3 = (K1+K2) * B

B = ( Q + P*K1 + C*K1 + C*K3) / (K1+K2)

计算出B的值以后,再根据P校验和计算出A的值就容易很多了。

A = P + B + C


【Linux环境下的RAID 6】

   根据前的内容已经知道RAID 6的大致原理了。因为伽罗华域的本原多项式有16种,因此RAID 6的种类有很多,再加上K值的不固定。因此计算某个RAID 6的Q校验值会变的很复杂。不过Linux环境下的RAID 6的K值经过测试,其值根据够成RAID 6阵列的磁盘数,从本原多项式0X11D的开始取(RAID 6总磁盘数 -2)个多项式的值作为K的值。



 

你可能感兴趣的:(linux,技术,安全性,文章,可靠性)