SnowFlock

معمارية تطبيقات المصادر المفتوحة (المجلد الأول)SnowFlock

معمارية تطبيقات المصادر المفتوحة (المجلد الأول) SnowFlock

Roy Bryant و Andrés Lagar-Cavilla

إذا استمتعت بهذه الكتب، فقد يعجبك أيضًا التصميم البرمجي بالأمثلة في بايثون (Software Design by Example in Python) والتصميم البرمجي بالأمثلة في جافاسكربت (Software Design by Example in JavaScript).

الحوسبة السحابية توفّر منصة حوسبة جذّابة من حيث تكلفتها المنخفضة. فبدلًا من شراء خادم فعلي وضبطه — بكل ما يستتبعه من وقت وجهد وتكاليف مسبقة — يمكن للمستخدمين استئجار «خوادم» في السحابة بنقرات قليلة من الفأرة مقابل أقل من عشرة سنتات في الساعة. وتحافظ مزوّدو السحابة على تكاليفهم المنخفضة عبر توفير أجهزة افتراضية (virtual machines, VMs) بدلًا من الحواسيب الفيزيائية. والمحرّك الأساسي هنا هو برمجيات المحاكاة الافتراضية، وتُسمّى مراقب الآلة الافتراضية (virtual machine monitor, VMM)، التي تحاكي آلة فيزيائية. ويُعزل المستخدمون بأمان تام داخل أجهزتهم الافتراضية «الضيوف»، ولا يعلمون البتة أنهم عادةً يتشاركون الآلة الفيزيائية («المضيف») مع كثيرين غيرهم.

18.1. تقديم SnowFlock

السحابة هبة للمؤسسات الرشيقة (agile). ومع الخوادم الفيزيائية، لا يملك المستخدمون سوى الانتظار بصبر نافد بينما يوافق آخرون (ببطء) على شراء الخادم، ويضعون الطلب، ويشحنون الخادم، ويثبّتون نظام التشغيل (Operating System, OS) وحِزم التطبيقات ويضبطونها. وبدلًا من انتظار أسابيع حتى ينجز الآخرون التسليم، يبقى المستخدم السحابي مسيطرًا على العملية ويستطيع إنشاء خادم مستقل جديد في دقائق.

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

يعالج SnowFlock هذه المشكلات عبر استنساخ الآلات الافتراضية (VM Cloning)، وهو استدعاء لواجهة برمجية (API) سحابية نقترحه. وبالطريقة نفسها التي تستدعي بها شيفرة التطبيق خدمات نظام التشغيل عبر واجهة استدعاء النظام (syscall)، بات بإمكانه الآن استدعاء خدمات السحابة عبر واجهة مماثلة. وبفضل VM Cloning في SnowFlock، يمكن مزج تخصيص الموارد وإدارة العنقود ومنطق التطبيق برمجيًا ومفعالجتها كعملية منطقية واحدة.

ينشئ استدعاء VM Cloning عدة خوادم سحابية، وهي نسخ مطابقة تمامًا من الآلة الافتراضية الأم حتى لحظة الاستنساخ. ومن الناحية المنطقية، ترث النسخ (clones) كامل حالة أصلها، بما في ذلك ذواكر التخزين المؤقت (caches) على مستوى نظام التشغيل وعلى مستوى التطبيق. وإضافةً إلى ذلك، تُضاف النسخ تلقائيًا إلى شبكة داخلية خاصة، فتنضم بذلك فعليًا إلى عنقود قابل للتوسّع ديناميكيًا. ويمكن إنشاء موارد حوسبة جديدة، مغلَّفةً في أجهزة افتراضية متطابقة، أثناء التشغيل واستخدامها ديناميكيًا حسب الحاجة.

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

