Reed - códigos Solomon em RAID 6

Existem muitos artigos na Internet sobre recuperação de dados em uma matriz RAID-6 e como fazer sua própria implementação de tal matriz. Mas a maioria desses artigos está repleta de fórmulas matemáticas. Leva muito tempo para entender o algoritmo real.



Neste artigo, tentarei mostrar um exemplo simples do meu próprio sistema de correção de erros baseado em RAID-6. Em particular, considere uma situação em que você precisa fornecer redundância de sistema para que ele possa resistir à falha de uma ou duas unidades.



Como bônus, informações sobre como a correção de erros funciona no RAID-5, porque o RAID-6 é uma versão aprimorada do RAID-5.



visão global



Digamos que você tenha três discos com alguns dados. Vamos chamá-los de D1, D2 e ​​D3. Para usar um sistema RAID-6, você precisa de duas unidades adicionais: PD e RS. Em alguns minutos, descreverei o que PD e RS representam. Portanto, um total de cinco drives: D1, D2, D3, PD e RS.







Então a situação:



  • D1, D2 e ​​D3 contêm dados arbitrários . Digamos fotos de gatos.

  • Um disco especial PD (Parity Drive, às vezes P na documentação) contém dados ampliados gerados automaticamente a partir de D1, D2 e ​​D3.

  • Segundo disco especial RS (códigos Reed-Solomon, às vezes chamados de Q) para os mesmos dados que PD.


Vamos ver como realizar operações básicas em tal array.



Como funciona a recuperação



Se você calcular PD e RS corretamente, poderá sobreviver sem dor a uma falha de até dois discos. O procedimento de recuperação depende de quais unidades específicas falham. Normalmente são consideradas sete situações. Abaixo, eles são classificados de fáceis a complexos.



  1. Perda de PD (apenas um disco).







    Um caso muito simples. A unidade PD contém apenas dados gerados automaticamente, portanto, podem ser recuperados usando os dados originais nas unidades D1, D2 e ​​D3.



  2. : D1, D2 D3 ( ).







    , , , RAID-5: PD . PD, . RS ( ).



  3. RS ( ).







    1: , RS,  — .



  4. PD RS ( ).







    1 3. , PD, RS.



  5. RS ( ).







    , . PD, , № 2. , RS.



  6. PD ( ).







    . ( D3), PD, . RS (D1 D2), D3. PD. ,  — .



  7. ( ).







    . PD, RS .  — .


Nas próximas seções, exploraremos esses casos com mais detalhes e veremos o código-fonte (em Python) que realiza a recuperação de dados real.



Lembre-se de que os arrays RAID-6 reais não alocam uma unidade inteira para PD ou RS. Esses dados estão espalhados por todas as unidades. Controladores diferentes usam métodos diferentes: assíncrono esquerdo ou síncrono direito, pode haver uma mudança em relação aos dados RAID, latência, etc. Vamos deixar de lado a discussão sobre por que isso acontece e como são as listras reais. RAID-6. Vamos nos concentrar especificamente nos códigos Reed-Solomon.



Dados de teste



Vamos definir "dados do usuário". Para simplificar, vamos definir o tamanho de cada "disco" para 5 bytes.



Disco Dados ASCII Dados em HEX
D1



primeiro 0x66, 0x69, 0x72, 0x73, 0x74
D2



segundo 0x73, 0x65, 0x63, 0x6e, 0x64
D3



terceiro 0x74, 0x68, 0x69, 0x72, 0x64


Agora, vamos examinar mais de perto os cenários mencionados.



Situação 1. Perda de disco PD



Para gerar PD, apenas discos de dados do usuário são necessários. No nosso caso, são D1, D2 e ​​D3. O disco PD é simplesmente XORed de todos os dados do usuário.



Para gerar o deslocamento 0 para PD, todos os bytes do deslocamento 0 devem ser compactados em todos os discos. Idem para o deslocamento 1 e assim por diante:



PD [0] = D1 [0] xou D2 [0] xou D3 [0]
PD [1] = D1 [1] xou D2 [1] xou D3 [1]
PD [2] = D1 [2] xou D2 [2] xou D3 [2]
PD [3] = D1 [3] xou D2 [3] xou D3 [3]
PD [4] = D1 [4] xou D2 [4] xou D3 [4]


Exemplo:



