مقالات معمّقة حول التكنولوجيا التي تشكّل المستقبل.

هندسة البرمجيات حين لا تستطيع إعادة تشغيل الخادم

البرمجيات الفضائية لا تفشل بسلاسة. تعرّف على كيفية كتابة المهندسين للكود لأنظمة يعني فيها الخلل خسارة مهمة بمليار دولار، وإعادة التشغيل تستغرق ساعات.

مركبة فضائية منفردة مغطاة بالدوائر تدور حول كوكب أحمر بعيدًا عن الأرض

يتعطل خادم الويب لديك الساعة 3 فجرًا. يعيد Kubernetes تشغيله. يرى المستخدمون صفحة خطأ قصيرة. لا أحد يُفصل من عمله. الآن تخيّل أن خادمك يدور حول المريخ، وإعادة التشغيل تستغرق 45 دقيقة (وخلالها لا يوجد تحكم في الوضعية، ولا تنظيم حراري، ولا اتصال)، و«المستخدم» مركبة فضائية بقيمة 2.5 مليار دولار، ولا يوجد Kubernetes أصلًا، فقط كودك والمعالج المقاوم للإشعاع الذي يعمل عليه.

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

القيود التي تشكّل كل شيء

الإشعاع. في الفضاء، تقصف الجسيمات عالية الطاقة الإلكترونيات باستمرار. جسيم واحد قد يقلب بتًا في الذاكرة (ما يُسمى single-event upset أو SEU)، أو يُفسد سجلًا، أو يتسبب في تجمّد المعالج. وهذا ليس نادرًا، فأقمار LEO الصناعية تتعرض لآلاف قلب البتات يوميًا. لذلك يستخدم العتاد المخصص للفضاء مكونات مقاومة للإشعاع، وهي أبطأ وأغلى وأقدم بأجيال من العتاد الاستهلاكي. المعالج في مركبة Mars Perseverance هو RAD750، وهو تقريبًا بمستوى PowerPC من عام 1998 يعمل بتردد 200 ميغاهرتز.

تأخّر الاتصال. يبعد المريخ من 4 إلى 24 دقيقة بالراديو (حسب موقعه المداري). ويبعد المشتري من 33 إلى 54 دقيقة. وهذا ليس مجرد زمن استجابة، بل يعني أن المركبة يجب أن تتعامل مع أي مشكلة بشكل ذاتي لمدة زمن الذهاب والإياب على الأقل، قبل أن يتمكن مركز التحكم الأرضي من رؤية المشكلة، فضلًا عن إرسال أمر. وعندما واجهت مسابير فوياجر شذوذًا على بُعد أكثر من 22 ساعة ضوئية من الأرض، اتخذت البرمجيات قراراتها بنفسها لما يقارب يومين.

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

كيف يختلف كود الفضاء

تستخدم البرمجيات الفضائية تقنيات تُعدّ في تطوير البرمجيات العادي إفراطًا هندسيًا لا معنى له.

التكرار الثلاثي المعياري (TMR). تُنفَّذ الحسابات الحرجة ثلاث مرات على ثلاثة معالجات مستقلة. ويقارن «مُحكِّم» النتائج الثلاث ويعتمد الإجابة الأغلبية. إذا أعطى أحد المعالجات إجابة خاطئة بسبب الإشعاع، يتغلب عليه الاثنان الآخران بالتصويت. وبعض الأنظمة تشغّل خمس نسخ (التكرار الخماسي) لمزيد من الاطمئنان.

تنظيف الذاكرة (Memory scrubbing). عملية خلفية تقرأ الذاكرة باستمرار، وتتحقق منها عبر رموز تصحيح الأخطاء (ECC)، وتصلح أخطاء البت الواحد قبل أن تتراكم لتصبح أخطاء متعددة البتات لا يمكن تصحيحها. وتعمل هذه العملية باستمرار، إذ يُفحص كل بايت في الذاكرة ويُصحَّح عدة مرات في الثانية.

مؤقتات المراقبة (Watchdog timers). مؤقتات عتادية يجب أن تُعاد تهيئتها دوريًا من البرنامج. إذا تجمّد البرنامج (ربما بسبب توقف ناجم عن الإشعاع)، ينتهي المؤقت ويُطلق إعادة تشغيل عتادية. ولذلك يجب تصميم البرنامج ليتحمل إعادة التشغيل غير المتوقعة في أي لحظة من تنفيذه، فأي حساب قد يُقاطَع ويُعاد من جديد.

