分布式系统下的纠删码 -- Locally Repairable Codes (LRC)

Posted Z-Pilgrim

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分布式系统下的纠删码 -- Locally Repairable Codes (LRC)相关的知识,希望对你有一定的参考价值。

 

分布式系统下的纠删码(二) -- Locally Repairable Codes (LRC)

 

一、     名词解释

MDS: Maximun Distance Separable.

 

 

 

MDS 性质:是纠删码的一个重要性质它保证n=k+m个磁盘中任意k个磁盘都可恢复出k个数据盘或可表示为该编码容忍任意m=n-k个磁盘发生故障而数据不发生丢失传统的RSCRS码都具有MDS性质最近提出来的一些编码往往牺牲MDS性质Rotated RSLocal Repair Codes减少修复开销

这里所说的“LRC牺牲MDS性质”,本文后面会讨论LRC的容错能力,可以解释这句话。

 

二、LRC的原理

       本文默认您已经读过本文的前一篇关于EC编码的介绍,以及理解了前一篇关于EC的编码和解码过程(有例子解释)。

EC编码的介绍:http://blog.csdn.net/u011026968/article/details/52295666

 

       1、LRC与EC   

LRC和EC的不同在于,EC只有两种类型的chunk,data chunk和code chunk, 其中每个code chunk都是其他所有的data chunk的线性组合,也就是每个code chunk和其他所有的data chunk都是有关系的,称之为global code chunk。LRC和EC不同的地方在于,LRC多了一种local code chunk,local code chunk和global code chunk的不同在于,local code chunk只与部分data chunk有关系,而global code chunk和所有的data chunk都有关系。比如:

 

(PS:这个LRC是新浪的LRC算法库的构造方法)

这个例子中,编码过程如上图,可以看出

C0=D0+D1

C1=D2

上面两个code chunk只和部分Data chunk有关,也就是所谓的”local”的意思

C2= D0+2*D1+4* D2

这个code chunk和所有的Data chunk都有关系,称为global code chunk

       2、LRC的原理简述

       本质上,其实,上面的Datachunk被分成了两组EC组,C0 D0 D1这三块是一个小的EC组,如果这个组里面坏掉任何一块chunk,那么可以通过其他两块恢复,C1和D2这一组也是一样的,坏掉任何一块都是可以通过本组里面的数据恢复的。这个时候,要恢复数据,需要的源数据块数< k, k是data chunk的总的个数。而EC中,坏掉一块数据,仍然需要拉去k块数据。可以看出LRC在某些情况下,做数据的恢复可以比EC效率高(尤其分布式环境下,少拉去源数据就能少很多通信的代价)。

       但是也可以从上面的例子看出新浪的LRC的算法的一点不足,这个LRC的构造可以做到坏掉任何一个data chunk都可以拉取小于k块数据来恢复,但是如果global code坏掉呢,就是C2坏掉呢?必须拉去k块数据才能恢复。

       我所做的工作,一是把新浪的LRC库用的范德蒙矩阵换成柯西矩阵(据说柯西矩阵更快),二就是解决上面的问题,最终目标是,坏掉任何一个chunk(无论是local code chunk , data chunk, global code chunk),都可以拉取小于k块源数据块把丢失的数据恢复出来。

       3、改进LRC的方法(我称为C_LRC, C是completely)

       其实很简单,加一个数据块,让所有的global code chunk和这个数据块成为一个新的ec组即可。LRC所谓的分组,其实就是分成小的EC组,然后有全局的EC组来辅助。所以这个做法还是很简单的。具体实现看下面部分。(第三部分写的都是LRC,其实都是按照我修改后的LRC也就是C_LRC的例子)

 

三、LRC编码解码示例

LRC编码解码的例子:

 

图 1 编码矩阵的结构

1、符号的定义:

data_cnt: 指的是数据块的数目

local code for data: LRC分组的code块

local_data_group_cnt: data的分组的数目,如上图是2。

global code: 通过所有的数据块计算出来的code块

global_code_chunk_cnt:global code 块的个数

local code for global code: global code的local code,也就是这个localcode只和global code有直接的计算关系

 

