Reed - Codes de Solomon en RAID 6

Il existe de nombreux articles sur Internet sur la récupération d'informations dans une matrice RAID-6 et sur la manière de créer votre propre implémentation d'une telle matrice. Mais la plupart de ces articles regorgent de formules mathématiques. Pour comprendre le vrai algorithme, vous devez passer beaucoup de temps.



Dans cet article, je vais essayer de montrer un exemple simple de mon propre système de correction d'erreur basé sur RAID-6. En particulier, envisagez une situation dans laquelle vous devez fournir une redondance du système afin qu'il puisse résister à la panne d'un ou deux disques.



En prime, des informations sur le fonctionnement de la correction d'erreur dans RAID-5, car RAID-6 est une version améliorée de RAID-5.



Aperçu



Disons que vous avez trois disques avec des données. Appelons-les D1, D2 et D3. Pour utiliser un système RAID-6, vous avez besoin de deux disques supplémentaires: PD et RS. Dans quelques minutes, je décrirai ce que représentent PD et RS. Donc, un total de cinq lecteurs: D1, D2, D3, PD et RS.







Donc la situation:



  • D1, D2 et D3 contiennent des donnĂ©es arbitraires . Disons des photos de chats.

  • Un disque spĂ©cial PD (Parity Drive, parfois P dans la documentation) contient des donnĂ©es zoomĂ©es automatiquement gĂ©nĂ©rĂ©es Ă  partir de D1, D2 et D3.

  • Deuxième disque spĂ©cial RS (codes Reed-Solomon, parfois appelĂ© Q) pour les mĂŞmes donnĂ©es que PD.


Voyons comment effectuer des opérations de base sur un tel tableau.



Comment fonctionne la récupération



Si vous calculez correctement PD et RS, vous pouvez survivre sans douleur à une panne de deux disques maximum. La procédure de récupération dépend des disques en question. Sept situations sont généralement considérées. Ci-dessous, ils sont triés de facile à complexe.



  1. Perte de PD (un seul disque).







    Un cas très simple. Le lecteur PD contient uniquement des données générées automatiquement, il peut donc être récupéré à l'aide des données d'origine sur les lecteurs D1, D2 et 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 .  â€” .


Dans les sections suivantes, nous explorerons ces cas plus en détail et verrons le code source (en Python) qui effectue la récupération de données réelle.



Gardez à l'esprit que les baies RAID-6 réelles n'allouent pas réellement un disque entier pour PD ou RS. Ces données sont réparties sur tous les disques. Différents contrôleurs utilisent différentes méthodes: asynchrone gauche ou synchrone droite, il peut y avoir un décalage par rapport aux données RAID, à la latence, etc. Laissons de côté la discussion sur pourquoi cela se produit et à quoi ressemblent les vraies bandes. RAID-6. Concentrons-nous spécifiquement sur les codes Reed-Solomon.



Données de test



Définissons les "données utilisateur". Pour plus de simplicité, définissons la taille de chaque "disque" sur 5 octets.



Disque Données ASCII Données en HEX
D1



première 0x66, 0x69, 0x72, 0x73, 0x74
D2



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



troisième 0x74, 0x68, 0x69, 0x72, 0x64


Examinons maintenant de plus près les scénarios mentionnés.



Situation 1. Perte du disque PD



Pour générer PD, seuls les disques de données utilisateur sont nécessaires. Dans notre cas, ce sont D1, D2 et D3. Le disque PD est simplement XORed de toutes les données utilisateur.



Pour générer l'offset 0 pour PD, tous les octets de l'offset 0 doivent être compressés sur tous les disques. Idem pour l'offset 1 et ainsi de suite:



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


Exemple:



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


Oui, c'est très simple. Faites ceci pour des disques entiers (dans notre cas, 5 octets) et obtenez un PD correctement généré:



Disque Données en HEX
PD



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


Ainsi, si seul PD Ă©choue, il est assez trivial de le restaurer Ă  partir de D1, D2 et D3.



Situation 2. Perte de l'un des magasins de données: D1, D2 ou D3



Au fait, c'est ainsi que fonctionne la correction des erreurs RAID-5. Si un seul disque de données utilisateur échoue, nous pouvons utiliser le disque PD pour recalculer les données utilisateur manquantes.