PD [0] = 0x66 xou 0x73 xor 0x74 => 0x61
PD [1] = 0x69 xou 0x65 xor 0x63 => 0x64
PD [2] = 0x72 xor 0x63 xor 0x69 => 0x78
PD [3] = 0x73 xor 0x6e xor 0x72 => 0x6f
PD [4] = 0x74 xou 0x64 xor 0x64 => 0x74


Sim, é muito simples. Faça isso para discos inteiros (no nosso caso, 5 bytes) e você obterá um PD gerado corretamente:



Disco Dados em HEX
PD



0x61, 0x64, 0x78, 0x6f, 0x74


Assim, se apenas o PD falhar, é bastante trivial restaurá-lo de D1, D2 e ​​D3.



Situação 2. Perda de um dos armazenamentos de dados: D1, D2 ou D3



A propósito, é assim que funciona a correção de erros do RAID-5. Se apenas um disco de dados do usuário falhar, podemos usar o disco PD para recalcular os dados do usuário ausentes.



Digamos que D2 esteja perdido. D1, D3, PD e RS permaneceram em estoque. Nesse caso, nem toque em RS. Apenas as unidades D1, D3 e PD são necessárias. Para calcular os dados perdidos, você pode usar a função XOR novamente como na situação anterior.



Para recuperar os dados do usuário do deslocamento 0, xorim os bytes dos deslocamentos zero dos discos de dados do usuário que sobraram (D1 e D3) com o byte do deslocamento zero PD. Repita para o deslocamento 1 e assim por diante:



D2 [0] = D1 [0] xou D3 [0] xou PD [0]
D2 [1] = D1 [1] xou D3 [1] xou PD [1]
D2 [2] = D1 [2] xou D3 [2] xou PD [2]
D2 [3] = D1 [3] xou D3 [3] xou PD [3]
D2 [4] = D1 [4] xou D3 [4] xou PD [4]


Exemplo:



D2 [0] = 0x66 xou 0x74 xor 0x61 => 0x73 (s)
D2 [1] = 0x69 xor 0x63 xor 0x64 => 0x65 (e)
D2 [2] = 0x72 xou 0x69 xor 0x78 => 0x63 (c)
D2 [3] = 0x73 xor 0x72 xor 0x6f => 0x6e (n)
D2 [4] = 0x74 xou 0x64 xor 0x74 => 0x64 (d)


Como você pode ver, é muito fácil recuperar dados de um disco ausente. Não importa qual disco está faltando: a função XOR sempre funciona.



Situação 3. Perda de disco RS



Agora os códigos de campo de Reed-Solomon e Galois entram em ação. Mas não se preocupe, você não precisa ser um matemático para usá-los.



Quando apenas perdemos o drive RS ou criamos um novo sistema como o RAID-6, precisamos apenas regenerar os códigos. Para fazer isso, use as tabelas gflog e gfilog com conteúdo imutável, bem como dados das unidades existentes D1, D2 e ​​D3.



A tabela gflog sempre se parece com isto:



0x00, 0x00, 0x01, 0x19, 0x02, 0x32, 0x1a, 0xc6, 0x03, 0xdf, 0x33, 0xee, 0x1b, 0x68, 0xc7, 0x4b,
0x04, 0x64, 0xe0, 0x0e, 0x34, 0x8d, 0xef, 0x81, 0x1c, 0xc1, 0x69, 0xf8, 0xc8, 0x08, 0x4c, 0x71,
0x05, 0x8a, 0x65, 0x2f, 0xe1, 0x24, 0x0f, 0x21, 0x35, 0x93, 0x8e, 0xda, 0xf0, 0x12, 0x82, 0x45,
0x1d, 0xb5, 0xc2, 0x7d, 0x6a, 0x27, 0xf9, 0xb9, 0xc9, 0x9a, 0x09, 0x78, 0x4d, 0xe4, 0x72, 0xa6,
0x06, 0xbf, 0x8b, 0x62, 0x66, 0xdd, 0x30, 0xfd, 0xe2, 0x98, 0x25, 0xb3, 0x10, 0x91, 0x22, 0x88,
0x36, 0xd0, 0x94, 0xce, 0x8f, 0x96, 0xdb, 0xbd, 0xf1, 0xd2, 0x13, 0x5c, 0x83, 0x38, 0x46, 0x40,
0x1e, 0x42, 0xb6, 0xa3, 0xc3, 0x48, 0x7e, 0x6e, 0x6b, 0x3a, 0x28, 0x54, 0xfa, 0x85, 0xba, 0x3d,
0xca, 0x5e, 0x9b, 0x9f, 0x0a, 0x15, 0x79, 0x2b, 0x4e, 0xd4, 0xe5, 0xac, 0x73, 0xf3, 0xa7, 0x57,
0x07, 0x70, 0xc0, 0xf7, 0x8c, 0x80, 0x63, 0x0d, 0x67, 0x4a, 0xde, 0xed, 0x31, 0xc5, 0xfe, 0x18,
0xe3, 0xa5, 0x99, 0x77, 0x26, 0xb8, 0xb4, 0x7c, 0x11, 0x44, 0x92, 0xd9, 0x23, 0x20, 0x89, 0x2e,
0x37, 0x3f, 0xd1, 0x5b, 0x95, 0xbc, 0xcf, 0xcd, 0x90, 0x87, 0x97, 0xb2, 0xdc, 0xfc, 0xbe, 0x61,
0xf2, 0x56, 0xd3, 0xab, 0x14, 0x2a, 0x5d, 0x9e, 0x84, 0x3c, 0x39, 0x53, 0x47, 0x6d, 0x41, 0xa2,
0x1f, 0x2d, 0x43, 0xd8, 0xb7, 0x7b, 0xa4, 0x76, 0xc4, 0x17, 0x49, 0xec, 0x7f, 0x0c, 0x6f, 0xf6,
0x6c, 0xa1, 0x3b, 0x52, 0x29, 0x9d, 0x55, 0xaa, 0xfb, 0x60, 0x86, 0xb1, 0xbb, 0xcc, 0x3e, 0x5a,
0xcb, 0x59, 0x5f, 0xb0, 0x9c, 0xa9, 0xa0, 0x51, 0x0b, 0xf5, 0x16, 0xeb, 0x7a, 0x75, 0x2c, 0xd7,
0x4f, 0xae, 0xd5, 0xe9, 0xe6, 0xe7, 0xad, 0xe8, 0x74, 0xd6, 0xf4, 0xea, 0xa8, 0x50, 0x58, 0xaf.


A tabela gfilog também é persistente:



0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1d, 0x3a, 0x74, 0xe8, 0xcd, 0x87, 0x13, 0x26,
0x4c, 0x98, 0x2d, 0x5a, 0xb4, 0x75, 0xea, 0xc9, 0x8f, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0,
0x9d, 0x27, 0x4e, 0x9c, 0x25, 0x4a, 0x94, 0x35, 0x6a, 0xd4, 0xb5, 0x77, 0xee, 0xc1, 0x9f, 0x23,
0x46, 0x8c, 0x05, 0x0a, 0x14, 0x28, 0x50, 0xa0, 0x5d, 0xba, 0x69, 0xd2, 0xb9, 0x6f, 0xde, 0xa1,
0x5f, 0xbe, 0x61, 0xc2, 0x99, 0x2f, 0x5e, 0xbc, 0x65, 0xca, 0x89, 0x0f, 0x1e, 0x3c, 0x78, 0xf0,
0xfd, 0xe7, 0xd3, 0xbb, 0x6b, 0xd6, 0xb1, 0x7f, 0xfe, 0xe1, 0xdf, 0xa3, 0x5b, 0xb6, 0x71, 0xe2,
0xd9, 0xaf, 0x43, 0x86, 0x11, 0x22, 0x44, 0x88, 0x0d, 0x1a, 0x34, 0x68, 0xd0, 0xbd, 0x67, 0xce,
0x81, 0x1f, 0x3e, 0x7c, 0xf8, 0xed, 0xc7, 0x93, 0x3b, 0x76, 0xec, 0xc5, 0x97, 0x33, 0x66, 0xcc,
0x85, 0x17, 0x2e, 0x5c, 0xb8, 0x6d, 0xda, 0xa9, 0x4f, 0x9e, 0x21, 0x42, 0x84, 0x15, 0x2a, 0x54,
0xa8, 0x4d, 0x9a, 0x29, 0x52, 0xa4, 0x55, 0xaa, 0x49, 0x92, 0x39, 0x72, 0xe4, 0xd5, 0xb7, 0x73,
0xe6, 0xd1, 0xbf, 0x63, 0xc6, 0x91, 0x3f, 0x7e, 0xfc, 0xe5, 0xd7, 0xb3, 0x7b, 0xf6, 0xf1, 0xff,
0xe3, 0xdb, 0xab, 0x4b, 0x96, 0x31, 0x62, 0xc4, 0x95, 0x37, 0x6e, 0xdc, 0xa5, 0x57, 0xae, 0x41,
0x82, 0x19, 0x32, 0x64, 0xc8, 0x8d, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0, 0xdd, 0xa7, 0x53, 0xa6,
0x51, 0xa2, 0x59, 0xb2, 0x79, 0xf2, 0xf9, 0xef, 0xc3, 0x9b, 0x2b, 0x56, 0xac, 0x45, 0x8a, 0x09,
0x12, 0x24, 0x48, 0x90, 0x3d, 0x7a, 0xf4, 0xf5, 0xf7, 0xf3, 0xfb, 0xeb, 0xcb, 0x8b, 0x0b, 0x16,
0x2c, 0x58, 0xb0, 0x7d, 0xfa, 0xe9, 0xcf, 0x83, 0x1b, 0x36, 0x6c, 0xd8, 0xad, 0x47, 0x8e, 0x01.


