الأدلة التقنية

الفرق بين NAS وSAN، ومتى يكفيك قرص متصل مباشرة

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

الفرق بين NAS وSAN، ومتى يكفيك قرص متصل مباشرة

عندما تمتلئ أقراص الحاسوب بالصور والفيديو، فأول ما يفعله أغلبنا هو أن يشتري قرصاً خارجياً ويوصله بكابل USB، ثم يأتي اليوم الذي تريد فيه العائلة أن تفتح الصور نفسها من الهاتف والتلفاز، أو يريد سيرفر الهوم لاب أن يحفظ أقراص أجهزته الافتراضية على جهاز آخر، وهنا تظهر ثلاثة أسماء تتكرر في كل منتدى ودليل شراء: DAS وNAS وSAN. وفي مقال عتاد الهوم لاب قارنا جهاز NAS بالأجهزة الأخرى من جهة السعر والكهرباء، أما هنا فسوف نشرح كيف تصل الأجهزة إلى التخزين أصلاً، وما الذي يمر على الكابل، ولماذا يحميك ترتيب الأقراص من عطل قرص ولا يحميك من ملف تالف دون أن تشعر.

وسوف نناقش في هذا المقال ما يلي:

  • الفرق بين التخزين المتصل مباشرة DAS والتخزين المتصل بالشبكة NAS وشبكة التخزين SAN، ومتى يناسب كل منها.
  • الوصول بالملفات File Access والوصول بالكتل Block Access، وأين يعمل نظام الملفات في كل حالة.
  • بروتوكولات المشاركة SMB وNFS وiSCSI، ولماذا يجب أن يختفي SMB1 من شبكتك.
  • مستويات RAID بالحساب، ولماذا لا تعد RAID نسخة احتياطية، وما الذي تقوله أوراق مواصفات الأقراص فعلاً عن أخطاء القراءة أثناء إعادة البناء.
  • أفكار ZFS الأساسية: ال Pool وال vdev والنسخ عند الكتابة Copy-on-Write وال Checksums وال Scrub وال Snapshots.
  • حساب سرعة الشبكة 1GbE و2.5GbE و10GbE مقابل سرعة القرص.
  • تجربة عملية: سيرفر Samba وسيرفر NFS في Containers وكلاينت يربطهما، ثم تجربة نفسد فيها نسخة من البيانات عمداً ونرى من يكتشفها.

ثلاث طرق لربط الأقراص بالأجهزة

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

ثلاث لوحات متجاورة: في اليمين DAS وفيها سيرفر واحد متصل بصندوق أقراص بكابل SATA أو SAS أو USB، وما يمر على الكابل كتل ونظام الملفات على السيرفر، وفي الوسط NAS وفيها حاسوب محمول وحاسوب مكتبي وتلفاز متصلة بـ Switch ثم بجهاز NAS عبر SMB وNFS، وما يمر ملفات ونظام الملفات على جهاز NAS، وفي اليسار SAN وفيها ثلاثة سيرفرات متصلة بـ Switch ثم بمصفوفة تخزين عبر Fibre Channel أو iSCSI، وما يمر كتل ونظام الملفات على كل سيرفر
DAS وNAS وSAN: ما يمر على الكابل، وأين يعمل نظام الملفات

التخزين المتصل مباشرة DAS

التخزين المتصل مباشرة Direct Attached Storage واختصاراً DAS هو قرص أو صندوق أقراص Enclosure متصل بجهاز واحد بكابل مباشر، مثل SATA أو SAS أو USB أو Thunderbolt، فيراه نظام التشغيل قرصاً محلياً عادياً، ويضع عليه نظام الملفات الذي يريده. والقرص الخارجي على حاسوبك هو DAS، والأقراص داخل السيرفر نفسه هي DAS أيضاً، وكذلك صندوق الأقراص JBOD الذي يتصل بالسيرفر بكابل SAS.

ونقطة قوته أنه الأبسط والأسرع والأرخص، فلا توجد شبكة في الطريق ولا بروتوكول إضافي، ونقطة ضعفه أن الأقراص ملك جهاز واحد، فإذا أراد جهاز آخر أن يقرأ ملفاً منها فلا بد أن يشاركه الجهاز الأول عبر الشبكة، وعندها تكون قد بنيت NAS بنفسك دون أن تقصد.

التخزين المتصل بالشبكة NAS

التخزين المتصل بالشبكة Network Attached Storage واختصاراً NAS هو جهاز (أو سيرفر) عليه أقراص ونظام ملفات، ويقدم الملفات للأجهزة الأخرى عبر شبكة IP العادية ببروتوكول مثل SMB أو NFS. والمهم هنا أن الأجهزة تطلب الملف باسمه ومساره، وجهاز NAS هو الذي يعرف أين تقع كتل هذا الملف على أقراصه، وهو الذي يطبق الصلاحيات Permissions والأقفال Locks، لذلك يستطيع الحاسوب والهاتف والتلفاز أن يفتحوا المجلد نفسه في الوقت نفسه دون أن يفسد أحدهم عمل الآخر.

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

شبكة التخزين SAN

شبكة التخزين Storage Area Network واختصاراً SAN هي شبكة مخصصة تصل السيرفرات بمصفوفات تخزين Storage Arrays، وتقدم لكل سيرفر قرصاً منطقياً يسمى LUN، فيراه السيرفر قرصاً محلياً تماماً كأنه DAS، ويضع عليه نظام ملفاته بنفسه. والشبكة نفسها قد تكون Fibre Channel بمحولات Switches وكروت خاصة، وهذا هو الشكل التقليدي في مراكز البيانات، والصورة التالية لمحول Fibre Channel من فئة Director:

محول Fibre Channel كبير من فئة Director مثبت في خزانة، فيه بطاقات منافذ عمودية كثيرة ومئات من كابلات الألياف الضوئية بلون أزرق فاتح متصلة بالمنافذ ومرتبة في حزم
محول Fibre Channel من فئة Director فيه 8 بطاقات و48 منفذاً في كل بطاقة. الصورة: Scottkipp، بترخيص CC BY-SA 4.0، المصدر: Wikimedia Commons (تم تحويلها إلى WebP).

وقد تكون الشبكة Ethernet عادية يمر عليها بروتوكول iSCSI الذي ينقل أوامر SCSI داخل TCP كما يعرفه RFC 7143، وهذا ما تجده في أغلب أجهزة NAS المنزلية التي تقدم خيار iSCSI Target بجانب مشاركة الملفات. أما المصفوفة نفسها فهي جهاز مليء بالأقراص ووحدات التحكم، مثل المصفوفة في الصورة التالية:

خزانة سوداء فيها مصفوفة تخزين EMC Clariion CX500، في أعلاها صف من خمسة عشر قرصاً في أدراج قابلة للسحب، وتحتها عدة وحدات بواجهات رمادية منحنية
مصفوفة تخزين EMC Clariion CX500 من النوع الذي يقدم LUNs للسيرفرات عبر SAN. الصورة: Michael Moll، بترخيص CC BY 2.5، المصدر: Wikimedia Commons (تم تحويلها إلى WebP).