Disons que D2 est perdu. D1, D3, PD et RS sont restés en stock. Dans ce cas, ne touchez même pas RS. Seuls les lecteurs D1, D3 et PD sont nécessaires. Pour calculer les données manquantes, vous pouvez utiliser à nouveau la fonction XOR comme dans la situation précédente.



Pour récupérer les données utilisateur à partir du décalage 0, xorimez les octets des décalages zéro des disques de données utilisateur qui restent (D1 et D3) avec l'octet du décalage zéro PD. Répétez pour le décalage 1, et ainsi de suite:



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


Exemple:



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


Comme vous pouvez le voir, il est très facile de récupérer des données à partir d'un disque manquant. Peu importe le disque manquant: la fonction XOR fonctionne toujours.



Situation 3. Perte du disque RS



Maintenant, les codes de terrain Reed-Solomon et Galois entrent en jeu. Mais ne vous inquiétez pas, vous n'avez pas besoin d'être mathématicien pour les utiliser.



Lorsque nous perdons seulement le lecteur RS ou que nous créons un nouveau système comme RAID-6, il nous suffit de régénérer les codes. Pour ce faire, utilisez les tables gflog et gfilog avec un contenu immuable, ainsi que les données des lecteurs existants D1, D2 et D3.



La table gflog ressemble toujours Ă  ceci:



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.


La table gfilog est Ă©galement persistante:



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.


Il n'est pas nécessaire d'inclure ces tables dans le programme, vous pouvez utiliser l'algorithme de génération suivant au moment de l'exécution:



# 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)
      
      





Une fois les tables déclarées, certaines opérations doivent être définies. Nous travaillons maintenant dans un champ fini ( champ de Galois), donc les opérations arithmétiques de base ont une implémentation différente (bien que le sens soit quelque peu similaire). Vous devez redéfinir les opérations de base - addition, multiplication et division:



# 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])]
      
      





Puisque les fonctions d'assistance sont déclarées, essayons de générer les données du disque 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)
      
      





Après l'exécution du script recover_rs.py



, le disque RS contient les données suivantes:



Disque Données en HEX
RS



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


Pour le moment, les disques D1, D2 et D3 sont protégés par l'algorithme complet de correction d'erreur RAID-6, car nous avons correctement généré PD et RS.



Il est important de se rappeler que les données RS actuelles ne sont valables que pour D1, D2 et D3 dans cet ordre particulier . Ainsi, le RS pour D1, D2 et D3 sera différent de D3, D2 et D1, même si les données réelles sur les disques sont les mêmes. Il est important de s'en souvenir car lors de la restauration de données RAID-6, vous devez connaître la séquence de disques correcte dans la matrice. Heureusement, si la matrice est petite, vous pouvez forcer la génération des données RS pour trouver la séquence de disques correcte.



Situation 4. Perte de DP et de RS



C'est aussi une situation simple: nous exécutons d'abord le scénario n ° 1, puis le n ° 3. Je le



répète, dans ce cas, les données utilisateur ne sont pas affectées. Nous pouvons les utiliser pour créer un PD. Ensuite pour créer RS. Les deux cas ont déjà été décrits aux points 1 et 3.



Situation 5. Perte de RS et d'un disque de données



Et ici, ce n'est pas difficile. Nous avons perdu un disque de données, mais nous avons toujours un PD, nous pouvons donc exécuter le scénario # 2 pour récupérer le disque de données manquant. Utilisez ensuite tous les disques de données pour la régénération RS comme dans le scénario # 3. L'ensemble complet de disques est maintenant récupéré.



Situation 6. Perte de PD et d'un disque de données



L'approche générale consiste à récupérer d'abord le disque de données manquant en utilisant d'autres disques en combinaison avec RS, puis, une fois que tous les disques de données ont été récupérés, procéder à la régénération du PD (scénario n ° 2).



Dans cette situation, vous devez faire quelques calculs. Supposons qu'avec PD nous avons perdu le disque de données D2. Nous avons donc D1, D3 et RS en stock.



Grâce au disque RS, nous pouvons restaurer D2 en combinant D1, D3 et RS, comme ceci:



# 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)
      
      





Tout d'abord, vous devez générer une valeur partialRS



en ajoutant (gf_add) les valeurs de retour gf_mul



pour tous les octets de tous les disques valides avec la valeur RS au lieu du disque de données manquant (dans notre cas, D2).



Nous utilisons ensuite la valeur partialRS