مع واجهة برمجية للتحكم البرمجي في VM Cloning، مع روابط ربط (bindings) بـ C وC++ وPython وJava، أصبح SnowFlock مرنًا ومتعدد الاستخدامات إلى حد بعيد. وقد استخدمنا SnowFlock بنجاح في تطبيقات نموذجية لعدّة أنظمة مختلفة إلى حد كبير. وفي سيناريوهات الحوسبة المتوازية، حققنا نتائج ممتازة عبر استنساخ صريح لأجهزة افتراضية عاملة توزّع الحمل تعاونيًا على مضيفات فيزيائية كثيرة. أما التطبيقات المتوازية التي تستخدم واجهة تمرير الرسائل (Message Passing Interface, MPI) وتعمل عادةً على عنقود من خوادم مخصّصة، فقد عدّلنا مدير بدء التشغيل الخاص بـ MPI لتوفير أداء جيد وحِمل إضافي أقل بكثير للتطبيقات دون تعديل، عبر تجهيز عنقود جديد من النسخ عند الطلب في كل تشغيل. وأخيرًا، في حالة استخدام مختلفة تمامًا، استخدمنا SnowFlock لتحسين كفاءة وأداء الخوادم المرنة (elastic). فخوادم اليوم المرنة المستندة إلى السحابة تُشغّل عمّالًا جددًا «باردين» حسب الحاجة لخدمة القفزات الحادة في الطلب. وباستنساخ آلة افتراضية قيد التشغيل بدلًا من ذلك، يضع SnowFlock العمال الجدد في الخدمة أسرع بـ 20 مرة، ولأن النسخ ترث المخازن الدافئة (warm buffers) لأصلها، فإنها تبلغ ذروة أدائها في وقت أقرب.

18.2. استنساخ الآلات الافتراضية

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

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

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

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

وبالمناسبة، إن كنت ملمًّا بمفاهيم الآلات الافتراضية، فأنت على الأرجح تتساءل إن كانت تحسينات الترحيل «الحي» (live migration) مفيدة هنا. فالترحيل الحي مضبوط لتقليص الفاصل الزمني بين تعليق الآلة الافتراضية الأصلية واستئناف تنفيذ النسخة الجديدة. ولتحقيق ذلك، ينسخ مراقب الآلة الافتراضية (Virtual Machine Monitor, VMM) حالة الآلة مسبقًا بينما ما زالت الأصلية قيد التشغيل، بحيث لا يلزم سوى نقل الصفحات التي تغيّرت حديثًا بعد تعليقها. وهذه التقنية لا تؤثر على الفاصل الزمني بين طلب الترحيل ولحظة بدء النسخة تنفيذها، وبالتالي فإنها لن تقلّل زمن الاستجابة في النسخ الفوري للآلة الافتراضية.

18.3. مقاربة SnowFlock

ينفّذ SnowFlock استنساخ الآلات الافتراضية عبر بدائية تُسمّى «VM Fork»، وهي أشبه بـ fork القياسية في يونكس، لكن مع فروق مهمة قليلة. أولًا، وبدلًا من تكرار عملية واحدة، تنسخ VM Fork آلة افتراضية كاملة، بما في ذلك كامل الذاكرة وجميع العمليات والأجهزة الافتراضية ونظام الملفات المحلي. ثانيًا، وبدلًا من إنتاج نسخة واحدة تعمل على المضيف الفيزيائي نفسه، تستطيع VM Fork أن تولّد نسخًا كثيرة بالتوازي في وقت واحد. وأخيرًا، يمكن تفريع الآلات الافتراضية إلى خوادم فيزيائية متمايزة، مما يتيح لك توسيع حضورك على السحابة بسرعة كلما احتجت.

المفاهيم التالية هي مفاتيح SnowFlock:

  • المحاكاة الافتراضية (Virtualization): تغليف الآلة الافتراضية لبيئة الحوسبة، مما يجعل السحب واستنساخ الآلات ممكنين.
  • الانتشار الكسول (Lazy Propagation): لا تُنسخ حالة الآلة الافتراضية حتى الحاجة، لذا تعمل النسخ خلال ثوانٍ قليلة.
  • البثّ المتعدد (Multicast): تحتاج النسخ الشقيقة إلى حالات متشابهة من حالة الآلة الافتراضية. ومع البث المتعدد، تبدأ عشرات النسخ العمل بسرعة نسخة واحدة.
  • أعطال الصفحات (Page Faults): عندما تحاول نسخة استخدام ذاكرة مفقودة، يقع عطل ويطلق طلبًا إلى الأصل. ويتوقف تنفيذ النسخة حتى تصل الصفحة المطلوبة.
  • النسخ عند الكتابة (Copy on Write, CoW): بأخذ نسخة من صفحات ذاكرتها وقرصها قبل الكتابة فوقها، تستطيع الآلة الافتراضية الأم مواصلة التشغيل مع الاحتفاظ بنسخة مجمّدة من حالتها لاستخدامها من قِبل النسخ.