2、编码

       (1)编码矩阵的构造

 

 

可以结合图1和符号定义部分理解编码矩阵的构造. 

 

定义

X:

 

Y:

Y就是新浪的LRC的编码矩阵,没有local code for global code。为了多一行作为local code for global code,我在新浪的LRC的encode矩阵左乘了一个矩阵X,X是(k + local_data_group_cnt + global_code_chunk_cnt + 1 ) * (k +local_data_group_cnt + global_code_chunk_cnt )的,其中上面的(k +local_data_group_cnt + global_code_chunk_cnt )*(k +local_data_group_cnt + global_code_chunk_cnt )是单位矩阵,下面多了一行,该行的构成是k +local_data_group_cnt 个0后面跟了global_code_chunk_cnt 个系数。我写的这些系数是范德蒙矩阵的第(1+global_code_chunk_cnt )行(行数下标从0开始)的前global_code_chunk_cnt 个数。实际实现的时候因为我用的intel ec库的cauchy 矩阵,所以选的是cauchy 矩阵的第(1+global_code_chunk_cnt )行(行数下标从0开始)的前global_code_chunk_cnt 个数。X*Y得到的矩阵就是C_LRC的编码矩阵。

 

(2)编码过程

  (2-1)

 

换种表示方法,结果一样,过程稍微不一样,这样表示有好处,后面具体说

  (2-2)

 

强调一点:

local code for data:

C0=D0+D1

C1=D2+D3

 

 

M:

M=X*Y。

注意到矩阵M的最后一行是与global code对应的编码矩阵的几行是线性相关的

(2) 解码过程

       (a)LRC起作用的时候:一个块丢掉的时候,具体分以下几种情况,分别解释decode的方法:

              (a1)丢掉一个data块,比如丢掉D2

              此时一个注意点,C0=D0+D1,也就是在global code没参与decode计算的时候,C0对于恢复D2D3起不到任何作用。

              对于丢掉D2的情况,恢复数据只需要数据块:D1 C1,其他数据都不需要。记source[i] ==1为第i个数据块在decode的时候用到

              Decode matrix的生成:
              (i)选取没有损坏的数据对应的行

              (ii)选取Source[i]== 1的code 以及丢掉的code。假设二者数目合起来为n_code。

              顺序按照(i) (ii)操作,直到构造出k*k的矩阵,其中k为数据块的个数,此处k=4。

              本例中的矩阵为:

 

 

记为Z1,

              (iii)求Z1的逆矩阵Z1-1,进而求出decode矩阵

逆矩阵:

 

 

 

       (a1-1)

       (a1-2)

decode Matrix就是:

式子(a1-1)中的[0 0 -1 1]这个矩阵

这样就求出来了丢失的数据D2

这里其实也可以看出来,求D2虽然用到了D0和D1的行,但是其实完全没有用到相应的数据。我写成式子a1-1的形式,就是为了说明这一点。式子a1-2的形式是为了按照EC解码的原理理解。

 

       (a2)丢失一个local code for data的情况,比如丢掉C0

              具体原理同(a1),所以此处简述推导过程:

恢复数据只需要数据块:D0 D1 ,

              生成decodematrix的过程:

              (i)选取数据没有损坏的k行生成k*k的矩阵Z

 

              (ii)求Z的逆矩阵

 

              (iii)生成逆矩阵解码:

                     decode matrix:

 

              解码过程:

 

 

 

 一样可以看出,虽然用到了D2D3的行,但是只是在求逆的时候用到,最后生成的decode matrix还是不会用到D2和D3的具体数据。

 

