SSD Nodes Learn 🎉 VPS من $5.50/شهر
الأدلة Matt Connorبقلم Matt Connor

كم مرة تشغّل ZFS scrub على VPS صغير؟

يقرأ scrub كل الكتل المخصّصة ويتحقق منها، لكنه لا يصلح التلف على جهاز واحد. تعرّف إلى الجدول العملي لتشغيله على pool صغير.

ما الذي يفعله ZFS scrub فعلياً

يقرأ ZFS scrub كل كتلة مخصّصة في الـpool، ويعيد حساب checksum الخاص بها، ثم يقارن النتيجة بـchecksum المخزّن في block pointer الأب. عندما تختلف القيمتان، يصلح ZFS الكتلة باستخدام أي redundancy يحتفظ به الـpool. لا توجد وظيفة أخرى في ZFS تنفّذ هذه المهمة. تتحقق عمليات القراءة العادية من الكتل التي تلمسها فقط، لذلك تظل الملفات التي لم تفتحها منذ عامين من دون تحقق إلى أن يقرأها scrub.

لا يُعد scrub fsck، أي عملية الإصلاح غير المتصلة التي تحتاج إليها أنظمة الملفات الأخرى. لا توجد مرحلة لإصلاح البنية، لأن ZFS لا يترك تنسيق القرص في حالة تالفة: تكتب كل عملية كتابة إلى موقع جديد، ثم يُحدَّث uberblock، وهو المؤشر الجذري للـpool، في النهاية. كما أن scrub لا يقرأ الجهاز بأكمله. بل يقرأ الكتل المخصّصة فقط، ولذلك يستغرق scrub على pool شبه فارغ دقائق، بينما يستغرق وقتاً أطول بكثير على الـpool نفسه عندما تكون نسبة امتلائه 80%.

يعمل scrub بأدنى أولوية لإدخال وإخراج البيانات يوفّرها ZFS. في Linux، تكون قيمة zfs_vdev_scrub_max_active الافتراضية 2، ولذلك لا يكون أكثر من قراءتي scrub قيد التنفيذ لكل vdev (جهاز افتراضي، أي مجموعة الأقراص التي يعاملها ZFS كوحدة واحدة). وتكون قيمة zfs_scrub_min_time_ms الافتراضية 750، وهي الحد الأدنى للوقت الذي يقضيه مؤشر ترابط المزامنة في أعمال scrub بين عمليات تفريغ مجموعات المعاملات، وهي عمليات الإيداع الدورية التي يجمع فيها ZFS عمليات الكتابة. على جهاز خامل، يستخدم scrub القرص بأكمله. وتحت الحمل، يتراجع scrub لإتاحة الموارد للعمليات الأخرى. في pool يضم جهازاً أو جهازين، لا توجد موارد أخرى يمكنه الانتقال إليها، ولذلك يكون جدولة scrub أهم هنا مما هي عليه في هيكل كبير يضم ستين محركاً.

لماذا تُجري scrub على pool لا يستطيع إصلاح نفسه؟

هذه هي الجملة التي تحدد كل ما يأتي على pool صغير. عند غياب التكرار، يكتشف scrub التلف ولا يستطيع إصلاحه. يكون القرص الافتراضي الواحد في VPS عبارة عن pool بلا mirror ولا parity. يقرأ ZFS الكتلة التالفة، ويفشل التحقق من checksum، ويعدّها في عمود CKSUM، ويحدد اسم الملف، ثم يتوقف، لأنه لا توجد نسخة ثانية يمكن إعادة البناء منها.

تجدر معرفة استثناءين جزئيين. يخزن ZFS افتراضياً نسخة إضافية من metadata (redundant_metadata=all)، ويكتبها في منطقة مختلفة من الجهاز، لذلك يستطيع scrub إصلاح directory entry أو block pointer تالف حتى في pool يتكون من جهاز واحد. كما أن dataset الذي يستخدم copies=2 يحتفظ بنسختين من كتل البيانات، مقابل استهلاك ضعف المساحة. لكن أياً منهما لا يصمد أمام فقدان الجهاز. وتحذر وثائق خاصية copies من هذا تحديداً: لا تنشئ pool من نوع striped، وتعيّن copies=2، ثم تعتقد أن لديك تكراراً.