نفّذنا SnowFlock باستخدام نظام المحاكاة الافتراضية Xen، لذا من المفيد تقديم بعض المصطلحات الخاصة بـ Xen من أجل الوضوح. في بيئة Xen، تُسمّى VMM هنا الناظر الفائق (hypervisor)، وتُسمّى الآلات الافتراضية «نطاقات» (domains). وعلى كل آلة فيزيائية (مضيف) يوجد نطاق مميّز، يُسمّى «النطاق 0» (domain 0, dom0)، يملك صلاحية كاملة على المضيف وأجهزته الفيزيائية، ويمكن استخدامه للتحكم في آلات افتراضية ضيفة إضافية، أو «مستخدمة»، تُسمّى «النطاق U» (domain U, domU).

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

  • وصف الآلة الافتراضية (VM Descriptor): يُستخدم هذا الكائن الصغير كبذرة للنسخة، ويحمل الهيكل المجرّد للآلة الافتراضية بما يلزم لبدء التنفيذ. وهو ينقصه كل ما يلزم من قوة لأداء عمل مفيد.
  • نظام التوزيع بالبث المتعدد (mcdist): يوزّع هذا النظام الموجود في جانب الأصل معلومات حالة الآلة الافتراضية بكفاءة إلى جميع النسخ في وقت واحد.
  • عملية خادم الذاكرة (Memory Server): تحافظ هذه العملية الموجودة في جانب الأصل على نسخة مجمّدة من حالة الأصل، وتتيحها لجميع النسخ عند الطلب عبر mcdist.
  • عملية Memtap: تعمل هذه العملية الموجودة في جانب النسخة نيابةً عن النسخة، وتتواصل مع خادم الذاكرة لطلب الصفحات المطلوبة والمفقودة.
  • استنارة النسخ (Clone Enlightenment): تستطيع نواة الضيف التي تعمل داخل النسخ تخفيف النقل عند الطلب لحالة الآلة الافتراضية عبر تقديم تلميحات إلى VMM. وهذه الخطوة اختيارية لكنها مرغوبة بشدة لسبب الكفاءة.
  • حزمة التحكم (Control Stack): تعمل الخدمات الخفية (daemons) على كل مضيف فيزيائي لتنسيق بقية المكوّنات وإدارة آلات SnowFlock الأم وآلاتها المنسوخة.

بنية نسخ الآلات الافتراضية في SnowFlock

الشكل 18.1: بنية نسخ الآلات الافتراضية في SnowFlock

وقصريًا، يوضّح الشكل 18.1 عملية استنساخ آلة افتراضية، مبينًا الخطوات الرئيسية الأربع: (1) تعليق الآلة الافتراضية الأم لإنتاج وصف معماري؛ (2) توزيع هذا الوصف على جميع المضيفات الهدف؛ (3) إطلاق نسخ تكون فارغة في معظمها من حيث الحالة؛ و(4) نشر الحالة عند الطلب. ويوضّح الشكل أيضًا استخدام التوزيع بالبث المتعدد عبر mcdist، وتجنّب الجلب بواسطة استنارة الضيف.

إن كنت مهتمًا بتجربة SnowFlock، فله نسختان. التوثيق والشيفرة مفتوحة المصدر لمشروع SnowFlock البحثي الأصلي في جامعة تورونتو متاحان[1]. وإذا كنت تفضّل تجربة النسخة ذات القوة الصناعية، فترخيص مجاني غير تجاري متاح من GridCentric Inc.[2]. ولأن SnowFlock يتضمّن تغييرات على الناظر الفائق ويتطلب الوصول إلى dom0، فإن تثبيته يتطلب صلاحيات مميّزة على الأجهزة الحاضنة. ولهذا السبب ستحتاج إلى استخدام عتادك الخاص، ولن تتمكّن من تجربته كمستخدم في بيئة سحابية تجارية مثل Amazon's EC2.

سنصف في الأقسام التالية بضع القطع المختلفة التي تتعاون لتحقيق استنساخ فوري وفعّال. وتتلاءم كل القطع التي سنتناولها معًا كما يوضّح الشكل 18.2.

المكوّنات البرمجية لـ SnowFlock

الشكل 18.2: المكوّنات البرمجية لـ SnowFlock

18.4. الوصف المعماري للآلة الافتراضية

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

الخطوة الأولى لتنفيذ هذا القرار التصميمي هي توليد وصف معماري (architectural descriptor) لحالة الآلة الافتراضية. وهذه هي البذرة التي ستُستخدم لإنشاء نسخ الآلات الافتراضية. وهي تحتوي على أدنى حد لازم لإنشاء آلة افتراضية وجعلها قابلة للجدولة. وكما يوحي الاسم، فإن هذا أدنى حد يتكوّن من بنى البيانات التي تتطلبها المواصفة المعمارية الأساسية. وفي حالة SnowFlock، تجمع المعمارية بين متطلبات معالج Intel x86 ومتطلبات Xen. ووصف المعماري يحتوي بالتالي على بنى بيانات مثل جداول الصفحات والسجلات الافتراضية وبيانات تعريف الأجهزة والطوابع الزمنية وغيرها. ونحيل القارئ المهتم إلى LCWB+11 للحصول على وصف معمّق لمحتويات الوصف المعماري.