Não é necessário incluir essas tabelas no programa, você pode usar o seguinte algoritmo de geração em tempo de execução:



# gflog_tables.py

def generate_tables():
    polynomial = 0x11d
    s = 8
    gf_elements = 1 << s

    gflog = gf_elements * [0]
    gfilog = gf_elements * [0]

    b = 1
    for i in range(0, gf_elements):
        gflog[b] = i & 255
        gfilog[i] = b & 255
        b <<= 1
        if b & gf_elements:
            b ^= polynomial

    gflog[1] = 0;
    return (gflog, gfilog)

def dump_table(caption, tab):
    item = 0
    print("--- {} ---".format(caption))
    for i in tab:
        print("0x{:02x}, ".format(i), end="")
        item += 1
        if item % 16 == 0:
            item = 0
            print()
    print("")

(gflog, gfilog) = generate_tables()

# Uncomment if you want to see the tables on the console:
#
# dump_table("gflog", gflog)
# dump_table("gfilog", gfilog)
      
      





Depois que as tabelas são declaradas, algumas operações precisam ser definidas. Agora estamos trabalhando em um campo finito ( campo de Galois), então as operações aritméticas básicas têm uma implementação diferente (embora o significado seja um tanto semelhante). Você precisa redefinir as operações básicas - adição, multiplicação e divisão:



# rs_functions.py

from gflog_tables import *

# Addition
def gf_add(*args):
    result = 0
    for arg in args:
        result ^= arg

    return result

# Indexing
# First drive is 1, second drive is 2, etc...
def gf_drive(index):
    global gfilog

    return gfilog[index - 1]

# Multiplication
def gf_mul(a, b):
    global gflog
    global gfilog

    if a == 0 or b == 0:
        return 0
    else:
        return gfilog[(gflog[a] + gflog[b]) % 255]

# Division helper
def sub_gf8(a, b):
    if a > b:
        return a - b
    else:
        return (255 - (0 - (a - b)))

# Division
def gf_div(a, b):
    global gfilog
    global gflog

    return gfilog[sub_gf8(gflog[a], gflog[b])]
      
      





Uma vez que as funções auxiliares são declaradas, vamos tentar gerar os dados do disco RS.



# case 3 -- recover_rs.py

from rs_functions import *

# Here are our drives, together with their data.
image1 = [ ord('f'), ord('i'), ord('r'), ord('s'), ord('t') ]
image2 = [ ord('s'), ord('e'), ord('c'), ord('n'), ord('d') ]
image3 = [ ord('t'), ord('h'), ord('i'), ord('r'), ord('d') ]

# This is a placeholder for our RS drive. It will be regenerated
# in the lines below.
imageRS = [0] * 5

# And this is our loop that generates the RS data using nothing more
# than the user data drives.
for i in range(0, 5):
    imageRS[i] = gf_add(gf_mul(gf_drive(1), image1[i]),
                        gf_mul(gf_drive(2), image2[i]),
                        gf_mul(gf_drive(3), image3[i]))

dump_table("imageRS", imageRS)
      
      





Depois de executar o script recover_rs.py



, o disco RS contém os seguintes dados:



Disco Dados em HEX
RS



0x4d, 0x1e, 0x0d, 0x7a, 0x31


No momento, as unidades D1, D2 e ​​D3 estão protegidas pelo algoritmo de correção de erros RAID-6 completo, uma vez que geramos PD e RS corretamente.



