ريد - أكواد سليمان في RAID 6

هناك العديد من المقالات على الإنترنت حول استعادة المعلومات في مصفوفة RAID-6 وكيفية تنفيذك الخاص لمثل هذه المصفوفة. لكن معظم هذه المقالات مكتظة بالصيغ الرياضية. يستغرق فهم الخوارزمية الحقيقية الكثير من الوقت.



سأحاول في هذه المقالة إظهار مثال بسيط لنظام تصحيح الأخطاء الخاص بي بناءً على RAID-6. على وجه الخصوص ، ضع في اعتبارك موقفًا تحتاج فيه إلى توفير تكرار للنظام بحيث يمكنه تحمل فشل محرك أو محركين.



كمكافأة ، معلومات حول كيفية عمل تصحيح الأخطاء في RAID-5 ، لأن RAID-6 هو نسخة محسنة من RAID-5.



نظرة عامة



لنفترض أن لديك ثلاثة أقراص بها بعض البيانات. دعنا نسميها D1 و D2 و D3. لاستخدام نظام RAID-6 ، تحتاج إلى محركي أقراص إضافيين: PD و RS. في غضون بضع دقائق ، سوف أصف ما يمثله PD و RS. إذن ، ما مجموعه خمسة محركات أقراص: D1 و D2 و D3 و PD و RS.







إذن الوضع:



  • تحتوي D1 و D2 و D3 على بيانات عشوائية . دعنا نقول صور القطط.

  • يحتوي القرص الخاص PD (Parity Drive ، أحيانًا P في الوثائق) على بيانات مكبرة يتم إنشاؤها تلقائيًا من D1 و D2 و D3.

  • القرص الثاني الخاص RS (رموز Reed-Solomon ، تسمى أحيانًا Q) لنفس البيانات مثل PD.


دعونا نرى كيفية إجراء العمليات الأساسية على مثل هذه المصفوفة.



كيف يعمل الاسترداد



إذا قمت بحساب PD و RS بشكل صحيح ، فيمكنك النجاة من فشل يصل إلى قرصين دون ألم. يعتمد إجراء الاسترداد على محركات الأقراص المعينة التي تفشل. عادة ما يتم النظر في سبع حالات. أدناه مرتبة من السهل إلى المعقد.



  1. فقدان PD (قرص واحد فقط).







    حالة بسيطة للغاية. يحتوي محرك PD على بيانات تم إنشاؤها تلقائيًا فقط ، لذا يمكن استعادتها باستخدام البيانات الأصلية الموجودة على محركات الأقراص D1 و D2 و 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 .  — .


في الأقسام التالية ، سوف نستكشف هذه الحالات بمزيد من التفصيل ونرى كود المصدر (في Python) الذي يقوم باستعادة البيانات الفعلية.



ضع في اعتبارك أن صفيفات RAID-6 الفعلية لا تخصص بالفعل محرك أقراص كامل لـ PD أو RS. تنتشر هذه البيانات عبر جميع محركات الأقراص. تستخدم وحدات التحكم المختلفة طرقًا مختلفة: غير متزامن أو متزامن يمينًا ، قد يكون هناك تحول فيما يتعلق ببيانات RAID ، والكمون ، وما إلى ذلك. دعنا نترك جانباً مناقشة سبب حدوث ذلك وكيف تبدو الخطوط الحقيقية RAID-6. دعونا نركز بشكل خاص على أكواد Reed-Solomon.



بيانات الاختبار



دعونا نحدد "بيانات المستخدم". للتبسيط ، دعنا نضبط حجم كل "قرص" على 5 بايت.



القرص بيانات ASCII البيانات في HEX
D1



أول 0x66 ، 0x69 ، 0x72 ، 0x73 ، 0x74
D2



ثانية 0x73 ، 0x65 ، 0x63 ، 0x6e ، 0x64
D3



الثالث 0x74 ، 0x68 ، 0x69 ، 0x72 ، 0x64