للوصف المعماري ثلاث خصائص مهمة: الأولى، أنه يمكن إنشاؤه في زمن قصير؛ فمئتا جزء من الثانية ليس أمرًا غير معتاد. والثانية، أنه صغير، إذ يكون أصغر عادةً بثلاث رتب عشرية من تخصيص ذاكرة الآلة الافتراضية الأصل (1 ميغابايت لآلة افتراضية بحجم 1 غيغابايت). والثالثة، أنه يمكن إنشاء آلة افتراضية منسوخة من الوصف في أقل من ثانية (عادةً 800 جزء من الثانية).

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

18.5. مكوّنات جانب الأصل

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

18.5.1. عملية Memserver

عند إنشاء الوصف المعماري، تتوقّف الآلة الافتراضية تمامًا في مكانها طوال العملية. والسبب في ذلك هو أن تستقر حالة ذاكرة الآلة الافتراضية؛ فقبل أن تُوقَف الآلة فعليًا وتُجدول خارج التنفيذ، تهدأ مشغّلات نظام التشغيل الداخلية إلى حالة يمكن منها للنسخ أن تعيد الاتصال بالعالم الخارجي داخل آلاتها الافتراضية الحاوية الجديدة. ونستفيد من هذه الحالة الساكنة لإنشاء «خادم ذاكرة»، أو memserver.

سيوفّر خادم الذاكرة لجميع النسخ البتات من الذاكرة التي تحتاجها من الأصل. وتُنقل الذاكرة بحجم صفحة ذاكرة x86 (4 كيلوبايت). وفي أبسط صوره، ينتظر خادم الذاكرة طلبات الصفحات من النسخ، ويخدم صفحة واحدة في كل مرة، ونسخة واحدة في كل مرة.

لكن هذه هي الذاكرة نفسها التي تحتاجها الآلة الافتراضية الأم لمواصلة التنفيذ. فلو سمحنا للأصل بأن يعدّل هذه الذاكرة من تلقاء نفسه، لَقُدِّمت للآلات الافتراضية المنسوخة محتويات ذاكرة تالفة: إذ ستختلف الذاكرة المخدومة عمّا كانت عليه لحظة الاستنساخ، وستُربك النسخ ارتباكًا شديدًا. وبمصطلحات هندسة النوى، هذه وصفة مضمونة لتكدّس آثار الاستدعاء (stack traces).

ولتفادي هذه المشكلة، يأتي مفهوم كلاسيكي في أنظمة التشغيل إلى النجدة: ذاكرة النسخ عند الكتابة (Copy-on-Write, CoW). وبمساعدة الناظر الفائق الخاص بـ Xen، يمكننا نزع صلاحية الكتابة من جميع صفحات الذاكرة في الآلة الافتراضية الأم. وعندما يحاول الأصل فعليًا تعديل صفحة ما، يُطلق عطل صفحة عتادي. ويعرف Xen سبب حدوث ذلك، فيُنشئ نسخة من الصفحة. ويُسمح للآلة الافتراضية الأم بالكتابة في الصفحة الأصلية ومواصلة التنفيذ، بينما يُبلَّغ خادم الذاكرة باستخدام النسخة المحفوظة للقراءة فقط. وبهذه الطريقة تبقى حالة الذاكرة عند لحظة الاستنساخ مجمّدة فلا تربك النسخ، بينما يظل الأصل قادرًا على مواصلة التنفيذ. وحِمل CoW ضئيل: فآليات مشابهة تستخدمها لينكس مثلًا عند إنشاء عمليات جديدة.

18.5.2. البثّ المتعدد عبر Mcdist

النسخ، عادةً، مصابة بمتلازمة وجودية تُعرف بـ«الحتمية المصيرية» (fate determinism). فنحن نتوقع أن تُنشأ النسخ لغرض واحد: مثلًا، لمطابقة (alignment) سلاسل X من الحمض النووي مقابل مقطع Y من قاعدة بيانات. وإضافةً إلى ذلك، نتوقع إنشاء مجموعة من النسخ بحيث يؤدي جميع الإخوة الشيء ذاته، ربما بمطابقة سلاسل X نفسها مقابل مقاطع مختلفة من قاعدة البيانات، أو مطابقة سلاسل مختلفة مقابل المقطع Y نفسه. وهكذا تُظهر النسخ بوضوح مقدارًا كبيرًا من الموضعية الزمنية (temporal locality) في وصولها إلى الذاكرة: فهي تستخدم الشيفرة نفسها وأجزاءً كبيرة من بيانات مشتركة.