É importante lembrar que os dados RS atuais são válidos apenas para D1, D2 e ​​D3 nessa ordem específica . Portanto, o RS para D1, D2 e ​​D3 será diferente de D3, D2 e ​​D1, embora os dados reais nos discos sejam os mesmos. É importante lembrar disso porque, ao recuperar dados RAID-6, você precisa saber a sequência correta do disco dentro da matriz. Felizmente, se o array for pequeno, você pode forçar os dados RS a serem gerados para encontrar a sequência de disco correta.



Situação 4. Perda de PD e RS



Esta também é uma situação simples: primeiro executamos o cenário nº 1 e depois o nº 3.



Repito, neste caso os dados do usuário não são afetados. Podemos usá-los para criar um PD. Então, para criar RS. Ambos os casos já foram descritos nos pontos 1 e 3.



Situação 5. Perda de RS e um disco de dados



E aqui não é difícil. Perdemos um disco de dados, mas ainda temos um PD, portanto, podemos executar o cenário 2 para recuperar o disco de dados ausente. Em seguida, use todos os discos de dados para regeneração RS, como no cenário nº 3. O conjunto completo de discos agora está recuperado.



Situação 6. Perda de PD e um disco de dados



A abordagem geral é primeiro recuperar o disco de dados ausente usando outros discos em combinação com RS e, em seguida, depois que todos os discos de dados forem recuperados, continuar a regenerar o PD (cenário 2).



Nesta situação, você deve fazer alguns cálculos. Suponha que, junto com PD, perdemos o disco de dados D2. Portanto, temos D1, D3 e RS em estoque.



Graças ao disco RS, podemos restaurar D2 combinando D1, D3 e RS, assim:



# case 6 -- recover_d2_and_pd.py

from rs_functions import *

# We have these drives...
image1 = [ ord('f'), ord('i'), ord('r'), ord('s'), ord('t') ]
image3 = [ ord('t'), ord('h'), ord('i'), ord('r'), ord('d') ]
imageRS = [ 0x4d, 0x1e, 0x0d, 0x7a, 0x31 ]

# ...and these drives are dead
imagePD = [0] * 5
image2 = [0] * 5

for i in range(0, 5):
    partialRS = gf_add(gf_mul(gf_drive(1), image1[i]),
                       imageRS[i],  # Use RS drive instead of the dead drive.
                       gf_mul(gf_drive(3), image3[i]))

    # gf_drive(2) is our dead drive.
    div_result = gf_div(1, gf_drive(2))

    # This will generate the data from the dead D2 drive.
    image2[i] = gf_mul(div_result, partialRS)

    # This will generate the data from the dead PD drive.
    imagePD[i] = gf_add(image1[i], image2[i], image3[i])

dump_table("image2", image2)
dump_table("imagePD", imagePD)
      
      





Primeiro, você precisa gerar um valor partialRS



adicionando (gf_add) os valores de retorno gf_mul



para todos os bytes de todos os discos válidos junto com o valor RS em vez do disco de dados ausente (em nosso caso, D2).



Em seguida, usamos o valor partialRS



para gerar novamente os dados D2, dividindo um pelo índice de disco morto ( gf_drive(2)



) e multiplicando o resultado por partialRS



. O argumento gf_drive(2)



indica o índice do nosso disco morto. Se D1 falhasse, usaríamos aqui gf_drive(1)



.



Depois de regenerar D2, restaure todos os discos de dados. Neste caso, realizamos a regeneração PD como no cenário # 1: no código acima, isso é feito adicionando (gf_add) dados de todos os discos. Se você lembrargf_add



O campo Galois é uma operação XOR simples, portanto, em vez de xorar manualmente os bytes de todos os discos de dados, você pode usar o gf_add



.



Situação 7. Perda de dois coletores de dados



Este é o cenário mais interessante e difícil. Suponha que os discos D2 e ​​D3 estejam fora de serviço. Neste caso, você precisa usar de alguma forma os discos D1, PD e RS para regenerar os discos ausentes.



Esta é uma abordagem diferente dos casos anteriores. Uma abordagem geral é primeiro gerar dados para D2 e, em seguida, usar a mesma estimativa do cenário 2 para gerar dados para D3. Aqui está o código:



# case 7 -- recover_d2_and_d3.py

from rs_functions import *