وقد يتساءل البعض: إذا كان iSCSI يعمل على Ethernet العادية، فهل جهاز NAS الذي يقدم iSCSI أصبح SAN؟ والإجابة أن الاسم يصف طريقة الوصول أكثر مما يصف الجهاز، فعندما يقدم الجهاز مجلداً عبر SMB فهو يعمل كـ NAS، وعندما يقدم LUN عبر iSCSI فهو يعمل كـ SAN، وكثير من الأجهزة اليوم تفعل الاثنين معاً.

الوصول بالملفات أم بالكتل؟

شرحنا الفرق بين تخزين الكتل وتخزين الملفات في مقال أنواع التخزين، والذي يهمنا هنا هو ما يعنيه ذلك على الشبكة، والصورة التالية تبين طلباً حقيقياً في كل حالة:

صفان: في الأعلى الوصول بالملفات إلى NAS، حيث يرسل الكلاينت طلب OPEN لمسار ملف وREAD من موضع معين مع اسم المستخدم، وفي جهاز NAS طبقات نظام الملفات والصلاحيات والأقفال ثم الأقراص، وفي الأسفل الوصول بالكتل إلى SAN، حيث يرسل السيرفر الذي يعمل عليه ext4 طلبات READ وWRITE بأرقام كتل LBA داخل LUN، والمصفوفة لا ترى إلا كتلاً مرقمة، وتحتها تحذير أحمر أن ربط LUN واحد بسيرفرين بنظام ext4 يجعل كلاً منهما يكتب فوق الآخر فيتلف
في NAS يرسل الجهاز اسم الملف، وفي SAN يرسل رقم الكتلة ويبقى نظام الملفات على السيرفر

في الصورة أعلاه لاحظ التالي:

  • في الوصول بالملفات يعرف جهاز NAS أن المستخدم sara فتح الملف img-05.jpg، لذلك يستطيع أن يمنع غيرها، وأن يقفل الملف إذا فتحه برنامجان، وأن يعرض لك المساحة المستخدمة لكل مجلد.
  • في الوصول بالكتل لا تعرف المصفوفة شيئاً عن الملفات، فهي تقرأ الكتلة رقم 4182 وتكتب الكتلة رقم 9906 لأن السيرفر طلب ذلك، ونظام الملفات ext4 أو XFS يعمل على السيرفر نفسه، ولهذا يكون أداء iSCSI أقرب إلى القرص المحلي في قواعد البيانات وأقراص الأجهزة الافتراضية.
  • ولهذا السبب نفسه لا تقم بربط LUN واحد بسيرفرين يكتبان عليه بنظام ملفات عادي مثل ext4، والسبب أن كل سيرفر يظن أنه وحده على القرص ويحتفظ بنسخته من خريطة الكتل في الذاكرة، فيكتب كل منهما فوق ما كتبه الآخر ويتلف نظام الملفات. والاستثناء هو أنظمة الملفات العنقودية Cluster File Systems المصممة لذلك، أو أن يكون الربط الثاني للقراءة فقط وبعلمك.

بروتوكولات المشاركة: SMB وNFS وiSCSI

قبل أن ندخل في كل بروتوكول، الصورة التالية تبين كم منفذاً يحتاج كل واحد منها، وهذا مهم عندما تضع جدار حماية Firewall بين شبكة الأجهزة وشبكة التخزين كما شرحنا في تقسيم الشبكة:

أربعة صفوف للبروتوكولات أمام جدار ناري: SMB 3 على المنفذ TCP 445 فقط، وNFSv3 يحتاج rpcbind على 111 وnfsd على 2049 وثلاثة منافذ عشوائية لـ mountd وnlockmgr وstatd هي 47113 و40441 و39959 في تجربتنا، وNFSv4 على المنفذ 2049 فقط، وiSCSI على المنفذ 3260
منفذ واحد لكل من SMB 3 وNFSv4 وiSCSI، وخمسة منافذ لـ NFSv3 ثلاثة منها عشوائية

SMB: مشاركة الملفات التي يعرفها Windows

بروتوكول SMB هو ما يستخدمه Windows عندما تفتح مجلداً على الشبكة بمسار مثل \\nas\photos، وتدعمه أنظمة macOS وLinux أيضاً، وعلى Linux تقدمه حزمة Samba. ويتفق الكلاينت والسيرفر في بداية الاتصال على أعلى نسخة Dialect يدعمانها معاً، والجدول التالي من توثيق Microsoft:

النسخةWindows للأجهزةWindows Server
SMB 3.1.1Windows 10 الإصدار 1607 وما بعدهWindows Server 2016 وما بعده
SMB 3.02Windows 8.1Windows Server 2012 R2
SMB 3.0Windows 8Windows Server 2012

والنسخة 3 هي التي أضافت التشفير Encryption داخل البروتوكول نفسه، وهذا ما سوف تراه في التجربة عندما يظهر AES-128-GCM في حالة الاتصال. أما النسخة الأولى SMB1 فقصتها مختلفة، فبحسب صفحة Microsoft عن SMBv1 فقد أعلنت الشركة إيقافه Deprecated في 2014، ولم يعد يثبت افتراضياً منذ Windows 10 الإصدار 1709، وWindows 11 لا يحتوي عليه لا كسيرفر ولا ككلاينت بعد التثبيت الجديد، والصفحة نفسها تقول بوضوح إن الشركة توصي بعدم إعادة تثبيته لأن فيه مشكلات أمنية معروفة مع برامج الفدية Ransomware.

📌
في 14 مارس 2017 نشرت Microsoft النشرة الأمنية MS17-010 بتصنيف حرج Critical، لثغرات في سيرفر SMBv1 تسمح لمخترق غير مسجل الدخول بتنفيذ كود على الجهاز بحزمة واحدة مصممة لذلك. وبعد شهرين، في مايو 2017، انتشر برنامج الفدية WannaCrypt بين الأجهزة التي لم تثبت التحديث، وكتبت Microsoft في إرشاداتها للعملاء أن الهجمات تستغل الثغرة التي أصلحها تحديث مارس، ونصحت بحجب البروتوكولات القديمة في الشبكة. والدرس لمن يملك NAS قديماً: إذا كان جهازك لا يتكلم إلا SMB1 فهذا جهاز يجب أن يحدث أو يستبدل، وليس سبباً لإعادة تفعيل SMB1 على حواسيب البيت.

وفي Samba نفسه أصبح SMB1 معطلاً افتراضياً منذ الإصدار 4.11، فبحسب ملاحظات الإصدار تغيرت القيمة الافتراضية لكل من client min protocol وserver min protocol إلى SMB2_02، وفي التجربة سوف نرفع الحد الأدنى إلى SMB3 ونرى ما يحدث عندما يحاول كلاينت قديم أن يتصل.

NFS: مشاركة الملفات بين أجهزة Linux

بروتوكول NFS هو الطريقة المعتادة لمشاركة مجلد بين سيرفرات Linux، ونسختاه المستخدمتان اليوم مختلفتان أكثر مما يوحي به الرقم:

  • NFSv3: يعرفه RFC 1813 بأنه يفترض سيرفراً بلا حالة Stateless، أي أن السيرفر لا يتذكر من فتح أي ملف، لذلك تحتاج الأقفال إلى خدمة منفصلة اسمها NLM، وتحتاج معرفة المجلدات المشتركة إلى خدمة mountd، ويحتاج الكلاينت إلى rpcbind ليعرف منافذ هذه الخدمات، وهذا ما يجعل عدد المنافذ في الصورة السابقة خمسة.
  • NFSv4: يقول RFC 7530 إنه، بخلاف النسخ السابقة، يدمج الأقفال وبروتوكول MOUNT داخله، ويحتفظ السيرفر بحالة الأقفال بنظام الإيجار Lease، والمنفذ المسجل له هو 2049 فلا يحتاج الكلاينت إلى rpcbind، ويضيف إطار الأمان RPCSEC_GSS الذي يسمح باستخدام Kerberos. والنسخة 4.1 في RFC 8881 و4.2 في RFC 7862 بنتا عليه.