نستثمر فرص الموضعية الزمنية عبر mcdist، وهو نظام التوزيع بالبث المتعدد الخاص بنا والمصمَّم خصيصًا لـ SnowFlock. ويستخدم Mcdist البثّ المتعدد عبر IP لتوزيع الحزمة نفسها في وقت واحد على مجموعة من المستقبِلين. وهو يستفيد من التوازي في عتاد الشبكة لخفض الحِمل الواقع على خادم الذاكرة. ومن خلال إرسال رد إلى جميع النسخ عند أول طلب لصفحة ما، تتحوّل طلبات كل نسخة إلى جلب مسبق (prefetch) لإخوتها، بسبب تشابه أنماط وصولها إلى الذاكرة.

على خلاف أنظمة البث المتعدد الأخرى، لا يلزم أن يكون mcdist موثوقًا، ولا يلزم أن يسلّم الحزم بترتيب معيّن، ولا يلزم أن يسلّم ردًا بشكل ذرّي إلى جميع المستقبِلين المقصودين. فالبث المتعدد تحسين خالص، ولا يلزم إلا ضمان التسليم إلى النسخة التي طلبت الصفحة صراحةً. والتصميم بالتالي بسيط ببراعة: لا يفعل الخادم سوى بثّ الردود، بينما تنتهي مهلة العملاء (time-out) إن لم يتلقَّوا ردًا على طلب ما، فيعيدون إرسال الطلب.

يتضمّن mcdist ثلاثة تحسينات خاصة بـ SnowFlock:

  • كشف التزامن (Lockstep Detection): عندما تقع الموضعية الزمنية بالفعل، تطلب عدة نسخ الصفحة نفسها في تتابع متقارب جدًا. ويتجاهل خادم mcdist جميع هذه الطلبات عدا أولها.
  • التحكم في التدفّق (Flow Control): يرفق المستقبِلون معدل استقبالهم بالطلبات. ويحدّ الخادم من معدل إرساله متبعًا متوسطًا مرجّحًا لمعدل استقبال العملاء. وإلا لغرِق المستقبِلون في كمٍّ هائل من الصفحات التي يرسلها خادم متعشّل.
  • النهاية (End Game): حين يكون الخادم قد أرسل معظم الصفحات، يعود إلى الردود أحادية الوجهة (unicast). ومعظم الطلبات في هذه المرحلة هي إعادة إرسال، ومن ثمّ فإن بثّ صفحة عبر الشبكة إلى جميع النسخ أمر غير ضروري.

18.5.3. القرص الافتراضي

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

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

18.6. مكوّنات جانب النسخة

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

18.6.1. عملية Memtap

تتكوّن عملية memtap، المرتبطة بكل نسخة بعد إنشائها، وهي شريان حياة النسخة. فهي تربط كل ذاكرة النسخة وتملؤها عند الطلب كلما لزم. وتستعين بمساعدة جوهرية من الناظر الفائق الخاص بـ Xen: إذ تُعطَّل صلاحية الوصول إلى صفحات ذاكرة النسخ، وتوجَّه الأعطال العتادية الناتجة عن أول وصول إلى صفحة من قِبل الناظر الفائق إلى عملية memtap.

في أبسط تجسّداتها، تكتفي عملية memtap بطلب الصفحة التي وقع فيها العطل من خادم الذاكرة، لكنّ هناك سيناريوهات أعقد أيضًا. أولًا، تستخدم مساعدات memtap‏ mcdist. وهذا يعني أن أي صفحة قد تصل في أي لحظة لمجرّد أنها طُلبت من نسخة أخرى—وهنا جمال الجلب المسبق اللامتزامن. ثانيًا، نسمح لآلات SnowFlock الافتراضية بأن تكون متعددة المعالجات. وإلا فلا متعة في الأمر. وهذا يعني أنه يتعيّن معالجة عدة أعطال على التوازي، ربما حتى من أجل الصفحة نفسها. ثالثًا، في الإصدارات اللاحقة تستطيع مساعدات memtap أن تجلب مسبقًا حزمة من الصفحات، وقد تصل بترتيب أيّ كان نظرًا لغياب الضمانات من خادم mcdist. وكان أيٌّ من هذه العوامل قادرًا على تحويل الأمر إلى كابوس تزامن، ونحن نمتلكها جميعها.