لذلك يوفّر scrub في pool يتكون من جهاز واحد شيئاً واحداً: إشعاراً مبكراً ودقيقاً. فهو يحوّل التلف الصامت إلى اسم ملف في zpool status -v، بينما لا تزال النسخة الاحتياطية تحتوي على نسخة سليمة من ذلك الملف. وهذا حجة لصالح النسخ الاحتياطية، وليس حجة ضد scrub. إذا لم تحسم بعد الفرق بين image لنقطة زمنية ونسخة فعلية خارج الخادم، فابدأ بقراءة لماذا لا تُعدّ snapshot في VPS نسخة احتياطية، لأن نتيجة scrub لا تفيد إلا إذا كان هناك شيء آخر يحتفظ بنسخة سليمة.

حتى عدم عثور scrub على أي مشكلة يُعد نتيجة. فهذا يخبرك بأن البيانات التي توشك على الوثوق بها سليمة، وهو ما تريد معرفته قبل الاستعادة أو الترحيل.

كم مرة يجب فحص مجموعة VPS صغيرة؟

الفحص الشهري هو الإعداد الافتراضي المناسب، وهو ما تفترضه الحزم مسبقاً. توفّر Debian وUbuntu مهمة cron تفحص المجموعات السليمة في يوم الأحد الثاني من كل شهر. يعمل نظام periodic في FreeBSD وفق حدّ زمني بالأيام، وتكون قيمة daily_scrub_zfs_default_threshold الافتراضية 35، وهو ما يصفه الدليل بأنه خمسة أسابيع.

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

قس مدة العملية، ثم قرر. شغّل عملية فحص واحدة يدوياً وراقب المدة التي تستغرقها.

  1. شغّل sudo zpool scrub tank في مساء هادئ، وسجّل المدة الإجمالية بدءاً من zpool status.
  2. إذا انتهت العملية خلال أقل بكثير من ساعة وكان الخادم خاملاً طوال الليل، فالفحص الأسبوعي مناسب من حيث التكلفة.
  3. إذا استغرقت العملية ساعات كثيرة بينما كانت المجموعة تخدم حركة الشبكة، فالتزم بالفحص الشهري واترك المهمة المرفقة بالحزمة تديره.
  4. أعد قياس المدة كلما نمت المجموعة بوضوح، لأن مدة الفحص ترتبط بالبيانات المخصّصة، لا بسعة القرص.

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

بدء عملية scrub وإيقافها مؤقتاً وإيقافها نهائياً

sudo zpool scrub tank
sudo zpool status tank

الإيقاف المؤقت والإيقاف النهائي عمليتان مختلفتان، وقد يؤدي اختيار العملية الخطأ إلى خسارة ساعات في أعمال مكررة.

sudo zpool scrub -p tank
sudo zpool scrub tank
sudo zpool scrub -s tank

يوقف -p العملية مؤقتاً. تُزامَن حالة الإيقاف المؤقت والتقدم إلى القرص دورياً، لذلك تستمر عملية scrub المتوقفة مؤقتاً بعد التصدير أو إعادة التشغيل: يعود الـpool وتبقى عملية scrub متوقفة مؤقتاً بانتظارك. يؤدي تشغيل zpool scrub مرة أخرى إلى استئناف العملية من آخر نقطة تحقق كُتبت على القرص. أما -s فيوقف عملية scrub، وتبدأ عملية scrub التالية من البداية. استخدم -p عندما تحتاج إلى القرص لمدة ساعة. استخدم -s عندما تريد إلغاء عملية scrub.

هناك علامتا خيار إضافيتان تستحقان المعرفة. ينتظر -w حتى تنتهي عملية scrub قبل أن يعيد النتيجة، وهذا ما تحتاج إليه داخل script حتى لا تبدأ الخطوة التالية مبكراً. ينفّذ -e عملية scrub للملفات التي تحتوي على أخطاء بيانات معروفة فقط، وفقاً لما أبلغ عنه zpool status -v. وهذه طريقة سريعة للتأكد من أن الملف الذي استعدته من backup أصبح سليماً.

ينفّذ ZFS عملية scrub واحدة أو resilver واحدة، وهي إعادة البناء التي تلي استبدال جهاز، في كل مرة لكل pool، لأن كلتا العمليتين تستهلكان قدرًا كبيرًا من عمليات الإدخال والإخراج. إذا كان أحد الأجهزة يخضع لعملية resilver، تنتظر عملية scrub دورها.

كيفية قراءة حالة zpool أثناء تشغيل scrub

شغّل sudo zpool status tank واقرأ الأرقام الخاصة بك بدلاً من مقارنتها بأرقام شخص آخر. أثناء تشغيل scrub، يعرض سطر scan: رقماً للبيانات المفحوصة، ورقماً للبيانات المُرسلة، والإجمالي، والبيانات المُصلحة، ونسبة الإنجاز، والتقدير الزمني المتبقي.