ولاحظ أن NFS في إعداده الافتراضي sec=sys يثق برقم المستخدم UID الذي يرسله الكلاينت، فإذا قال الكلاينت إنه المستخدم 1000 فالسيرفر يصدقه، لذلك حدد في ملف /etc/exports الشبكة المسموح لها بدقة، ولا تفتح NFS لشبكة لا تثق بكل جهاز فيها.

iSCSI: قرص عبر الشبكة

بروتوكول iSCSI ينقل أوامر SCSI داخل TCP، والمنفذ الافتراضي له بحسب RFC 7143 هو 3260، وطرفاه هما الهدف Target الذي يقدم ال LUN، والبادئ Initiator الذي يربطه ويراه قرصاً. ويستخدم عادة لأقراص الأجهزة الافتراضية في Proxmox وغيره، ولقواعد البيانات التي تريد قرصاً وليس مجلداً مشتركاً.

أي بروتوكول تستخدم؟

الحالةالبروتوكولوالسبب
مجلد مشترك لأجهزة Windows وmacOS والهواتفSMB 3كل الأنظمة تدعمه، وفيه مستخدمون وكلمات مرور وتشفير
مجلد مشترك بين سيرفرات Linux أو ContainersNFSv4منفذ واحد، وأقفال داخل البروتوكول، وأداء جيد على Linux
أجهزة قديمة لا تدعم إلا NFSv3NFSv3مع تثبيت منافذ mountd وNLM وstatd إذا كان بينهما جدار ناري
قرص لجهاز افتراضي أو قاعدة بياناتiSCSIقرص كامل لسيرفر واحد، ونظام الملفات عليه
جهاز لا يدعم إلا SMB1لا شيءحدث الجهاز أو استبدله

RAID بالحساب قبل الشراء

المصفوفة RAID تجمع عدة أقراص في وحدة واحدة، إما لتكون أسرع، أو لتبقى البيانات متاحة إذا تعطل قرص، والفكرة التي تتكرر في أغلب المستويات هي التماثل Parity: قيمة تحسب من الكتل في الصف نفسه، فإذا ضاعت كتلة واحدة أعيد حسابها من الباقي. والصورة التالية تبين أشهر المستويات بأربعة أقراص بحجم 8 تيرابايت:

أربع بطاقات لأربعة أقراص بحجم 8 تيرابايت: RAID 0 يوزع البيانات على الأقراص الأربعة فيعطي 32 تيرابايت ولا يتحمل تعطل أي قرص، وRAID 10 مرآتان بقرصين فيعطي 16 تيرابايت ويتحمل قرصاً واحداً وأحياناً قرصين إذا كانا في مرآتين مختلفتين، وRAID 5 بتماثل واحد موزع يعطي 24 تيرابايت ويتحمل قرصاً واحداً، وRAID 6 بتماثلين يعطي 16 تيرابايت ويتحمل أي قرصين، وتحت كل اسم الاسم المقابل في ZFS: stripe وmirror وraidz1 وraidz2
المساحة المتاحة وعدد الأقراص التي يمكن أن تتعطل لكل مستوى بأربعة أقراص 8 تيرابايت

والحساب نفسه موثق في صفحة مفاهيم ال Pool في OpenZFS: المرآة Mirror من N أقراص بحجم X تحفظ X بايت وتتحمل تعطل N-1 قرصاً، ومجموعة raidz من N أقراص بحجم X وفيها P أقراص للتماثل تحفظ تقريباً (N-P)×X وتتحمل تعطل P قرصاً. ولنأخذ مثالاً بخمسة أقراص 8 تيرابايت في raidz2: (5 − 2) × 8 = 24 تيرابايت، ويمكن أن يتعطل أي قرصين. ولاحظ أن هذه أرقام المصنع بالتيرابايت العشري، وأن نظام الملفات يحجز جزءاً لنفسه، لذلك سوف ترى رقماً أقل في الواجهة.

وهنا يأتي الخطأ الذي يكرره كل مبتدئ تقريباً، وهو أن يعتبر RAID نسخة احتياطية. وRAID لا يعيد لك ملفاً حذفته، ولا ملفاً شفره برنامج فدية، والسبب أن الحذف والتشفير عمليات كتابة صحيحة من وجهة نظر المصفوفة، فتنفذها على كل الأقراص في اللحظة نفسها، وكذلك الحريق أو سرقة الجهاز يأخذان الأقراص كلها معاً. لذلك RAID يبقي الخدمة تعمل عند عطل قرص، والنسخة الاحتياطية المنفصلة هي التي تعيد البيانات، كما شرحنا في النسخ الاحتياطي بقاعدة 3-2-1.

إعادة البناء وأخطاء القراءة: ما الذي تقوله الأرقام فعلاً؟

عندما يتعطل قرص في RAID 5 وتضع مكانه قرصاً جديداً، تبدأ عملية إعادة البناء Rebuild (وتسمى في ZFS ال Resilver)، وفيها تقرأ المصفوفة كل الأقراص الباقية من أولها إلى آخرها لتحسب محتوى القرص الجديد. وفي هذه الساعات لا يوجد في RAID 5 أي هامش، فإذا فشلت قراءة كتلة من قرص آخر فلا توجد نسخة ثالثة تعيد حسابها منها.

وهنا تنتشر في المنتديات أرقام مخيفة عن احتمال فشل إعادة البناء، والأفضل أن نبدأ من المصدر نفسه. ف ورقة مواصفات WD Red Plus المنشورة في مارس 2025 تذكر في بند Non-recoverable errors per bits read القيمة «أقل من 1 في 1014» لكل السعات، بينما تذكر ورقة Ultrastar DC HC560 المخصص لمراكز البيانات القيمة 1 في 1015. والحساب البسيط يقول إن 1014 بت تساوي 12.5 تيرابايت، وإن إعادة بناء RAID 5 من أربعة أقراص 8 تيرابايت تقرأ 24 تيرابايت، ثم يستنتج أن الفشل شبه مؤكد.

ولماذا لا يصح هذا الاستنتاج كما هو؟ والسبب أن الرقم في الورقة حد أعلى تلتزم به الشركة («أقل من»)، وليس معدلاً مقاساً لما يحدث في الأقراص فعلاً، ولم نجد شركة تنشر المعدل المقاس، لذلك لا نستطيع أن نعطيك احتمالاً دقيقاً، ولن نخترع رقماً. والذي نستطيع قوله بثقة ثلاثة أشياء:

  • كلما كبرت الأقراص طالت إعادة البناء وزادت البيانات التي يجب أن تقرأ دون خطأ، لذلك مع الأقراص الكبيرة اختر تماثلاً مزدوجاً مثل RAID 6 أو raidz2، أو مرايا Mirrors، حتى يبقى هامش أثناء إعادة البناء.
  • الفحص الدوري Scrub يقرأ كل الأقراص بانتظام، فيكتشف الكتل الضعيفة ويصلحها من التماثل وأنت ما زلت تملك الهامش، بدلاً من أن تكتشفها أثناء إعادة البناء.
  • في ZFS لا يعني خطأ القراءة غير القابل للإصلاح ضياع ال Pool كله، فالأمر zpool status -v بحسب صفحة الدليل يعرض قائمة الملفات التي فيها أخطاء، فتستعيد تلك الملفات وحدها من النسخة الاحتياطية.