الآن دعونا نلقي نظرة فاحصة على السيناريوهات المذكورة.



الحالة 1. فقدان قرص PD



لإنشاء PD ، يلزم فقط أقراص بيانات المستخدم. في حالتنا ، هذه هي D1 و D2 و D3. قرص PD هو ببساطة XORed لجميع بيانات المستخدم.



لإنشاء الإزاحة 0 لـ PD ، يجب ضغط جميع البايتات من الإزاحة 0 عبر كافة الأقراص. كما سبق للإزاحة 1 وما إلى ذلك:



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]


مثال:



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


نعم ، الأمر بسيط للغاية. افعل هذا للأقراص بأكملها (في حالتنا 5 بايت) ، وستحصل على PD بشكل صحيح:



القرص البيانات في HEX
PD



0x61 ، 0x64 ، 0x78 ، 0x6f ، 0x74


وبالتالي ، إذا فشل PD فقط ، فمن التافه إلى حد ما استعادته من D1 و D2 و D3.



الحالة 2. فقدان أحد مخازن البيانات: D1 أو D2 أو D3



بالمناسبة ، هذه هي الطريقة التي يعمل بها إصلاح خطأ RAID-5. إذا فشل قرص بيانات مستخدم واحد فقط ، فيمكننا استخدام قرص PD لإعادة حساب بيانات المستخدم المفقودة.



لنفترض أن D2 ضاع. ظلت D1 و D3 و PD و RS في المخزون. في هذه الحالة ، لا تلمس RS. هناك حاجة إلى محركات الأقراص D1 و D3 و PD فقط. لحساب البيانات المفقودة ، يمكنك استخدام وظيفة XOR مرة أخرى كما في الموقف السابق.



لاستعادة بيانات المستخدم من الإزاحة 0 ، xorim البايت من الإزاحات الصفرية لأقراص بيانات المستخدم المتبقية (D1 و D3) مع البايت من الإزاحة صفر PD كرر للإزاحة 1 ، وهكذا:



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]


مثال:



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


كما ترى ، من السهل جدًا استرداد البيانات من قرص مفقود. لا يهم القرص المفقود: تعمل وظيفة XOR دائمًا.



الحالة 3. فقدان قرص RS



الآن يتم تشغيل رموز الحقول Reed-Solomon و Galois. لكن لا تقلق ، ليس عليك أن تكون عالم رياضيات لاستخدامها.



عندما نفقد محرك RS فقط أو ننشئ نظامًا جديدًا مثل RAID-6 ، نحتاج فقط إلى إعادة إنشاء الرموز. للقيام بذلك ، استخدم جداول gflog و gfilog ذات المحتوى غير القابل للتغيير ، وكذلك البيانات من محركات الأقراص الحالية D1 و D2 و D3.



يبدو جدول gflog دائمًا كما يلي:



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.


جدول gfilog ثابت أيضًا:



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.


ليس من الضروري تضمين هذه الجداول في البرنامج ، يمكنك استخدام خوارزمية التوليد التالية في وقت التشغيل:



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





بعد الإعلان عن الجداول ، يجب تحديد بعض العمليات. نحن الآن نعمل في مجال محدود ( حقل جالوا) ، وبالتالي فإن العمليات الحسابية الأساسية لها تطبيق مختلف (على الرغم من أن المعنى مشابه إلى حد ما). تحتاج إلى إعادة تعريف العمليات الأساسية - الجمع والضرب والقسمة:



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





منذ الإعلان عن وظائف المساعد ، دعنا نحاول إنشاء بيانات قرص 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)
      
      





بعد تشغيل البرنامج النصي recover_rs.py



، يحتوي قرص RS على البيانات التالية:



القرص البيانات في HEX
RS



0x4d ، 0x1e ، 0x0d ، 0x7a ، 0x31


في الوقت الحالي ، تتم حماية محركات الأقراص D1 و D2 و D3 بواسطة خوارزمية تصحيح أخطاء RAID-6 الكاملة ، نظرًا لأننا أنشأنا PD و RS بشكل صحيح.