يرتكز تصميم memtap بأكمله على خريطة ثنائية (bitmap) لحضور الصفحات. تُنشأ الخريطة وتُهيَّأ عند معالجة الوصف المعماري لإنشاء الآلة الافتراضية المنسوخة. وهي مصفوفة بتات مسطّحة يُحدَّد حجمها بعدد الصفحات التي تتّسع لها ذاكرة الآلة الافتراضية. ولدى معالجات Intel تعليمات ملائمة لتعديل البتات ذرّيًا: فيمكن ضبط بت، أو إجراء «اختبار وضبط» (test and set)، مع ضمان الذرّية بالنسبة إلى المعالجات الأخرى في الجهاز نفسه. ويتيح لنا ذلك تجنّب الأقفال في معظم الحالات، وبالتالي إتاحة الوصول إلى الخريطة من كيانات مختلفة في نطاقات حماية مختلفة: الناظر الفائق الخاص بـ Xen، وعملية memtap، ونواة الضيف المنسوخة نفسها.

حين يتعامل Xen مع عطل صفحة عتادي ناتج عن أول وصول إلى صفحة، يستخدم الخريطة ليقرّر ما إذا كان يحتاج إلى تنبيه memtap. كما يستخدم الخريطة لإدراج عدة معالجات افتراضية معطّلة في قائمة الانتظار باعتبارها معتمدة على الصفحة المفقودة نفسها. وتقوم Memtap بتخزين الصفحات مؤقتًا عند وصولها. وعندما يمتلئ مخزنها المؤقت أو تصل صفحة طُلبت صراحةً، تُوقَف الآلة الافتراضية، وتُستخدم الخريطة للتخلّص من أي صفحات مكرّرة وصلت مع أنها موجودة بالفعل. ثم تُنسخ أي بقية صفحات مطلوبة إلى ذاكرة الآلة الافتراضية، وتُضبط البتات المناسبة في الخريطة.

18.6.2. النسخ الذكية تتجنّب عمليات الجلب غير الضرورية

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

هناك حالة شائعة جدًا تحدث فيها هذه العملية ويمكن فيها تجنّب عمليات الجلب. فكل عمليات تخصيص الذاكرة في النواة (باستخدام vmalloc وkzalloc وget_free_page وbrk في مساحة المستخدم وما شابه) تُعالَج في النهاية بواسطة مخصّص صفحات النواة. وعادةً ما تُطلب الصفحات من مخصّصات وسيطة تدير مقاطع أدقّ: مخصّص slab، ومخصّص malloc في glibc لعملية في مساحة المستخدم، وغيرها. لكنّ سواء كان التخصيص صريحًا أم ضمنيًا، فإن نتيجة دلالية واحدة تبقى صحيحة دائمًا: لا أحد يهتمّ بمحتوى الصفحة، لأن محتوياتها ستُكتب فوقها بشكل عشوائي. فلماذا نجلب هذه الصفحة إذًا؟ لا سبب للقيام بذلك، والخبرة العملية تُظهر أن تجنّب عمليات الجلب هذه مفيد إلى حد بعيد.

18.7. واجهة استنساخ الآلات الافتراضية للتطبيقات

ركّزنا حتى الآن على التفاصيل الداخلية لاستنساخ آلة افتراضية بكفاءة. ومهما كانت الأنظمة الانعزالية (solipsistic) ممتعة، فنحن بحاجة إلى توجيه انتباهنا إلى من سيستخدمون النظام:التطبيقات

18.7.1. تنفيذ واجهة البرمجة (API)

يُتاح استنساخ الآلات الافتراضية للتطبيق عبر واجهة SnowFlock البسيطة، والمبينة في الشكل 18.1. والاستنساخ، في جوهره، عملية من مرحلتين. فتطلب أولًا تخصيصًا لنسخ الآلة، وإن كان ذلك التخصيص، بسبب سياسات النظام السارية، قد يكون أصغر مما طُلب. ثم تستخدم هذا التخصيص لاستنساخ آلتك الافتراضية. والافتراض الأساسي هو أن آلتك الافتراضية تركز على عملية واحدة. يناسب VM Cloning الآلات الافتراضية ذات التطبيق الواحد، مثل خادم ويب أو عنصرًا في مزرعة عارضات (render farm). وإن كان لديك بيئة سطح مكتب مؤلّفة من مئة عملية، تستدعي فيها تطبيقات متعددة استنساخ الآلات الافتراضية في آن واحد، فأنت تترقّب الفوضى.