// Simplified space software patterns
// Watchdog — must be kicked regularly or hardware resets
void main_loop(void) {
while (1) {
kick_watchdog();  // Reset the timer — we're alive
// All operations must complete within watchdog timeout
read_sensors();
kick_watchdog();
run_attitude_control();
kick_watchdog();
check_thermal_limits();
kick_watchdog();
process_ground_commands();
kick_watchdog();
}
}
// Critical value stored with redundancy
typedef struct {
int32_t value_a;  // Primary copy
int32_t value_b;  // Redundant copy
int32_t value_c;  // Third copy for voting
} RedundantInt;
int32_t read_redundant(RedundantInt *r) {
// Majority vote — tolerates one corrupted copy
if (r->value_a == r->value_b) return r->value_a;
if (r->value_a == r->value_c) return r->value_a;
if (r->value_b == r->value_c) return r->value_b;
// All three differ — flag anomaly
raise_anomaly(MEMORY_CORRUPTION);
return r->value_a;  // Best guess
}

الاختبار هو المنتج

يقدّر مختبر الدفع النفاث التابع لناسا (JPL) أن اختبار البرمجيات الفضائية يستهلك 60 إلى 80% من إجمالي جهد التطوير. ليس 60% من الوقت، بل 60% من التكلفة الإجمالية. والاختبار أغلى من التطوير نفسه، لأن عليه أن يُثبت الصحة بدرجة لا يقترب منها اختبار البرمجيات العادي.

يجب اختبار كل مسار تنفيذي. ليس «تغطية عالية للكود» بالمعنى الذي يقصده مطورو الويب، بل كل مسار حرفيًا عبر كل دالة، بما فيها مسارات الأخطاء، ومسارات انتهاء المهلة، والمسارات التي تتعامل مع أعطال العتاد. تغطية الفروع بنسبة 100% هي نقطة البداية، لا الهدف.

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

يزداد استخدام التحقق الرسمي (Formal verification) للمكونات الأكثر حرجًا. فبدلًا من اختبار أن الكود يعمل مع مدخلات محددة، يثبت التحقق الرسمي رياضيًا أن الكود يعمل مع كل المدخلات الممكنة. وهو مكلف وبطيء، لكن بالنسبة للكود الذي يتحكم في وضعية المركبة (اتجاهها) أو يدير الدفع، فالتكلفة مبررة.

ما الذي يسوء رغم ذلك

رغم هذه الصرامة، تفشل البرمجيات الفضائية. والإخفاقات مفيدة للتعلّم لأنها تكشف حدود أدق الهندسة.

  • Mars Climate Orbiter (1999) تحطّم لأن فريقًا استخدم الوحدات الإمبراطورية وفريقًا آخر استخدم المترية. كان البرنامج صحيحًا، لكن المتطلبات كانت خاطئة. لا يوجد اختبار يلتقط مواصفة خاطئة.
  • Ariane 5 Flight 501 (1996) انفجر لأن قيمة عشرية بدقة 64 بت حُوّلت إلى عدد صحيح بـ16 بت فحدث فيض. أُعيد استخدام الكود من Ariane 4، حيث لم تتجاوز القيمة نطاق 16 بت أبدًا. كان الكود صحيحًا لـAriane 4 وخاطئًا بشكل كارثي لـAriane 5.
  • Mars Polar Lander (1999) على الأرجح تحطّم لأن اهتزاز مستشعر أثناء نشر الأرجل فُسِّر خطأً على أنه ملامسة للأرض، فأُوقفت المحركات على ارتفاع 40 مترًا. مشكلة في تفسير المستشعر المرتبط بالتوقيت لم يكتشفها الاختبار لأن الاختبار لم يحاكِ خصائص الاهتزاز بدقة.
  • العيب الأولي في مرآة هابل (1990) لم يكن خطأ برمجيًا، بل صُقلت المرآة بشكل خاطئ بسبب أداة قياس مُعايَرة بشكل غير صحيح. وكانت أداة الاختبار نفسها تحتوي على خلل.

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

ماذا تستطيع برمجيات الأرض أن تتعلم

معظمنا لا يكتب برمجيات فضائية. لكن بعض هذه الممارسات تنتقل مباشرة إلى بناء أنظمة موثوقة على الأرض.

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

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

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

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

البرمجيات الفضائية الجديدة

تتحدى صناعة الفضاء التجارية (SpaceX وRocket Lab وPlanet) بعض هذه الأعراف. تستخدم SpaceX نظام Linux ولغة C++ في حواسيب رحلات Falcon 9، وهو ما يُعد هرطقة وفق معايير صناعة الطيران التقليدية. وتشغّل Planet Labs مئات الأقمار الصناعية الصغيرة وتتعامل معها كنظام موزّع أكثر من كونها عتادًا مفصلًا: إذا تعطّل قمر، تعوّض الكوكبة ذلك.

يعكس هذا التحول سؤالًا أوسع: ما مقدار الموثوقية التي تحتاجها فعلًا؟ مركبة مريخية بقيمة 2.5 مليار دولار تبرر خمس سنوات من الاختبار. أما قمر اتصالات بقيمة 500 ألف دولار، وهو واحد من مئات في كوكبة، فيبرر أقل بكثير. يجب أن تتناسب الممارسة الهندسية مع ملف المخاطر، لا أن تتبع التقاليد الموضوعة لحقبة مختلفة دون تفكير.

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