يمثل Scanned مرحلة البيانات الوصفية، حيث يتنقل ZFS عبر شجرة الكتل ويجمع العناوين التي يحتاج إلى قراءتها. ويمثل Issued مرحلة البيانات، أي عمليات القراءة التي أُرسلت فعلياً إلى الجهاز بعد ترتيبها وفق ترتيب القرص. إنّ scrub المرتب هو سبب وجود هذين العدادين، بينما يتتبع issued التقدم الفعلي. في البداية يتقدم scanned كثيراً على issued، ولذلك لا يكون التقدير الزمني ذا دلالة كبيرة. قيّم التقدم بعد الوصول إلى أول عشرة بالمئة.

يحصي Repaired البايتات التي أُعيدت كتابتها من نسخة سليمة. في pool لا تتوفر فيه أي redundancy، تبقى هذه القيمة صفراً مهما كانت نتيجة scrub. وهذا يعيد صياغة النقطة السابقة في صورة رقم يمكنك مراقبته.

اقرأ بعد ذلك أعمدة كل جهاز. يحصي READ وWRITE أخطاء الإدخال والإخراج التي أبلغ عنها الجهاز نفسه. ويحصي CKSUM الكتل التي فشل التحقق من checksum لها، كما أن CKSUM هو العمود الذي يهدف scrub إلى تعبئته. إذا كانت قيمة CKSUM غير صفرية في جهاز يبدو سليماً، فهذه نتيجة حقيقية: عادت البيانات، لكنها عادت بشكل غير صحيح.

السطر الأخير هو الحكم. errors: No known data errors تعني نجاح العملية. وأي قيمة أخرى تعني ضرورة تشغيل sudo zpool status -v tank، الذي يطبع القائمة الكاملة لأخطاء البيانات منذ آخر scrub مكتمل، بما في ذلك أسماء الملفات المتأثرة. استعد تلك الملفات من النسخة الاحتياطية، وشغّل sudo zpool clear tank لإعادة ضبط العدادات، ثم شغّل scrub مرة أخرى. يعيد كل scrub مكتمل إنشاء تلك القائمة، لذلك فإن اسم الملف الغائب بعد scrub كامل ونظيف قد اختفى فعلاً.

ما مهمة الفحص الدوري الموجودة على خادمك؟

لا تفترض وجود مهمة، ولا تفترض وجود مهمة واحدة فقط. تختلف الآلية حسب المنصة والحزمة. تنسيق pool متماثل في كل مكان، لذلك من السهل نسيان أن الأدوات المحيطة به تختلف، وأن طريقة توفير ZFS في FreeBSD مقارنةً بـLinux هي الفرق المهم هنا.

في FreeBSD توجد المهمة ضمن نظام periodic. اضبط القيم التالية في /etc/periodic.conf:

daily_scrub_zfs_enable="YES"
daily_scrub_zfs_pools="tank"
daily_scrub_zfs_default_threshold="35"

daily_scrub_zfs_pools قائمة مفصولة بمسافات لأسماء pool، وتركها فارغة يفحص كل pool. daily_scrub_zfs_default_threshold هو عدد الأيام بين عمليات الفحص عندما لا يكون هناك حد خاص بـpool، ويذكر الدليل أن القيمة الافتراضية هي 35. تعمل المهمة اليومية كل يوم، لكنها تبدأ الفحص فقط بعد تجاوز الحد المحدد.

في Linux يعتمد ذلك على حزمة ZFS الخاصة بتوزيعتك، وقد تحتوي بعض الأنظمة على الآليتين معاً. توجد مؤقتات systemd خاصة بكل pool، وهي zfs-scrub-monthly@tank.timer وzfs-scrub-weekly@tank.timer، وتُفعَّل لـpool واحد في كل مرة. توفّر Debian وUbuntu أيضاً /etc/cron.d/zfsutils-linux، التي تشغّل برنامجاً نصياً يفحص كل pool في حالة ONLINE في الأحد الثاني من كل شهر. تحقق مما هو موجود لديك قبل إضافة أي شيء:

systemctl list-timers 'zfs-*'
ls /etc/cron.d/ | grep -i zfs
sudo zpool history tank | grep scrub

zpool history هي الإجابة الدقيقة، لأنها تسجل عمليات الفحص التي بدأها pool فعلياً، مع تواريخها. يعني إجراء فحصين في الشهر أن الآليتين تعملان، ويجب تعطيل إحداهما. لتفعيل مؤقت:

sudo systemctl enable --now zfs-scrub-monthly@tank.timer

المساحة الحرة أهم من أي معلمة قابلة للضبط

تتحدد مدة الفحص في pool صغيرة بكمية البيانات المخصصة ومدى تشتتها. وامتلاء pool يزيد العاملين سوءاً.

توصي OpenZFS بالحفاظ على مساحة حرة في pool تتجاوز 10%. وعند انخفاضها عن ذلك، تبدأ metaslabs، وهي الأجزاء التي يعمل عليها المخصِّص، بتجاوز عتبة المساحة الحرة البالغة 4%، وينتقل المخصِّص من first-fit إلى best-fit. يستهلك best-fit قدراً أكبر بكثير من CPU. وترتفع مدة استجابة الكتابة، ويزداد التجزؤ، ويصبح الفحص التالي أبطأ، لأن الكمية نفسها من البيانات تصل الآن على هيئة عمليات قراءة أكثر وأصغر.

لذلك، لا تبدأ المعالجة الأولى من معلمة قابلة للضبط، بل من حذف الأشياء. تكون snapshots القديمة السبب المعتاد على خادم ZFS، تليها صور Docker وطبقاتها التي لم يحذفها أحد وحزم kernel التي خلّفتها عمليات الترقية. شغّل zfs list -o space قبل أن تلمس أي شيء آخر، لأنه يفصل المساحة التي تحتفظ بها snapshots عن المساحة التي تستخدمها البيانات الحية.

ثم تأتي المعلمات، باختصار. في Linux، يمكنك قراءة القيم الحالية:

cat /sys/module/zfs/parameters/zfs_scrub_min_time_ms
cat /sys/module/zfs/parameters/zfs_vdev_scrub_max_active

يتيح FreeBSD المعلمات نفسها عبر sysctl، لذا اعثر على قيمك باستخدام sysctl -a | grep scrub. يؤدي رفعها إلى إنهاء الفحص بسرعة أكبر، لكنه يجعل تطبيقك أبطأ. ويؤدي خفضها إلى العكس. في pool تحتوي على جهاز أو جهازين، لا يمنحك أي إعداد النتيجتين معاً، لأن هناك queue واحدة فقط لتقسيمها. نادراً ما تصلح معلمة مشكلة في التصميم. إذا كان الفحص الشهري يسبب بطئاً، فالاستنتاج الصريح هو أن pool ممتلئة أكثر من اللازم أو أن الجهاز بطيء جداً، وأن المعلمة القابلة للضبط لا تفعل سوى نقل المشكلة.

وقت scrub هو المعاينة الفعلية لوقت resilver

ينفّذ resilver عملية المرور نفسها التي ينفّذها scrub: يقرأ الكتل المخصّصة، ويتحقق منها، ويكتب الكتل المفقودة إلى الجهاز البديل. لذلك فإن المدة التي يستغرقها scrub هي أقرب تقدير واقعي للمدة التي سيستغرقها rebuild، وللمدة التي سيعمل خلالها الـpool بتكرار منخفض أثناء ذلك.

يجدول ZFS مهام resilver بجدولة أكثر نشاطاً من مهام scrub، لذلك يكتمل rebuild عادةً أسرع من scrub للـpool نفسه. اعتبر مدة scrub حداً أعلى محافظاً. إذا استغرق scrub تسع ساعات، فخطط لنافذة rebuild بهذه المدة تقريباً، واعلم أن تعطل جهاز ثانٍ خلال هذه النافذة يؤدي إلى فقدان الـpool. وهذا هو السبب العملي لاختيار أزواج mirrored بدلاً من مجموعة raidz عريضة واحدة، لأن raidz، وهو تخطيط parity الذي يستخدمه ZFS بديلاً عن RAID 5، ينفّذ rebuild بقراءة كل جهاز ما زال يعمل.

في الـpool الذي يتكون من جهاز واحد، لا يحدث resilver إطلاقاً. إذا تعطل الجهاز، يتعطل الـpool معه. وقت الاستعادة لديك هو وقت restore، لذا قِس عملية restore بدلاً من ذلك. عملية restore لم تنفّذها من قبل ليست خطة استعادة.

ما الذي يتغير عند استئجار القرص

في VPS، يكون جهاز الكتل افتراضياً. يعرض برنامج Hypervisor وحدة تخزين، وقد تكون هذه الوحدة في الطبقة الأساسية على NVMe محلي أو على وحدة تخزين شبكية مكررة لها آلية parity خاصة بها. وينتج عن ذلك أثران على عمليات scrub.

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

