استعادة ند ADAMANT بعد انقطاع الشبكة: العقد الأولية، والكشف، واختيار المزامنة
تحافظ عقد ADAMANT على الاتصال بالشبكة من خلال ثلاث آليات منفصلة يسهل الخلط بينها عند قراءة سجلات وحدة التحكم بعد انقطاع الشبكة. تشرح هذه الملاحظة كيفية تفاعل هذه الآليات، ولماذا قد تتوقف المزامنة حتى مع استمرار الاتصال بالعقد الأولية (seed peers)، وما ينبغي أن يتوقعه المشغلون أثناء عملية الاستعادة.
الخلفية
تحتفظ العقدة بجدول مؤقت للأقران (peer table) يتم تعبئته من ثلاث مصادر: الأقران الأولية المدرجة في ملف التهيئة peers.list، والأقران المحفوظة التي تُحمَل من قاعدة البيانات عند التشغيل، والأقران المكتشفين الذين تُسترجع عناوينهم من عقد أخرى عبر الطلب GET /peer/list. العقد الأولية مجمدة — فهي لا تُحذف أبدًا من الجدول، حتى لو فشلت طلبات الاتصال بها.
كل قِران له حالة: BANNED (0، مستبعد من الاستخدام العادي)، أو DISCONNECTED (1، معروف ولكن غير قابل للاستخدام حاليًا للمزامنة أو البث)، أو CONNECTED (2، استجاب بنجاح مؤخرًا ويُعتبر مؤهلًا للمزامنة). عند فشل الطلب، تنخفض نسبة نجاح القِران. وعندما ينخفض معدل نجاح قِران كان في حالة CONNECTED إلى أقل من 80٪، تُخفض حالته إلى DISCONNECTED. فشل الاتصال بسبب انتهاء المهلة (ECONNABORTED) لا يؤدي إلى حذف القِران؛ بل يقلل فقط من معدل النجاح.
ثلاث آليات متوازية
التحقق من العقد الأولية (هادئ). عند التشغيل، وكل ~5 ثوانٍ، تقوم العقدة بإرسال طلب PING إلى كل قِران أولي مذكور في التهيئة عبر GET /peer/height. تسجَّل حالات الفشل على مستوى trace، وغالبًا ما تكون غير مرئية في مخرجات وحدة التحكم الافتراضية. يُعيد الاتصال الناجح ترقية القِران إلى الحالة CONNECTED.
اكتشاف الأقران (صاخب). كل ~5 ثوانٍ، تختار العقدة قِرانًا عشوائيًا واحدًا من الذاكرة (سواء كان بحالة DISCONNECTED أو CONNECTED) وتطالب بـ GET /peer/list لاكتشاف عناوين جديدة. إذا انتهت مهلة اختيار هذا القِران العشوائي الواحد، تظهر في وحدة التحكم الرسالة التالية:
Discovering new peers failed. ECONNABORTED Request failed GET http://<peer>/peer/list
يُشير هذا الخطأ فقط إلى القِران المختار عشوائيًا، وليس إلى جدول الأقران بالكامل. أثناء الاستعادة، غالبًا ما تظهر عقد سحابية لم تكن معروفة جيدًا وقد تم اكتشافها مسبقًا وحفظها في قاعدة البيانات. هذا لا يعني أن العقدة تتجاهل العقد الأولية.
مزامنة الكتلة (صارمة). يستخدم مسار التحميل (loader) الدالة peers.list() مع عامل التصفية الافتراضي: الأقران في حالة CONNECTED فقط. إذا لم يكن هناك قِران حالي في حالة CONNECTED وله ارتفاع (height) قابل للاستخدام، فإن المزامنة تنتهي بالرسالة التالية:
Failed to find enough good peers
في هذه الحالة، لا تكون العقدة منفصلة عن الشبكة بمعنى عدم وجود سجلات أقران، بل ببساطة ليس لديها أي أقران نشطة مناسبة لتنزيل الكتل.
الجدول الزمني النموذجي للانقطاع
عند حدوث انقطاع في الشبكة، تبدأ طلبات HTTP إلى جميع الأقران بالفشل. تتحول الأقران التي كانت في حالة CONNECTED إلى DISCONNECTED، ولا يستطيع المحمل اختيار أقران جيدين، وبالتالي يتوقف الارتفاع (height) عن التقدم. تستمر أخطاء اكتشاف الأقران في الظهور ضد إدخالات قديمة عشوائية، بينما تعمل عمليات التحقق من العقد الأولية بهدوء في الخلفية. بمجرد أن يستجيب قِران أولي أو قِران معروف آخر بنجاح لطلب ping، يعود إلى الحالة CONNECTED وتستأنف المزامنة.
قد تستغرق الفترة بين “عودة الإنترنت” و”استئناف العقدة للمزامنة” عدة دقائق — أو أكثر إذا كانت العقد البعيدة لا تزال غير قابلة للوصول — لأن الاستعادة تعتمد على استجابة ناجحة من قِران يصبح في حالة CONNECTED، وليس فقط على استعادة الاتصال المحلي.
توقعات المشغلين
رؤية أخطاء اكتشاف ضد عناوين غير مألوفة بعد انقطاع الشبكة أمر طبيعي، ولا يدل بحد ذاته على خطأ في التهيئة. لا تزال العقد الأولية من ملف التهيئة تُستدعى؛ ببساطة، لا تظهر أخطاء التحقق منها بوضوح في السجلات الافتراضية. رسالة Failed to find enough good peers تعني عدم وجود أقران نشطة حاليًا، وليس أن جدول الأقران قد تم مسحه. إعادة تشغيل العقدة تعيد تحميل العقد الأولية والأقران من قاعدة البيانات، لكن الاستعادة ما زالت تتطلب استجابة قِران بعيد واحد على الأقل.
تحسينات محتملة
يمكن لعدة تغييرات تحسين تجربة المشغل: تسجيل أخطاء التحقق من العقد الأولية بمستوى warn عندما لا تبقى أي أقران في حالة CONNECTED لأكثر من فترة معينة، أو تفضيل العقد الأولية أو الأقران التي عملت مؤخرًا في الدالة getFromRandomPeer بدلًا من الاختيار العشوائي الموحّد، أو إعادة محاولة جميع العقد الأولية بشكل متوازٍ عندما تُبلغ المزامنة برسالة Failed to find enough good peers، أو تقليل أسطر التحذير المكررة عندما تستنفد async.retry جميع محاولات المزامنة.