pour régénérer les données D2 en divisant un par l'indice de disque mort ( gf_drive(2)



) et en multipliant le résultat par partialRS



. L'argument gf_drive(2)



indique l'index de notre disque mort. Si D1 Ă©chouait, nous utiliserions ici gf_drive(1)



.



Après avoir régénéré D2, restaurez tous les disques de données. Dans ce cas, nous effectuons une régénération PD comme dans le scénario n ° 1: dans le code ci-dessus, cela se fait en ajoutant (gf_add) les données de tous les disques. Si tu te souviensgf_add



Le champ Galois est une simple opération XOR, donc au lieu de xoring manuellement les octets de tous les disques de données, vous pouvez utiliser le gf_add



.



Situation 7. Perte de deux collecteurs de données



C'est le scénario le plus intéressant et le plus difficile. Supposons que les disques D2 et D3 sont en panne. Dans ce cas, vous devez d'une manière ou d'une autre utiliser les disques D1, PD et RS pour régénérer les disques manquants.



Il s'agit d'une approche différente des cas précédents. Une approche générale consiste à générer d'abord des données pour D2, puis à utiliser la même estimation que dans le scénario n ° 2 pour générer des données pour D3. Voici le code:



# 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)
      
      





Tout d'abord, vous devez ajouter tous les octets de tous les disques de données existants à générer partialPD



. Dans cet exemple, nous n'avons qu'un seul disque de données, donc le paramètre partialPD



sera simplement le contenu du disque D1. Mais les baies RAID-6 couvrent plusieurs disques. Par conséquent, si nous avons plus d'un disque de données, par exemple trois disques de données en direct, le calcul partialPD ressemblera à ceci:



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





Ensuite, nous avons besoin d'un paramètre partialRS



. Il peut être calculé en ajoutant des données à partir de disques existants comme suit:



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.
      
      





Dans notre cas, il n'y a qu'un seul périphérique de stockage de données (D1), donc le nôtre partialRS



est simple gf_mul(gf_drive(1), image1[i])



.



Ensuite, vous devez générer le paramètre g



en divisant un par la somme des indices de disque mort (D2 et D3).



Vient ensuite le paramètre xoredPD



; il est calculé en ajoutant le contenu de la PD au paramètre partialPD



précédemment calculé. Le paramètre suivant est xoredRS



calculé de la même manière, en l'ajoutant partialRS



au contenu RS.



Passons maintenant à la partie délicate. Vous pouvez calculer les données du premier disque cassé, c'est-à-dire du disque D2. Pour ce faire, multipliez l'indice du deuxième disque cassé (D3) par un paramètre xoredPD



et ajoutez un paramètre au résultat xoredRS



. Ensuite, après avoir multiplié le résultat par le paramètreg



, nous obtenons le contenu du disque D2.



Puisque nous venons de récupérer des données pour D2, ce cas n'est pas différent du scénario n ° 2 - perte d'un disque de données (D3). Tous les disques de données en direct (D1 et D2) doivent être ajoutés au PD pour créer le lecteur D3.



Terminé! Nous avons renvoyé un jeu complet de disques.



Épilogue



J'ai choisi Python pour démontrer que la correction des erreurs avec les codes Reed-Solomon ne nécessite pas beaucoup de programmation ou de puissance de traitement. Tout est très rapide et la mise en œuvre peut être assez compacte. Bien sûr, une implémentation plus efficace doit être écrite avec un traitement parallèle à l'esprit. Comme chaque octet est calculé indépendamment des autres, la parallélisation n'est pas difficile.



Il convient de noter que la méthode de récupération de données décrite ne doit pas être utilisée sur des disques physiques distincts. Les «disques» peuvent être considérés comme des «tampons» dans le processus de transmission de données sur un canal non fiable, et une telle correction d'erreur reste efficace. Cela nécessite des calculs plus intensifs qu'avec les codes de Hamming, mais deux flux tombés peuvent être soulevés. Il s'agit d'une fonction de résilience puissante.



Bien sûr, RAID-6 est loin d'être une nouvelle invention, et les codes Reed-Solomon sont encore plus anciens. Ils ont été utilisés dans la mission Voyager 2 , ce qui est plutôt cool.



Parmi les alternatives les plus modernes pour les codes Reed-Solomon, il y a les codes turbo  - j'espère que j'aurai l'occasion de les approfondir Ă©galement.



All Articles