من المهم أن تتذكر أن بيانات RS الحالية صالحة فقط لـ D1 و D2 و D3 بهذا الترتيب المعين . وبالتالي ، فإن RS لـ D1 و D2 و D3 ستكون مختلفة عن D3 و D2 و D1 ، حتى لو كانت البيانات الفعلية على محركات الأقراص هي نفسها. من المهم تذكر ذلك لأنه عند استرداد بيانات RAID-6 ، تحتاج إلى معرفة تسلسل القرص الصحيح داخل الصفيف. لحسن الحظ ، إذا كان الصفيف صغيرًا ، يمكنك فرض إنشاء بيانات RS للعثور على تسلسل القرص الصحيح.



الموقف 4. فقدان PD و RS



هذا أيضًا موقف بسيط: ننفذ أولاً السيناريو رقم 1 ، ثم # 3.



أكرر ، في هذه الحالة لا تتأثر بيانات المستخدم. يمكننا استخدامها لإنشاء PD. ثم لإنشاء RS. تم بالفعل وصف كلتا الحالتين في النقطتين 1 و 3.



الحالة 5. فقدان RS وقرص بيانات واحد



وهنا ليس من الصعب. لقد فقدنا قرص بيانات واحدًا ، ولكن لا يزال لدينا PD ، لذا يمكننا تشغيل السيناريو رقم 2 لاستعادة قرص البيانات المفقود. ثم استخدم جميع أقراص البيانات لتجديد RS كما في السيناريو رقم 3. يتم الآن استرداد المجموعة الكاملة من الأقراص.



الموقف 6. فقدان PD وقرص بيانات واحد



تتمثل الطريقة العامة في استرداد قرص البيانات المفقود أولاً باستخدام أقراص أخرى مع RS ، وبعد ذلك ، بعد استعادة جميع أقراص البيانات ، تابع إعادة إنشاء PD (السيناريو رقم 2).



في هذه الحالة ، عليك القيام ببعض الحسابات. افترض أنه مع PD فقدنا قرص البيانات D2. لذلك لدينا D1 و D3 و RS في المخزون.



بفضل قرص RS ، يمكننا استعادة D2 من خلال الجمع بين D1 و D3 و RS ، على النحو التالي:



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





أولاً ، تحتاج إلى إنشاء قيمة partialRS



عن طريق إضافة (gf_add) قيم الإرجاع gf_mul



لجميع وحدات البايت لجميع الأقراص الصالحة جنبًا إلى جنب مع قيمة RS بدلاً من قرص البيانات المفقود (في حالتنا ، D2).



ثم نستخدم القيمة partialRS



لتجديد بيانات D2 بقسمة واحد على مؤشر القرص الميت ( gf_drive(2)



) وضرب النتيجة في partialRS



. gf_drive(2)



تشير الوسيطة إلى فهرس القرص الميت. إذا فشلت D1 ، فسنستخدمها هنا gf_drive(1)



.



بعد إعادة إنشاء D2 ، قم باستعادة كافة أقراص البيانات. في هذه الحالة ، نقوم بإجراء تجديد PD كما في السيناريو رقم 1: في الكود أعلاه ، يتم ذلك عن طريق إضافة بيانات (gf_add) من جميع الأقراص. اذا تذكرتgf_add



يعد حقل Galois عملية XOR بسيطة ، لذا بدلاً من xoring يدويًا للبايتات من جميع أقراص البيانات ، يمكنك استخدام ملف gf_add



.



الموقف 7. فقدان اثنين من جامعي البيانات



هذا هو السيناريو الأكثر إثارة للاهتمام والأصعب. افترض أن الأقراص D2 و D3 معطلة. في هذه الحالة ، تحتاج إلى استخدام الأقراص D1 و PD و RS بطريقة أو بأخرى لإعادة إنشاء الأقراص المفقودة.