(a3)丢了一个global code

       之前看的新浪的LRC库,这种情况下是按EC搞了,也就是必须拉去至少k个块来恢复。

       改进的LRC,这种情况是要用num(globalcode)块数据来恢复。

       式子2-2的表示的好处应该可以看出来了,decode相当于针对下面这个矩阵来说的

 

 

       先说几点结论:

       (a3.1)矩阵的行列做交换不影响矩阵是否可逆

       (a3.2)如果globalcode对应的行或者local code for global code对应的行去掉,剩下的k*k的矩阵(对于上图而言k=8),是满秩的。这个还是很容易证明的,简单说说把,“如果global code对应的行”去掉,那么剩下的global code和local code for global code对应的行通过加减等操作肯定能把localcode for global code对应的行变成去掉的行,然后可以通过矩阵行列做交换,变成单位矩阵,也就是这个剩下的k*k的矩阵是满秩的,因此必然可逆。

       上面其实证明了LRC decode的时候,选择的k*k的矩阵是为什么是可逆的。(我对新浪的LRC做的补充就是让global code和data都是LRC的,也就是all chunk can be repaired locally . 这才是LRC(LocallyRepairable Code))。

       由上面就可以知道globalcode和local code for global code这些块坏掉一块的时候如何恢复。恢复方法和Localcode for data中,一个数据块或者Local code for data块丢掉是完全一样的。不再赘述。

       (PS:这种情况下其实我做得更加简单粗暴,我是直接用EC decode做了,也就是把global code 和local code for global code作为一个EC组,矩阵会更小点,EC会更快点吧,当然计算的代价差异很小的)

 

      (a4)丢了local code for global code。跟a3差不多,此处不赘述

(b)丢失多块(>1块)数据,丢失的数据不包含local code for global code。

此时和新浪的LRC是一样的,需要拉取k块数据。(其实是有一些代价可以衡量下选择策略的,比如一种情况:…..)

如上文所述,“矩阵M的最后一行是与global code对应的编码矩阵的几行是线性相关的”,因此当某些情况下,如果globalcode对应的行都选取的话,local code for global code选上是没用的。

举个例子丢2块数据,分别为D0和D1吧。

    (i)选取k*k矩阵

             

       (ii)decode的过程

              第一步解出所有的data,如下

 

 

 

 

              第二步是解出丢失的数据,也就是上面的式子两边同时乘以丢失的chunk对应的Ecode matrix的行,也就是D0和D1对应的encode matrix的行,即可恢复出来数据,如下

 

 

 

 

(c)丢失多块(>1块)数据,丢失的数据包含local code for global code。

      还是举个例子,假设丢了3块,分别为D1C2 C4,也就是一个data 一个global code,加上local code for global code丢了。

       (i)选取k*k矩阵:

 

 

 

       (ii)decode 的推导

              第一步是解出所有的Data,如下

 

 

  第二步是恢复出来数据,也就是上面的式子两边同时乘以丢失的chunk对应的Ecode matrix的行,也就是D1 C2 C4对应的encodematrix的行,即可恢复出来数据,过程如下,

         

你没看错,就是这么简单。

 

四、 C_LRC的效果分析

       1、C_LRC与新浪的LRC

LRC增加一个local code for globalcode和新浪的LRC的对比:

本质上,其实我的LRC也就是对global code做了冗余为1的EC。(当然LRC每个组的本质也就是对某些块做了冗余为1的EC),每多一个分组,也都是冗余chunk的数目加一,提高了decode速度。

       2、容错能力

还有一个值得细考虑的问题,增加localcode for global code对容错能力有没有提升?

先看新浪的LRC(没有local code for global code), 新浪的LRC的容错能力,有可能是3块有可能是4块

比如丢了D1 D0 C0 C2

 

剩下

 

显然不可逆。也就没法恢复。

如果丢失

剩下D1 D2 C0 C2

 

 

显然是可逆的,而且能计算出来。从这里可以看出来关键在于是不是某一个组的chunk都丢了,这会影响是否能恢复。我们参考这个发现,考虑local code for global code的情况。

 

如果没有local code for global code, 那么容错能力至少是n-k-local_group_cnt+1,对于本例应该是3,也就是最多丢三块,那么我们此处讨论如果丢了4块是不是能恢复。仍然分两种情况:

(1)丢失的4块里面包含local code for global code和global code中的一块,有一个数据组完全丢失。

       假设丢了D1D0 C0 C2,

       不考虑local codefor global code的话,此时剩下的4行为:

 

逆矩阵

 

于是发现还是可以解码的。

 

(2)丢失的数据里面包含local code for global code和global code中的2块