sf_request_ticket(n) يطلب تخصيصًا لـ n نسخة. ويُعيد ticket يصف تخصيصًا لـ m≤n نسخة.
sf_clone(ticket) ينسخ باستخدام تخصيص ticket. ويُعيد ID النسخة، 0&le;ID<m.
sf_checkpoint_parent() يجهّز نقطة تفتيش غير قابلة للتغيّر C للآلة الافتراضية الأم لاستخدامها في إنشاء النسخ في وقت لاحق تمامًا.
sf_create_clones(C, ticket) نفسها كـ sf_clone، وتستخدم نقطة التفتيش C. وستبدأ النسخ التنفيذ عند النقطة التي استُدعي عندها sf_checkpoint_parent() المقابل.
sf_exit() للأبناء (1&le;ID<m)، ينهي الابن.
sf_join(ticket) للأم (ID = 0)، يحجب حتى يبلغ جميع الأبناء في ticket استدعاء sf_exit الخاص بهم. وعند تلك النقطة يكون جميع الأبناء قد أُنهيت ويُتلف ticket.
sf_kill(ticket) للأم فقط، يتخلّص من ticket ويقتل فورًا جميع الأبناء المرتبطين به.

الجدول 18.1: واجهة SnowFlock البرمجية لاستنساخ الآلات الافتراضية

لا تفعل واجهة البرمجة سوى ترميز الرسائل (marshalling) ونشرها إلى XenStore، وهي واجهة منخفضة الإنتاجية قائمة على الذاكرة المشتركة تستخدمها Xen لعمليات مستوى التحكم. وتعمل خدمة SnowFlock المحلية (SnowFlock Local Daemon, SFLD) على الناظر الفائق وتستمع إلى هذه الطلبات. إذ تُفكّ ترميز الرسائل، وتُنفَّذ، وتُنشر الردود.

يمكن للبرامج التحكّم في VM Cloning مباشرةً عبر واجهة البرمجة، المتوفّرة لـ C وC++ وPython وJava. ويمكن لسكربتات الصدفة التي تتولّى تشغيل برنامج ما أن تستخدم سكربتات سطر الأوامر المقدَّمة بدلًا من ذلك. ويمكن لأطر العمل المتوازية مثل MPI أن تضمّ واجهة البرمجة داخلها: وعندئذٍ تستطيع برامج MPI استخدام SnowFlock دون أن تعرف به أصلًا، ودون أي تعديل في شيفرتها المصدرية. كما يمكن لموازنات الحمل (load balancers) الواقعة أمام خوادم الويب أو خوادم التطبيقات أن تستخدم الواجهة لاستنساخ الخوادم التي تديرها.

تنظّف خدمات SFLD تنفيذ طلبات VM Cloning. فهي تنشئ الوصفات المعمارية وتنقلها، وتنشئ الآلات الافتراضية المنسوخة، وتطلق خوادم القرص والذاكرة، وتطلق عمليات memtap المساعدة. وهي نظام موزّع مصغّر مسؤول عن إدارة الآلات الافتراضية في عنقود فيزيائي.

تؤجّل خدمات SFLD قرارات التخصيص إلى خدمة SnowFlock الرئيسية المركزية (SnowFlock Master Daemon, SFMD). وتكتفي SFMD بالتكامل مع برمجيات إدارة العناقيد المناسبة. ولم نرَ أي حاجة إلى إعادة اختراع العجلة هنا، وأجّلنا قرارات تخصيص الموارد والحصص والسياسات وغيرها إلى برمجيات مناسبة مثل Sun Grid Engine أو Platform EGO.

18.7.2. تعديلات ضرورية

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

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

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

ولمنع تصادم الشبكات الخاصة الافتراضية الخاصة بنسخ تنتمي إلى آباء مختلفين—ولمنع هجمات DDoS المتبادلة—تُعزل الشبكات الافتراضية للنسخ على مستوى Ethernet (أي الطبقة الثانية). فنحتجز نطاقًا من معرّفات OUI لعناوين MAC الخاصة بـ Ethernet[3] ونخصّصها للنسخ. وسيكون OUI دالةً في الآلة الافتراضية الأم. ومثلما يحدّد معرّف الآلة الافتراضية عنوانَ IP الخاص بها، فإنه يحدّد أيضًا عنوان MAC الخاص بـ Ethernet خارج نطاق OUI. ويترجم مشغّل الشبكة الافتراضية عنوان MAC الذي تعتقد الآلة الافتراضية أنها تملكه إلى العنوان المسنَد لها دلالةً على معرّفها، ويرشّح كل حركة بيانات تتجه إلى الشبكة الخاصة الافتراضية أو منها وذات OUI مختلف. وهذا العزل يعادل ما يمكن تحقيقه عبر ebtables، وإن كان تنفيذه أبسط بكثير.