هذا نهج مختلف عن الحالات السابقة. يتمثل النهج العام في إنشاء البيانات أولاً لـ D2 ثم استخدام نفس التقدير كما في السيناريو رقم 2 لإنشاء بيانات لـ D3. ها هو الكود:



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





أولاً ، تحتاج إلى إضافة كافة البايت من كافة أقراص البيانات الموجودة لتوليدها partialPD



. في هذا المثال ، لدينا قرص بيانات واحد فقط ، لذا فإن المعلمة partialPD



ستكون ببساطة محتويات قرص D1. لكن صفيفات RAID-6 تمتد عبر محركات أقراص متعددة. لذلك ، إذا كان لدينا أكثر من قرص بيانات واحد ، على سبيل المثال ، ثلاثة أقراص بيانات حية ، فسيبدو حساب partPD كما يلي:



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





بعد ذلك نحتاج إلى معلمة partialRS



. يمكن حسابه عن طريق إضافة البيانات من الأقراص الموجودة على النحو التالي:



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.
      
      





في حالتنا ، لا يوجد سوى محرك بيانات واحد (D1) ، لذا فإن محركنا partialRS



بسيط gf_mul(gf_drive(1), image1[i])



.



ثم تحتاج إلى إنشاء المعلمة g



بقسمة واحد على مجموع مؤشرات القرص الميت (D2 و D3).



بعد ذلك تأتي المعلمة xoredPD



؛ يتم حسابها عن طريق إضافة محتويات PD إلى المعلمة partialPD



المحسوبة مسبقًا. يتم xoredRS



حساب المعلمة التالية بطريقة مماثلة ، عن طريق الإضافة partialRS



إلى محتوى RS.



الآن بالنسبة للجزء صعبة. يمكنك حساب البيانات من أول قرص مكسور ، أي من القرص D2. للقيام بذلك ، اضرب فهرس القرص المكسور الثاني (D3) بواسطة معلمة xoredPD



وأضف معلمة إلى النتيجة xoredRS



. ثم بعد ضرب النتيجة بالمعاملg



، نحصل على محتويات القرص D2.



نظرًا لأننا استعدنا للتو بيانات D2 ، فإن هذه الحالة لا تختلف عن السيناريو رقم 2 - فقدان قرص بيانات واحد (D3). لإنشاء محرك أقراص D3 ، يجب إضافة جميع محركات أقراص البيانات الحية (D1 و D2) إلى PD.



منجز! أعدنا مجموعة كاملة من الأقراص.



الخاتمة



اخترت Python لإثبات أن تصحيح الأخطاء باستخدام أكواد Reed-Solomon لا يتطلب الكثير من البرمجة أو قوة المعالجة. كل شيء سريع جدًا ويمكن أن يكون التنفيذ مضغوطًا تمامًا. بالطبع ، يجب كتابة تنفيذ أكثر كفاءة مع وضع التوازي في الاعتبار. نظرًا لأن كل بايت يتم حسابه بشكل مستقل عن البايتات الأخرى ، فإن الموازاة ليست صعبة.



وتجدر الإشارة إلى أن طريقة استعادة البيانات الموصوفة لا يجب استخدامها على أقراص مادية منفصلة. يمكن اعتبار "الأقراص" "مخازن مؤقتة" في عملية نقل البيانات عبر قناة غير موثوقة ، ويظل تصحيح الخطأ هذا فعالاً. هنا ، هناك حاجة إلى مزيد من العمليات الحسابية المكثفة مقارنة بأكواد هامنج ، ولكن يمكن رفع تيارين ساقطين. هذه ميزة مرونة قوية.



بالطبع ، RAID-6 بعيد عن اختراع جديد ، ورموز Reed-Solomon أقدم. تم استخدامها مرة أخرى في مهمة Voyager 2 ، وهو أمر رائع جدًا.



من بين البدائل الأكثر حداثة لرموز Reed-Solomon ، توجد رموز توربو  - آمل أن تتاح لي الفرصة للبحث فيها أيضًا.



All Articles