أفكار ZFS الأساسية

نظام ZFS ليس نظام ملفات فقط، وإنما يجمع إدارة الأقراص و RAID ونظام الملفات في طبقة واحدة، وهذا ما يجعله يعرف عن بياناته ما لا تعرفه مصفوفة RAID العادية. وأهم أفكاره كما في توثيق OpenZFS:

  • مجمع التخزين Pool وال vdev: ال Pool هو المساحة التي تنشئ فيها أنظمة الملفات Datasets، ويتكون من جهاز افتراضي vdev أو أكثر، وكل vdev إما قرص واحد أو Mirror أو raidz1/2/3. والحماية على مستوى ال vdev، فإذا ضاع vdev واحد ضاع ال Pool كله، لذلك لا تضف قرصاً منفرداً إلى Pool فيه raidz2.
  • النسخ عند الكتابة Copy-on-Write: لا يكتب ZFS فوق الكتلة القديمة، وإنما يكتب النسخة الجديدة في مكان فارغ ثم يغير المؤشر إليها، فإذا انقطعت الكهرباء في منتصف الكتابة بقيت النسخة القديمة سليمة.
  • مجموع التحقق Checksum: بحسب صفحة ال Checksums يحسب ZFS مجموع تحقق لكل كتلة ويحفظه في المؤشر إليها، فيكتشف التلف عند القراءة، ويصلح الكتلة تلقائياً إذا كان في ال Pool تكرار مثل Mirror أو raidz.
  • الفحص الدوري Scrub: بحسب صفحة zpool-scrub يفحص كل البيانات ليكتشف التلف الصامت، بخلاف إعادة البناء التي تفحص فقط ما يعرف ZFS أنه ناقص.
  • اللقطات Snapshots: بحسب صفحة المفاهيم ال Snapshot نسخة للقراءة فقط تنشأ بسرعة كبيرة ولا تستهلك في البداية أي مساحة إضافية، وهي ممتازة للتراجع عن حذف خاطئ، ولكنها على الأقراص نفسها، فلا تغني عن النسخة الاحتياطية.

وقد يتساءل البعض: هل يحتاج ZFS ذاكرة ECC؟ والأسئلة الشائعة في OpenZFS تقول إنها ليست شرطاً ولكنها موصى بها بقوة، والسبب أن بتاً ينقلب في الذاكرة قبل الكتابة سوف يكتب إلى القرص بمجموع تحقق صحيح لبيانات خاطئة، وهذا ينطبق على أي نظام ملفات آخر، وقد شرحنا كيف تصحح ذاكرة ECC هذا البت في ذاكرة ECC. أما رخصة OpenZFS فهي CDDL، ولهذا لا يأتي داخل نواة Linux، وإنما يثبت كحزمة منفصلة، كما في دليل تثبيته على Debian من مستودع contrib.

هل الشبكة أبطأ من القرص؟

سرعات الشبكة تكتب بالبت في الثانية، وسرعات الأقراص بالبايت، والتحويل قسمة على 8. فرابط 1GbE حده النظري 1000 ÷ 8 = 125 ميجابايت في الثانية، و2.5GbE (من معيار IEEE 802.3bz) حده 312.5، و10GbE حده 1250. أما القرص فورقة WD Red Plus نفسها تذكر للسعة 8 تيرابايت (WD80EFPX) معدل نقل داخلياً يصل إلى 215 ميجابايت في الثانية، والصورة التالية تضع الأرقام على مقياس واحد مع وقت نقل 1 تيرابايت:

أعمدة أفقية على مقياس واحد: 1GbE بحد 125 ميجابايت في الثانية وينقل 1 تيرابايت في ساعتين و13 دقيقة، وقرص WD Red Plus 8TB بحد 215 ميجابايت في الثانية وينقل 1 تيرابايت في ساعة و17 دقيقة، و2.5GbE بحد 312.5 ميجابايت في الثانية في 53 دقيقة، و10GbE بحد 1250 ميجابايت في الثانية في 13 دقيقة، وتحتها معادلة الحساب
الحد النظري لكل سرعة شبكة مقابل قرص واحد، ووقت نقل 1 تيرابايت

والنتيجة العملية أن قرصاً واحداً يكفي ليملأ رابط 1GbE في النسخ المتتابع للملفات الكبيرة، لذلك إذا كان جهاز NAS فيه عدة أقراص وتنسخ إليه ملفات فيديو كبيرة فسوف تكون الشبكة هي عنق الزجاجة، وهنا يفيدك 2.5GbE، والذي لا يحتاج عادة إلا كرت شبكة ومحولاً Switch يدعمانه مع كابلات Cat 5e التي في أغلب البيوت. أما الملفات الصغيرة الكثيرة مثل آلاف الصور فيحكمها زمن الوصول وعدد العمليات أكثر من السرعة، فلا تتوقع أن يتضاعف نسخها مع الرابط الأسرع.

تجربة عملية: Samba وNFS في Containers

سوف نبني ثلاث Containers على شبكة واحدة: سيرفر Samba، وسيرفر NFS، وكلاينت يربط الاثنين، ثم Container رابعاً نجرب فيه ما يحدث عندما تتلف نسخة من البيانات. وكل شيء على Docker في جهاز واحد، لذلك أرقام السرعة هنا للتوضيح فقط، ولا تمثل شبكة حقيقية.

تشغيل السيرفرات

الأوامر التالية تنشئ الشبكة وال Containers وتثبت الحزم، ولاحظ أن سيرفر NFS والكلاينت يحتاجان --privileged لأن سيرفر NFS في Linux يعمل داخل النواة Kernel، والربط Mount عملية في النواة أيضاً:

docker network create lab-nas-net
docker run -d --name lab-nas-smb --network lab-nas-net --tmpfs /srv/share:size=2g alpine:3.20 sleep infinity
docker run -d --name lab-nas-nfs --network lab-nas-net --privileged --tmpfs /srv/nfs:size=2g alpine:3.20 sleep infinity
docker run -d --name lab-nas-client --network lab-nas-net --privileged alpine:3.20 sleep infinity
docker exec lab-nas-smb apk add --no-cache samba
docker exec lab-nas-nfs apk add --no-cache nfs-utils
docker exec lab-nas-client apk add --no-cache cifs-utils nfs-utils

بعد ذلك نجهز Samba بمستخدم اسمه sara ومجلد مشترك، ونرفع الحد الأدنى للبروتوكول إلى SMB3 ونجعل التشفير إلزامياً:

docker exec -i lab-nas-smb sh <<'EOF'
adduser -D -H sara
printf 'Lab-Pass-2026\nLab-Pass-2026\n' | smbpasswd -a -s sara
chown sara /srv/share
cat > /etc/samba/smb.conf <<'CONF'
[global]
   server role = standalone server
   server min protocol = SMB3
   smb encrypt = required
   map to guest = never