قد يكون الأمر ممتعًا أن تقتصر النسخ على التحدّث فيما بينها، لكنه ليس ممتعًا إلى هذا الحد. أحيانًا نرغب في أن تستجيب نسخنا لطلبات HTTP القادمة من الإنترنت، أو تُركّب مستودعات بيانات عامة. ونجهّز أي مجموعة من الآب والنسخ بآلة افتراضية مخصّصة للتوجيه (router). وتؤدي هذه الآلة الافتراضية الصغيرة عمل جدار الحماية، وتنظيم معدّل الإرسال، وحوركة العناوين (NAT) لحركة البيانات من النسخ إلى الإنترنت. كما تضع حدًّا للاتصالات الواردة إلى الآلة الافتراضية الأم وإلى المنافذ المعروفة. والآلة الافتراضية للتوجيه خفيفة الوزن، لكنها تمثّل نقطة مركزية واحدة لتركيز حركة البيانات الشبكية، وهو ما قد يحدّ من قابلية التوسّع بدرجة كبيرة. ويمكن تطبيق قواعد الشبكة نفسها على نحو موزّع على كل مضيف تعمل عليه آلة افتراضية منسوخة. ونحن لم نصدر تلك التصويبة التجريبية بعد.

تُسند خدمات SFLD المعرّفات، وتعلّم مشغّلات الشبكة الافتراضية كيف ينبغي أن تضبط نفسها: عناوين MAC وIP الداخلية، وتوجيهات DHCP، وإحداثيات آلة التوجيه الافتراضية، وقواعد الترشيح، وغيرها.

18.8. الخاتمة

بتعديل الناظر الفائق الخاص بـ Xen ونقل حالة الآلة الافتراضية كسولًا، يستطيع SnowFlock إنتاج عشرات النسخ من آلة افتراضية قيد التشغيل في بضع ثوانٍ. وبذلك يكون استنساخ الآلات الافتراضية بـ SnowFlock فوريًا وحيًّا—وهو ما يحسّن قابلية استخدام السحابة عبر أتمتة إدارة العنقود ومنح التطبيقات تحكّمًا برمجيًا أكبر في موارد السحابة. كما يحسّن SnowFlock مرونة السحابة بتسريع إنشاء الآلات الافتراضية بمعامل 20، وتحسين أداء معظم الآلات الافتراضية المنشأة حديثًا عبر الاستفادة من ذواكر التخزين المؤقت الدافئة لنظام التشغيل والتطبيقات الموجودة في ذاكرة الأصل. ومفاتيح أداء SnowFlock الفعّال هي الاستدلالات (heuristics) التي تتجنّب عمليات جلب الصفحات غير الضرورية، ونظام البث المتعدد الذي يتيح لإخوة النسخ أن يجلبوا حالتهم مسبقًا بشكل تعاوني. ولم يحتج الأمر إلا إلى تطبيق ذكي لتقنيات مجرَّبة ومضمونة، وبعض الحيل اليدوية، وحصّة سخيّة من تصحيح الأخطاء بمستوى الإنتاج الصناعي.

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

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

إن كنت مهتمًا بمزيد من المعرفة، فيمكنك زيارة موقع جامعة تورونتو[1:1] للحصول على الأوراق البحثية والشيفرة مفتوحة المصدر المرخّصة وفق GPLv2، وموقع GridCentric[4] للحصول على تنفيذ بمستوى القوة الصناعية.

الحواشي

  1. http://sysweb.cs.toronto.edu/projects/1
  2. http://www.gridcentriclabs.com/architecture-of-open-source-applications
  3. OUI، أو المعرّف الفريد للمؤسسة (Organizational Unique ID)، هو نطاق من عناوين MAC المخصّصة لمورّد.
  4. http://www.gridcentriclabs.com/

  1. http://sysweb.cs.toronto.edu/projects/1 ↩︎ ↩︎

  2. http://www.gridcentriclabs.com/architecture-of-open-source-applications ↩︎

  3. OUI، أو المعرّف الفريد للمؤسسة (Organizational Unique ID)، هو نطاق من عناوين MAC المخصّصة لمورّد. ↩︎

  4. http://www.gridcentriclabs.com/ ↩︎