ثانياً، لا يمكنك عادةً قراءة بيانات SMART (تقنية المراقبة والتحليل والإبلاغ الذاتي) للجهاز الموجود أسفل القرص الافتراضي. لذلك قد لا تتوفر إطلاقاً الإنذارات المبكرة التي يعتمد عليها مراقبة سلامة الأقراص على VPS. يصبح عداد CKSUM الناتج عن عمليات scrub الإشارة الرئيسية التي يمكنك مراقبتها.

إذا أردت أن يُصلح ZFS الأخطاء بدلاً من الإبلاغ عنها فقط، فيجب أن يحتوي التجمع على أكثر من جهاز واحد داخل المثيل نفسه. وهذا قرار متعلق بالخطة، وليس إعداداً قابلاً للضبط. يوفّر اختيار VPS للتخزين بدلاً من VPS عادي السعة المطلوبة، لكن توفر جهازين مستقلين يعتمد على الخطة. شغّل lsblk وتحقق من ذلك قبل إنشاء mirror تكتشف لاحقاً أنه مبني على شريحتين من وحدة تخزين واحدة. نحن نؤجر خوادم Linux وFreeBSD، ولسنا جهاز ZFS مُداراً. لذلك تقع عليك مسؤولية تشغيل جدول scrub والنسخ الاحتياطية. هذه هي المقايضة: تحكم كامل في التجمع، وملكية كاملة لصيانته.

FAQ

كم مرة ينبغي أن أجري scrub على مجموعة ZFS في VPS؟

يكفي إجراء scrub شهرياً لمعظم المجموعات الصغيرة، وهذا يتوافق مع الإعدادات الافتراضية للحزم: مهمة cron في ثاني يوم أحد من الشهر على Debian وUbuntu، وحدّ افتراضي مدته 35 يوماً في نظام periodic على FreeBSD. يكون الإجراء الأسبوعي مناسباً فقط بعد قياس مدة scrub والتأكد من اكتماله بسرعة على خادم خامل في بقية الوقت. في مجموعة مزدحمة تضم جهازاً أو جهازين، يستهلك scrub الأسبوعي عمليات إدخال وإخراج حقيقية للتطبيق كل أسبوع، ولا يوفر سوى بضعة أسابيع من الإنذار المبكر الإضافي.

هل إجراء scrub على مجموعة ZFS ذات قرص واحد عديم الفائدة؟

لا، ما دمت تعرف ما الذي يقدمه. عند عدم وجود تكرار، يكتشف scrub التلف ولا يستطيع إصلاحه، باستثناء بيانات التعريف التي يحتفظ ZFS بنسخة إضافية منها افتراضياً. ما تحصل عليه هو قائمة بأسماء الملفات التالفة في zpool status -v، وذلك في وقت مبكر بما يكفي لاستعادتها ما دامت نسخة سليمة منها موجودة في مكان آخر. الإجراء الصحيح هو تحسين النسخ الاحتياطية، لأن scrub يحدد لك الملف الذي يجب استعادته بالضبط.

هل يمكنني إيقاف scrub مؤقتاً وإكماله لاحقاً؟

نعم. يوقفه zpool scrub -p tank مؤقتاً، وتُكتب حالة الإيقاف المؤقت والتقدم على القرص دورياً، لذلك يظل scrub متوقفاً مؤقتاً بعد إجراء export أو إعادة التشغيل. شغّل zpool scrub tank مرة أخرى لاستئنافه من آخر نقطة تحقق. لا تستخدم zpool scrub -s tank لهذا الغرض: إذ يوقف -s عملية scrub، وتبدأ العملية التالية من البداية.

لماذا يستغرق scrub في ZFS وقتاً طويلاً، وهل يمكنني تسريعه؟

ترتبط مدة scrub بالبيانات المخصّصة وتجزئتها، لا بسعة القرص. تكون المجموعة التي تجاوز امتلاؤها 90% بطيئة لأن metaslabs التي تقل المساحة الحرة فيها عن 4% تدفع المخصّص من استراتيجية first-fit إلى best-fit، ويحوّل التفتت الناتج scrub إلى عدد كبير من عمليات القراءة الصغيرة. يساعد تحرير المساحة عادةً أكثر من أي إعداد قابل للضبط. يمكنك رفع zfs_scrub_min_time_ms أو zfs_vdev_scrub_max_active لمنح scrub حصة أكبر من قائمة الانتظار، لكن هذه الحصة تُقتطع مباشرة من تطبيقاتك في المجموعة التي تضم جهازاً أو جهازين.