[share]
   path = /srv/share
   valid users = sara
   read only = no
CONF
smbd -D
smbd --version
EOF

والمخرج سوف يكون كما يلي:

Added user sara.
Version 4.19.9

ثم سيرفر NFS، حيث نكتب المجلد المشترك في /etc/exports ونشغل الخدمات التي يحتاجها:

docker exec -i lab-nas-nfs sh <<'EOF'
echo '/srv/nfs 192.168.0.0/16(rw,sync,no_subtree_check,fsid=0)' > /etc/exports
mount -t nfsd nfsd /proc/fs/nfsd
rpcbind && rpc.statd && rpc.nfsd 8 && rpc.mountd && exportfs -ra
exportfs -v
cat /proc/fs/nfsd/versions
rpcinfo -p
EOF

والمخرج سوف يكون كما يلي:

/srv/nfs      	192.168.0.0/16(sync,wdelay,hide,no_subtree_check,fsid=0,sec=sys,rw,secure,root_squash,no_all_squash)
+3 +4 +4.1 +4.2
   program vers proto   port  service
    100000    4   tcp    111
    100000    3   tcp    111
    100000    2   tcp    111
    100000    4   udp    111
    100000    3   udp    111
    100000    2   udp    111
    100024    1   udp  49305
    100024    1   tcp  39959
    100003    3   tcp   2049
    100003    4   tcp   2049
    100227    3   tcp   2049
    100021    1   udp  51530
    100021    3   udp  51530
    100021    4   udp  51530
    100021    1   tcp  40441
    100021    3   tcp  40441
    100021    4   tcp  40441
    100005    1   udp  58977
    100005    1   tcp  41117
    100005    2   udp  48170
    100005    2   tcp  58073
    100005    3   udp  56798
    100005    3   tcp  47113

في الإعداد أعلاه لاحظ التالي:

  • السطر +3 +4 +4.1 +4.2 يعني أن السيرفر يقدم NFSv3 وكل نسخ NFSv4.
  • جدول rpcinfo هو سبب المنافذ الخمسة في الصورة السابقة: البرنامج 100000 هو rpcbind على 111، و100003 هو NFS نفسه على 2049، و100005 هو mountd، و100021 هو مدير الأقفال nlockmgr، و100024 هو statd، والثلاثة الأخيرة على منافذ عشوائية تتغير مع كل تشغيل.
  • root_squash في السطر الأول قيمة افتراضية، ومعناها أن المستخدم root على الكلاينت يعامل كمستخدم بلا صلاحيات على السيرفر، وسوف نراها بعد قليل.
  • القيمة fsid=0 تجعل هذا المجلد هو المجلد الرئيسي Root الذي يراه كلاينت NFSv4، لذلك سوف يربطه باسم / وليس بالمسار الكامل. ولاحظ أن ال Volume هنا من نوع tmpfs، والسبب أن نظام ملفات overlay الذي يستخدمه Docker لا يقبل المشاركة عبر NFS، فإذا جربت مجلداً عادياً داخل ال Container فسوف ترى الخطأ does not support NFS export.

الربط من الكلاينت

الآن نربط المشاركات الثلاث من الكلاينت: SMB بالنسخة 3.1.1، وNFS بالنسختين 3 و4.1:

docker exec -i lab-nas-client sh <<'EOF'
mkdir -p /mnt/smb /mnt/nfs3 /mnt/nfs4
mount -t cifs //lab-nas-smb/share /mnt/smb -o username=sara,password=Lab-Pass-2026,vers=3.1.1
rpcbind && rpc.statd
mount -t nfs -o vers=3 lab-nas-nfs:/srv/nfs /mnt/nfs3
mount.nfs4 lab-nas-nfs:/ /mnt/nfs4 -o vers=4.1
mount | grep -E 'cifs|nfs' | sed -E 's/,(rsize|wsize|namlen|timeo|retrans|acregmin|file_mode|dir_mode|cache|uid|noforceuid|gid|noforcegid|relatime|soft|nounix|serverino|mapposix|bsize|echo_interval|actimeo|closetimeo|mountport|mountproto|local_lock|clientaddr|mountaddr|addr|mountvers)[^,)]*//g'
EOF
docker exec lab-nas-smb smbstatus -b 2>/dev/null | tail -4

والمخرج سوف يكون كما يلي:

//lab-nas-smb/share on /mnt/smb type cifs (rw,vers=3.1.1,username=sara)
lab-nas-nfs:/srv/nfs on /mnt/nfs3 type nfs (rw,vers=3,hard,proto=tcp,sec=sys)
lab-nas-nfs:/ on /mnt/nfs4 type nfs4 (rw,vers=4.1,hard,proto=tcp,sec=sys)
Samba version 4.19.9
PID     Username     Group        Machine                                   Protocol Version  Encryption           Signing
----------------------------------------------------------------------------------------------------------------------------------------
33      sara         sara         192.168.224.4 (ipv4:192.168.224.4:47668)  SMB3_11           AES-128-GCM          partial(AES-128-CMAC)

في المخرج أعلاه لاحظ التالي:

  • الأمر sed يحذف الخيارات الطويلة من مخرج mount حتى يبقى المهم فقط.
  • سطر smbstatus يؤكد من جهة السيرفر أن الاتصال بالنسخة SMB3_11 وأن البيانات مشفرة بـ AES-128-GCM، وهذا ما طلبناه بـ smb encrypt = required.
  • الخيار hard في NFS يعني أن الكلاينت ينتظر السيرفر إلى الأبد إذا اختفى، ولا يعيد خطأ للبرنامج، وهذا يحمي البيانات من كتابة نصفية، ولكنه يعني أيضاً أنك إذا أوقفت سيرفر NFS قبل أن تفك الربط من الكلاينت فسوف تعلق العمليات على الكلاينت، وقد يرفض Docker إيقاف ال Container نفسه حتى يعود السيرفر، لذلك افصل الربط دائماً قبل إيقاف السيرفر.

قياس سرعة النسخ (للتوضيح)

نكتب ملفاً حجمه 1 جيجابايت إلى كل مشاركة مع conv=fsync حتى ينتظر dd وصول البيانات فعلاً، ثم نفرغ ذاكرة التخزين المؤقت Cache ونقرأ الملف:

docker exec -i lab-nas-client sh <<'EOF'
mount | grep -cE 'cifs|nfs'
for d in /mnt/smb /mnt/nfs3 /mnt/nfs4; do
  printf '%-10s ' $d
  dd if=/dev/zero of=$d/test.bin bs=1M count=1024 conv=fsync 2>&1 | tail -1
done
for d in /mnt/smb /mnt/nfs3 /mnt/nfs4; do
  echo 3 > /proc/sys/vm/drop_caches
  printf '%-10s read ' $d
  dd if=$d/test.bin of=/dev/null bs=1M 2>&1 | tail -1
done
EOF

والمخرج سوف يكون كما يلي:

3
/mnt/smb   1073741824 bytes (1.0GB) copied, 32.368583 seconds, 31.6MB/s
/mnt/nfs3  1073741824 bytes (1.0GB) copied, 11.962633 seconds, 85.6MB/s
/mnt/nfs4  1073741824 bytes (1.0GB) copied, 9.199248 seconds, 111.3MB/s
/mnt/smb   read 1073741824 bytes (1.0GB) copied, 42.851718 seconds, 23.9MB/s
/mnt/nfs3  read 1073741824 bytes (1.0GB) copied, 10.284629 seconds, 99.6MB/s
/mnt/nfs4  read 1073741824 bytes (1.0GB) copied, 10.884492 seconds, 94.1MB/s

ولماذا كان SMB أبطأ بكثير هنا؟ والسبب أن كل بايت فيه يشفر ويفك تشفيره على المعالج نفسه الذي يشغل الطرفين، وللتأكد أوقفنا التشفير الإلزامي وأعدنا الربط والكتابة مرتين:

docker exec lab-nas-client sh -c 'rm -f /mnt/smb/test.bin /mnt/nfs3/test.bin; umount /mnt/smb'
docker exec lab-nas-smb sh -c "sed -i 's/smb encrypt = required/smb encrypt = off/' /etc/samba/smb.conf; smbcontrol all reload-config"
docker exec lab-nas-client sh -c 'mount -t cifs //lab-nas-smb/share /mnt/smb -o username=sara,password=Lab-Pass-2026,vers=3.1.1; for i in 1 2; do dd if=/dev/zero of=/mnt/smb/test.bin bs=1M count=1024 conv=fsync 2>&1 | tail -1; done; rm /mnt/smb/test.bin'
docker exec lab-nas-smb smbstatus -b | tail -1

والمخرج سوف يكون كما يلي:

1073741824 bytes (1.0GB) copied, 14.720864 seconds, 69.6MB/s
1073741824 bytes (1.0GB) copied, 9.358958 seconds, 109.4MB/s
85      sara         sara         192.168.224.4 (ipv4:192.168.224.4:34932)  SMB3_11           -                    partial(AES-128-CMAC)

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

نكسر الإعداد: كلاينت قديم، وroot على NFS

الآن نجرب كلاينت يطلب SMB1 فقط، ثم ننشئ ملفاً على NFS بالمستخدم root:

docker exec lab-nas-client sh -c 'apk add --no-cache samba-client >/dev/null 2>&1; smbclient //lab-nas-smb/share -U sara%Lab-Pass-2026 --option="client min protocol=NT1" --option="client max protocol=NT1" -c ls; echo rc=$?'
docker exec lab-nas-client sh -c 'touch /mnt/nfs4/from-root.txt; ls -ln /mnt/nfs4/'

والمخرج سوف يكون كما يلي:

smbXcli_negprot_smb1_done: No compatible protocol selected by server.
Protocol negotiation to server lab-nas-smb (for a protocol between NT1 and NT1) failed: NT_STATUS_INVALID_NETWORK_RESPONSE
rc=1
total 0
-rw-r--r--    1 65534    65534            0 Oct  9 08:26 from-root.txt

في المخرج أعلاه لاحظ التالي:

  • الاسم NT1 هو اسم SMB1 في Samba، والسيرفر رفض كل نسخة أقل من SMB3، فالجهاز القديم لا يتصل أصلاً، وهذا ما تريده.
  • الملف الذي أنشأه root على الكلاينت ملك المستخدم 65534 (nobody) على السيرفر، وهذا هو root_squash، فمن يملك root على جهاز في الشبكة لا يصبح root على ملفات NAS.

وخطأ آخر سوف تراه إذا ربطت NFSv3 دون أن تشغل rpc.statd على الكلاينت، لأن أقفال NFSv3 تحتاجه كما ذكرنا:

mount.nfs: rpc.statd is not running but is required for remote locking.
mount.nfs: Either use '-o nolock' to keep locks local, or start statd.

والحل أن تشغل الخدمة كما فعلنا في خطوة الربط، وليس أن تضيف nolock، لأن nolock يجعل الأقفال محلية على كل كلاينت، فلا يعرف كلاينت أن آخر فتح الملف نفسه. وهذا الخطأ لا يظهر في NFSv4 أصلاً لأن الأقفال داخل البروتوكول.

نسخة تالفة: RAID 1 مقابل نظام ملفات بمجموع تحقق

هذه التجربة تجيب عن سؤال مهم: إذا تلفت نسخة واحدة من البيانات بصمت، أي دون أن يبلغ القرص عن خطأ، فهل تكتشف المصفوفة ذلك؟ وكنا نريد أن نجربها على ZFS، ولكن نواة Docker Desktop على Windows لا تحتوي على ZFS، والأمر التالي يبين ذلك:

docker run --rm alpine:3.20 sh -c "uname -r; grep -wE 'btrfs|zfs|nfsd|cifs' /proc/filesystems"
5.15.167.4-microsoft-standard-WSL2
nodev	nfsd
nodev	cifs
	btrfs

لذلك استخدمنا Btrfs الموجود في النواة، وهو يقوم على الفكرة نفسها: مجموع تحقق لكل كتلة، وإصلاح من النسخة السليمة عند القراءة كما في توثيق Btrfs، وفحص دوري Scrub كما في صفحة ال Scrub. وقارناه بمصفوفة md RAID 1 العادية في Linux. ولاحظ أن الأقراص هنا ملفات مربوطة كأجهزة Loop، وأن أجهزة Loop مشتركة بين كل Containers الجهاز، لذلك احفظ أسماءها لتفصلها في النهاية، ولا تلمس الأجهزة التي لم تنشئها:

docker run -d --name lab-nas-raid --privileged alpine:3.20 sleep infinity
docker exec lab-nas-raid sh -c 'apk add --no-cache mdadm btrfs-progs e2fsprogs util-linux coreutils grep >/dev/null 2>&1; mdadm --version; btrfs --version'
docker exec -i lab-nas-raid sh <<'EOF'
mkdir -p /lab /mnt/md /mnt/bt && cd /lab
for i in 1 2 3 4; do truncate -s 300M disk$i.img; done
for i in 1 2 3 4; do losetup -f --show disk$i.img; done | tee loops.txt
EOF
mdadm - v4.3 - 2024-02-15
btrfs-progs v6.8.1
/dev/loop2
/dev/loop3
/dev/loop4
/dev/loop5

الأرقام في جهازك قد تختلف، فاستبدلها في الأوامر التالية. والآن الجزء الأول: RAID 1 من القرصين loop2 وloop3، نكتب عليه ملفاً فيه مليونا سطر ونحسب ال Hash، ثم نغير 26 بايتاً في القرص الثاني وحده مباشرة، أي من تحت المصفوفة كما يحدث في التلف الصامت:

docker exec -i lab-nas-raid sh <<'EOF'
mdadm --create /dev/md100 --level=1 --raid-devices=2 /dev/loop2 /dev/loop3 --run --quiet
mdadm --wait /dev/md100
mkfs.ext4 -q /dev/md100 && mount /dev/md100 /mnt/md
awk 'BEGIN{for(i=1;i<=2000000;i++) printf "family-photo-line-%08d\n", i}' > /mnt/md/photos.txt
sha256sum /mnt/md/photos.txt
umount /mnt/md; sync; echo 3 > /proc/sys/vm/drop_caches
OFF=$(grep -obUaF 'family-photo-line-01000000' /dev/loop3 | head -1 | cut -d: -f1)
echo "corrupting loop3 at byte $OFF"
printf 'family-photo-line-0100XXXX' | dd of=/dev/loop3 bs=1 seek=$OFF conv=notrunc,fsync status=none
blockdev --flushbufs /dev/loop3; echo 3 > /proc/sys/vm/drop_caches
mount -o ro /dev/md100 /mnt/md
sha256sum /mnt/md/photos.txt
grep -n XXXX /mnt/md/photos.txt
umount /mnt/md
echo check > /sys/block/md100/md/sync_action; sleep 1; mdadm --wait /dev/md100
echo "mismatch_cnt: $(cat /sys/block/md100/md/mismatch_cnt)"
mdadm --stop /dev/md100 >/dev/null; mdadm --zero-superblock /dev/loop2 /dev/loop3
EOF

والمخرج سوف يكون كما يلي:

2035fd4b5755103c9085e34558e810c596b8f2125811565224e68a102a6b722b  /mnt/md/photos.txt
corrupting loop3 at byte 30146725
fa96cde4cdc8d2e120d40a7c2e16df4f60b495373147dda6eae9eb4c751b6591  /mnt/md/photos.txt
1000000:family-photo-line-0100XXXX
mismatch_cnt: 128

في المخرج أعلاه لاحظ التالي:

  • ال Hash تغير من 2035… إلى fa96…، والسطر رقم مليون أصبح 0100XXXX، ومع ذلك لم يظهر أي خطأ، فقد قرأت المصفوفة الكتلة من القرص الثاني وسلمتها للبرنامج كما هي، والسبب أن md لا يعرف أي النسختين صحيحة، فهو لا يحفظ مجموع تحقق للبيانات.
  • الفحص check اكتشف أن النسختين مختلفتان وأعطى mismatch_cnt بقيمة 128، وهو عدد القطاعات Sectors وليس البايتات، وتوثيق النواة يقول إن الرقم قد يكون أكبر من عدد الأخطاء الفعلية لأن md يعمل بالصفحات. ولكن الفحص لا يقول أي النسختين هي الصحيحة، فلو طلبت منه الإصلاح repair فسوف يجعل النسختين متطابقتين، وليس بالضرورة على النسخة السليمة.

والجزء الثاني: الملف نفسه على Btrfs بنسختين RAID1 على loop4 وloop5، ونفسد النسخة على loop5 بالطريقة نفسها:

docker exec -i lab-nas-raid sh <<'EOF'
mkfs.btrfs -q -f -d raid1 -m raid1 /dev/loop4 /dev/loop5
mount /dev/loop4 /mnt/bt
awk 'BEGIN{for(i=1;i<=2000000;i++) printf "family-photo-line-%08d\n", i}' > /mnt/bt/photos.txt
sha256sum /mnt/bt/photos.txt
umount /mnt/bt; sync; echo 3 > /proc/sys/vm/drop_caches
OFF=$(grep -obUaF 'family-photo-line-01000000' /dev/loop5 | head -1 | cut -d: -f1)
echo "corrupting loop5 at byte $OFF"
printf 'family-photo-line-0100XXXX' | dd of=/dev/loop5 bs=1 seek=$OFF conv=notrunc,fsync status=none
blockdev --flushbufs /dev/loop5; echo 3 > /proc/sys/vm/drop_caches
mount /dev/loop4 /mnt/bt
for i in 1 2 3 4; do echo 3 > /proc/sys/vm/drop_caches; sha256sum /mnt/bt/photos.txt; done
grep -c XXXX /mnt/bt/photos.txt
dmesg | grep -i btrfs | grep -iE 'csum|fixed|correct|repair' | tail -4 | sed -E 's/^\[[ 0-9.]+\] //'
btrfs scrub start -B /mnt/bt
btrfs device stats /mnt/bt
umount /mnt/bt
EOF

والمخرج سوف يكون كما يلي:

2035fd4b5755103c9085e34558e810c596b8f2125811565224e68a102a6b722b  /mnt/bt/photos.txt
corrupting loop5 at byte 94174373
2035fd4b5755103c9085e34558e810c596b8f2125811565224e68a102a6b722b  /mnt/bt/photos.txt
2035fd4b5755103c9085e34558e810c596b8f2125811565224e68a102a6b722b  /mnt/bt/photos.txt
2035fd4b5755103c9085e34558e810c596b8f2125811565224e68a102a6b722b  /mnt/bt/photos.txt
2035fd4b5755103c9085e34558e810c596b8f2125811565224e68a102a6b722b  /mnt/bt/photos.txt
0
BTRFS warning (device loop4): csum failed root 5 ino 257 off 26996736 csum 0xa73e0523 expected csum 0xe4ae2882 mirror 2
BTRFS info (device loop4): read error corrected: ino 257 off 26996736 (dev /dev/loop5 sector 183928)
Starting scrub on devid 1
Starting scrub on devid 2
scrub done for c7f30b4f-64c7-4a32-a285-92c789844d0c
Scrub started:    Fri Oct  9 08:33:44 2026
Status:           finished
Duration:         0:00:01
Total to scrub:   103.41MiB
Rate:             103.41MiB/s
Error summary:    no errors found
[/dev/loop4].write_io_errs    0
[/dev/loop4].read_io_errs     0
[/dev/loop4].flush_io_errs    0
[/dev/loop4].corruption_errs  0
[/dev/loop4].generation_errs  0
[/dev/loop5].write_io_errs    0
[/dev/loop5].read_io_errs     0
[/dev/loop5].flush_io_errs    0
[/dev/loop5].corruption_errs  1
[/dev/loop5].generation_errs  0

في المخرج أعلاه لاحظ التالي:

  • ال Hash بقي 2035… في القراءات الأربع، ولم يظهر XXXX في الملف، فالبرنامج لم يستلم البيانات التالفة أبداً.
  • سطر csum failed … mirror 2 يعني أن Btrfs قرأ النسخة الثانية فوجد أن مجموع التحقق لا يطابق، فقرأ النسخة الأولى، ثم كتب النسخة السليمة فوق التالفة كما يقول سطر read error corrected.
  • لهذا لم يجد ال Scrub بعدها أي خطأ، وبقي العداد corruption_errs 1 على loop5 ليخبرك أن هذا القرص أعطى بيانات تالفة مرة، وهو عداد يستحق المراقبة.

ولكن ماذا عن ملف لا يفتحه أحد؟ هنا يأتي دور ال Scrub، فنفسد سطراً آخر ونشغل ال Scrub مباشرة دون أن نقرأ الملف:

docker exec -i lab-nas-raid sh <<'EOF'
echo 3 > /proc/sys/vm/drop_caches
OFF=$(grep -obUaF 'family-photo-line-01500000' /dev/loop5 | head -1 | cut -d: -f1)
echo "corrupting loop5 at byte $OFF"
printf 'family-photo-line-0150XXXX' | dd of=/dev/loop5 bs=1 seek=$OFF conv=notrunc,fsync status=none
blockdev --flushbufs /dev/loop5; echo 3 > /proc/sys/vm/drop_caches
mount /dev/loop4 /mnt/bt
btrfs scrub start -B /mnt/bt | grep -E 'Error summary|Corrected|Uncorrectable|Unverified'
btrfs scrub start -B /mnt/bt | grep -E 'Error summary'
sha256sum /mnt/bt/photos.txt
umount /mnt/bt
EOF