此时C4是可以用的,而C4是C3和C2的线性组合,因此可以作为一个Global code用。也就是两个global code 和1个local code for global code这一个组,如果丢了两个,剩下的可以作为一个globalcode用。这样的话,其他的数据丢失任意2个都是可以恢复的。丢失3个有可能不能恢复。比如

丢失了

D1 D0 C0 C2C3

这种情况下留下的k*k矩阵为

 

显然秩为3,不可逆(此时丢了5块)。

也有丢了5块可以恢复的例子:

比如丢了

D1 D0 C1 C2C3

剩下的矩阵为

 

是可逆的。

 

总结来看,就上面的例子,所有的块分了三组,分别为

group_1: D0 D1 C0

group_2: D2 D3 C1

group_3:C2 C3 C4

 

每个组可以提供的秩的个数为num(group_i) – 1,因为每个组有一个code块,该code块其实是另两个块的线性组合。

 

Local code for global code这个组比较特殊,相当于万能的,可以提供任意列的秩。而data的group只能提供某num(group_i) – 1列的秩,比如group_1只能是第一行和第二行,而group_2只能是第三行和第四行,group_3可以随意补充group_1和group_2的秩。(我这样描述不知道会不会被搞数学的拿砖拍死 T_T)。

因此判断是不是能恢复,只需要看这几个组留下的数据中,对应的encode matrix的行能不能凑出来一个秩为4的矩阵。

 

记函数s(g)为g这个group能提供的秩,

函数left(g)为g这个group剩下的数据块的个数

函数num(g)为g这个group的总的数据块的数目

那么每个组的s(g)的计算方法是(这个方法我自己理解总结的,如果有问题可以探讨):

 

if (left(g) == num(g)) //也就是这个组没有损失数据

       s(g) = num(g) – 1;

else

       s(g) = left(g);

 

然后对每个组s(g)求和,假设结果是sum, 如果sum >= k,那么是可逆的也就是可以恢复的。其中k为数据块的个数。所以对于LRC,用丢失了多少块来判断是不是能恢复是不合适的,还是要看具体丢了哪几块。另外也可以看出来,多了一块local code for global code块对所有数据的容错能力还是有提升的,而且是可以作为global code用的(当>=1个其他global code丢失的时候)。

 对于C_LRC,可以容忍的丢失的数据块的数目的上限t的范围是:    global_code_cnt +1 =< t <= m-k。 也就是如果<=global_code_cnt +1个数据块丢失,一定可以恢复出来,如果是丢失t块数据( global_code_cnt +1 =< t <= m-k) 要根据具体丢了哪几块数据来确定是不是能恢复

其中m是C_LRC编码矩阵的行数,k是所有的data chunk的数目

 

 

五、下一步工作

       (1)上面的一些说明都没有基于有限域,所以下一步可能还是要在有限域上简单证明下

       (2)分布式环境下Local怎么分组? 我目前想得是,同一个组在一台机器,同一个组的不同数据块在这台机器的不同的硬盘上。这样可以减小通信的代价。

  (3)LRC在解码的时候,少于k块可以,但是矩阵构造的时候还是按照k*k来构造的。这个事情需要再确认下用的intel ec库在用于LRC的时候有没有冗余计算,以及用的k*k矩阵,为什么少于k就可以恢复,这个此处只是道理讲了以及举了一些例子,还没想到更好的说明方式。

(4)facebook ms都有自己的做法。论文看了一部分,可以考虑下有没有可以借鉴和继续优化LRC算法的地方。

 

目前这个C_LRC测试得还不够,还在继续,因为上学原因,最近时间很少,周末加班+晚上赶了赶搞的,博客可能有点乱,因为是边写代码边写博客理思路的

 

以上是关于分布式系统下的纠删码 -- Locally Repairable Codes (LRC)的主要内容,如果未能解决你的问题,请参考以下文章

分布式系统下的纠删码技术 -- Erasure Code (EC)

minio对象存储

纯干货 | 深入剖析 HDFS 3.x 新特性-纠删码

纯干货 | 深入剖析 HDFS 3.x 新特性-纠删码

HDFS纠删码

如何选择纠删码编码引擎 | 纠删码技术详解(上)