الإصدارات الموزَّعة

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

التخزين المؤقت عن بُعد

إنّ أبسط نوع للتصميم الموزّع هو النوع الذي يستفيد من التخزين المؤقت عن بُعد فقط، كما هو موضّح في الشكل 1.

مبنى موزّع يتضمّن تخزينًا مؤقتًا عن بُعد

الشكل 1. مبنى موزّع يعرض التخزين المؤقت عن بُعد

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

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

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

التنفيذ عن بُعد

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

نظام التنفيذ عن بُعد

الشكل 2. نظام تنفيذ عن بُعد

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

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

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

الإصدارات الموزَّعة في Google

منذ عام 2008، تستخدم Google نظام إصدار موزعًا يوظّف عن بُعد التخزين المؤقت عن بُعد والتنفيذ عن بُعد، كما هو موضّح في الشكل 3.

نظام إصدار عالي المستوى

الشكل 3. نظام الإصدار الموزّع من Google

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

يُطلق على نظام التنفيذ عن بُعد من Google اسم Forge. يرسل عميل Forge في Blaze (ما يُعرف باسم Bazel' مكافئ داخلي) يُرسل الموزِّع طلبات كل إجراء إلى مهمة يتم تنفيذها في مراكز البيانات المعروفة باسم أداة الجدولة. تحتفظ أداة الجدولة بنسخة مؤقتة من نتائج الإجراءات، ما يتيح لها عرض رد على الفور إذا كان الإجراء قد تم إنشاؤه بواسطة أي مستخدم آخر للنظام. إذا لم يكن الأمر كذلك، يضع الإجراء في قائمة انتظار. تقرأ مجموعة كبيرة من مهام "المُنفِّذ" الإجراءات باستمرار من هذه القائمة، ونفِّذها ونخزِّن النتائج مباشرةً في جداول ObjFS Bigtables. تتوفّر هذه النتائج لمنفّذي الإجراءات المستقبلية أو يمكن للمستخدم النهائي تنزيلها باستخدام objfsd.

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