والمخرج سوف يكون كما يلي:

corrupting loop5 at byte 107674373
WARNING: errors detected during scrubbing, 1 corrected
Error summary:    csum=1
  Corrected:      1
  Uncorrectable:  0
  Unverified:     0
Error summary:    no errors found
2035fd4b5755103c9085e34558e810c596b8f2125811565224e68a102a6b722b  /mnt/bt/photos.txt

ال Scrub الأول وجد خطأ مجموع تحقق واحداً وأصلحه، والثاني لم يجد شيئاً، وال Hash ما زال 2035…. وهذا بالضبط ما يفعله zpool scrub في ZFS، ولهذا تجدول أنظمة NAS المبنية على ZFS وBtrfs فحصاً دورياً. والصورة التالية تلخص الفرق الذي رأيناه:

صفان: في الأعلى md RAID 1 بقرصين، القرص الأول فيه الكتلة السليمة 01000000 والثاني فيه 0100XXXX، فيقرأ md القرص الثاني ويستلم الحاسوب الملف ويتغير ال Hash من 2035 إلى fa96 دون أي خطأ، ثم يعطي الفحص mismatch_cnt بقيمة 128 دون أن يعرف أي النسختين صحيحة، وفي الأسفل Btrfs RAID1 أو ZFS mirror بالقرصين نفسيهما، فيفشل مجموع التحقق في النسخة الثانية ويقرأ النسخة الأولى ويعيد البيانات السليمة ثم يكتبها فوق التالفة، وبجانبه ال Scrub الذي يفحص الملفات التي لا يفتحها أحد
المصفوفة دون مجموع تحقق تسلمك النسخة التالفة، ونظام الملفات بمجموع تحقق يكتشفها ويصلحها

التنظيف

افصل الربط من الكلاينت أولاً لأن ربط NFS من نوع hard كما ذكرنا، ثم افصل أجهزة Loop التي أنشأتها بأسمائها، ثم احذف ال Containers والشبكة بأسمائها:

docker exec lab-nas-client sh -c 'umount /mnt/smb /mnt/nfs3 /mnt/nfs4'
docker exec lab-nas-raid sh -c 'for d in 2 3 4 5; do losetup -d /dev/loop$d; done; rm -f /lab/*.img'
docker rm -f lab-nas-client lab-nas-nfs lab-nas-smb lab-nas-raid
docker network rm lab-nas-net

أخطاء شائعة

  • اعتبار RAID نسخة احتياطية: RAID يحميك من عطل قرص فقط، والحذف وبرامج الفدية والحريق تصل إلى كل الأقراص معاً.
  • تفعيل SMB1 من أجل جهاز قديم: هذا يفتح الشبكة كلها لثغرات مثل التي استغلها WannaCrypt، فحدث الجهاز أو استبدله.
  • ربط LUN واحد بسيرفرين: نظام الملفات العادي على iSCSI لسيرفر واحد فقط.
  • RAID 5 بأقراص كبيرة دون فحص دوري: إعادة البناء تقرأ كل الأقراص، فاختر تماثلاً مزدوجاً وجدول Scrub منتظماً.
  • إضافة قرص منفرد إلى ZFS Pool فيه raidz: كل vdev يجب أن يكون محمياً لأن ضياع واحد منها يضيع ال Pool.
  • فتح NFS لشبكة كاملة بـ *: NFS بإعداد sec=sys يصدق رقم المستخدم الذي يرسله الكلاينت، فحدد الشبكة بدقة.
  • شراء 10GbE لنسخ آلاف الصور الصغيرة: الملفات الصغيرة يحكمها زمن الوصول، وفائدة السرعة الأعلى تظهر في الملفات الكبيرة.

الخلاصة

  • DAS أقراص لجهاز واحد، وNAS ملفات يشترك فيها الجميع عبر SMB وNFS ونظام الملفات على جهاز NAS، وSAN أقراص LUN عبر Fibre Channel أو iSCSI ونظام الملفات على كل سيرفر.
  • SMB 3 للأجهزة المختلطة، وNFSv4 بين سيرفرات Linux بمنفذ واحد هو 2049، وiSCSI على المنفذ 3260 لأقراص الأجهزة الافتراضية، وSMB1 لا مكان له في شبكتك.
  • المساحة في raidz أو RAID 5/6 تقريباً (N − P) × حجم القرص، وRAID ليس نسخة احتياطية.
  • رقم أخطاء القراءة في ورقة المواصفات حد أعلى وليس معدلاً مقاساً، والحل العملي تماثل مزدوج وفحص دوري ونسخة احتياطية، وليس الخوف من رقم.
  • في تجربتنا سلم md RAID 1 الملف التالف دون أي خطأ، بينما اكتشف Btrfs التلف بمجموع التحقق وأصلحه، وهي الفكرة نفسها في ZFS.
  • قرص واحد يملأ رابط 1GbE، و2.5GbE ترقية رخيصة لمن ينقل ملفات كبيرة.
دليلNAS جاهز أم تبنيه بنفسك؟ ما الذي تكسبه وما تخسرهكيف تقرر بين جهاز NAS جاهز وجهاز تبنيه بنفسك، بأرقام الشركات وأسعارها الرسمية وما تعلمناه من هجمات الفدية.دليلأي نظام تشغيل تضعه على NAS تبنيه بنفسك؟كيف تختار نظام تشغيل لجهاز NAS تبنيه بنفسك، مع تجربة تستعيد فيها ملفاً محذوفاً وقرصاً كاملاً من التماثل.دليلأنواع التخزين وواجهة S3: أين تضع بيانات تطبيقك؟أين تضع قاعدة البيانات وملفات المستخدمين والنسخ الاحتياطية، ولماذا يناسب كلاً منها نوع مختلف من التخزين.دليلعتاد الهوم لاب: Mini PC أم NAS أم سيرفر مستعمل؟كيف تختار جهاز الهوم لاب بأرقام الشركة المصنعة وليس بالسعر وحده، وكم يكلفك من الكهرباء في السنة بالتعرفة السعودية.دليلالنسخ الاحتياطي بقاعدة 3-2-1 واختبار الاستعادةكيف تحدد كم بيانات تقبل أن تخسر، وتبني نسخاً لا يستطيع المخترق حذفها، وتتأكد أنك تستطيع استعادتها فعلاً.

سجل التحديثات

  • أكتوبر 2026: كتابة المقال، والتجربة على Docker Engine 29.8.0 بنواة WSL2 مع Alpine 3.20 وSamba 4.19.9 وnfs-utils وmdadm 4.3 وbtrfs-progs 6.8.1، والأرقام من توثيق Microsoft وSamba وOpenZFS وBtrfs وRFC 1813 و7530 و7143 وأوراق مواصفات Western Digital كما قرأناها في 9 أكتوبر 2026.
نشرة عرب رووت | ArabRoot

معرفة تستحق مكاناً في بريدك.

مقالات مختارة وأدوات مفيدة وأفكار لمشروعك القادم، في رسالة واحدة كل أسبوع.

يمكنك إلغاء الاشتراك متى شئت. الخصوصية

تم استلام طلبك. افتح بريدك واضغط رابط التأكيد لإتمام الاشتراك.