# These drives are still alive.
image1 = [ ord('f'), ord('i'), ord('r'), ord('s'), ord('t') ]
imagePD = [ 0x61, 0x64, 0x78, 0x6f, 0x74 ]
imageRS = [ 0x4d, 0x1e, 0x0d, 0x7a, 0x31 ]

# These drives are dead, we can't read from them.
image2 = [0] * 5
image3 = [0] * 5

for i in range(0, 5):
    partialPD = gf_add(image1[i]) # add other drives if they exist
    partialRS = gf_add(gf_mul(gf_drive(1), image1[i])) # add other drives if they exist

    g = gf_div(1, gf_add(gf_drive(2), gf_drive(3)))
    xoredPD = gf_add(partialPD, imagePD[i])
    xoredRS = gf_add(partialRS, imageRS[i])
    mid = gf_add(gf_mul(gf_drive(3), xoredPD), xoredRS) # gf_drive(3) is the second drive we've lost

    # Regenerate data for D2.
    data = gf_mul(mid, g)
    image2[i] = data

    # Regenerate data for D3.
    image3[i] = gf_add(image1[i], image2[i], imagePD[i])

    # or:
    #
    # image3[i] = gf_add(data, xoredPD)

dump_table("image2", image2)
dump_table("image3", image3)
      
      





Primeiro, você precisa adicionar todos os bytes de todos os discos de dados existentes para gerar partialPD



. Neste exemplo, temos apenas um disco de dados, então o parâmetro partialPD



será simplesmente o conteúdo do disco D1. Mas as matrizes RAID-6 abrangem várias unidades. Portanto, se tivermos mais de um disco de dados, por exemplo, três discos de dados ativos, o cálculo parcial do PD será semelhante a este:



partialPD = gf_add(image1[i], image2[i], image3[i])
      
      





Em seguida, precisamos de um parâmetro partialRS



. Ele pode ser calculado adicionando dados de discos existentes da seguinte maneira:



partialRS = gf_add(A, B, C, ..., Z)

where A = gf_mul(gf_drive(1), image1[i])
      B = gf_mul(gf_drive(2), image2[i]) if we have drive 2
      C = gf_mul(gf_drive(3), image3[i]) if we have drive 3

etc.
      
      





No nosso caso, existe apenas um drive de dados (D1), então o nosso partialRS



é simples gf_mul(gf_drive(1), image1[i])



.



Então você precisa gerar o parâmetro g



dividindo um pela soma dos índices de disco morto (D2 e D3).



Em seguida, vem o parâmetro xoredPD



; é calculado adicionando o conteúdo do PD ao parâmetro partialPD



calculado anteriormente. O próximo parâmetro é xoredRS



calculado de forma semelhante, adicionando-o partialRS



ao conteúdo RS.



Agora para a parte mais complicada. Você pode calcular os dados do primeiro disco quebrado, ou seja, do disco D2. Para fazer isso, multiplique o índice do segundo disco quebrado (D3) por um parâmetro xoredPD



e adicione um parâmetro ao resultado xoredRS



. Então, depois de multiplicar o resultado pelo parâmetrog



, obtemos o conteúdo do disco D2.



Como acabamos de recuperar os dados do D2, este caso não é diferente do cenário 2 - perda de um disco de dados (D3). Para criar uma unidade D3, todas as unidades de dados dinâmicas (D1 e D2) devem ser adicionadas ao PD.



Feito! Devolvemos um conjunto completo de discos.



Epílogo



Escolhi Python para demonstrar que corrigir erros com códigos Reed-Solomon não requer muita programação ou poder de processamento. Tudo é muito rápido e a implementação pode ser bastante compacta. Obviamente, uma implementação mais eficiente deve ser escrita com o paralelismo em mente. Como cada byte é calculado independentemente dos outros, a paralelização não é difícil.



Deve-se observar que o método de recuperação de dados descrito não precisa ser usado em discos físicos separados. Os "discos" podem ser considerados "buffers" no processo de transmissão de dados por um canal não confiável, e essa correção de erro permanece eficaz. Requer cálculos mais intensivos do que com os códigos de Hamming, mas dois fluxos caídos podem ser gerados. Este é um recurso de resiliência poderoso.



É claro que o RAID-6 está longe de ser uma invenção nova e os códigos Reed-Solomon são ainda mais antigos. Eles foram usados ​​na missão Voyager 2 , o que é muito legal.



Entre as alternativas mais modernas para os códigos Reed-Solomon estão os códigos turbo  - espero ter a oportunidade de aprofundá-los também.



All Articles