AWS Certified CloudOps Engineer - Associate

اختيار استراتيجية النشر

استراتيجيات النشر الخمس التي يتوقّع الاختبار أن تميّز بينها: all at once وrolling وimmutable وblue/green وcanary أو التحويل التدريجي للحركة. ما يكلّفه كل منها من سعة ووقت ومستخدمين متضرّرين، ولماذا طبقة البيانات هي الجزء الذي لا يصلحه أيٌّ منها.

متوسط 25 دقائق 6 أهداف التعلّم
  1. اشرح السؤالين اللذين يولّدان كل استراتيجيات النشر: أتستبدل أم تبني، وكم من الحركة تصل النسخة الجديدة
  2. قارن all at once وrolling وimmutable وblue/green وcanary وlinear من حيث تكلفة السعة والتعرّض وسرعة التراجع
  3. احسب السعة التي تبقى في الخدمة أثناء نشر rolling، وقرّر هل يحتملها أسطولك
  4. ميّز blue/green عن canary بآلية تحويل الحركة لا بعدد البيئات
  5. حدّد قيود قاعدة البيانات والجلسات التي تجعل نشر نسختين حيّتين معاً غير آمن
  6. اربط كلمات الاختبار مثل التراجع السريع والسعة الكاملة ونسبة صغيرة من الحركة بالاستراتيجية التي تشير إليها

اثنتا عشرة instance من EC2 خلف Application Load Balancer. لديك AMI جديدة تصلح خللاً في التسجيل، وتشحن معها دون أن تدري database driver يسرّب الاتصالات تحت الحمل. خلال 40 دقيقة تقريباً سينفد الـ connection pool وتبدأ الطلبات في تجاوز المهلة.

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

السؤالان خلف كل استراتيجية

انزع المصطلحات ولن يبقى إلا قراران.

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

حين تصير النسخة الجديدة حيّة، كم من الحركة يصلها دفعة واحدة؟ كلها، أو نسبة تتصاعد، أو شريحة صغيرة ثابتة اخترت أنت أن تخاطر بها.

كل استراتيجية مسمّاة هي إجابة محدّدة عن هذين السؤالين. وحين ترى ذلك تتوقّف الأسماء عن كونها قائمة تُحفَظ وتصير إحداثيات.

all at once: الاستراتيجية التي تحصل عليها مجاناً

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

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

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

rolling: بادل زمن النشر بالتوافر

قسّم الأسطول إلى دفعات وحدّث دفعة واحدة في كل مرة. الـ instances في الدفعة الحالية تُسحب من الـ load balancer، وتُحدَّث، وتُفحَص صحتها، ثم تعود قبل أن تبدأ الدفعة التالية.

طبّق الأرقام على الـ 12 instance بحجم دفعة 25 بالمئة:

  • حجم الدفعة 3 instances، فعدد الدفعات 4.
  • بينما دفعة خارج الخدمة تخدم 9 instances. وهذه 75 بالمئة من السعة.
  • زمن النشر الكلي نحو 4 أضعاف (زمن التحديث زائد زمن فحص الصحة)، فنشر يستغرق 4 دقائق للدفعة يمتدّ 16 دقيقة بدل 4.

رقم الـ 75 بالمئة هو قيد التصميم، وهو موضع الضرر. فإن كانت الـ 12 instance مقاسة للذروة، فإن 9 instances في الذروة تنقص 25 بالمئة، وتصير عملية النشر نفسها سبب قفزة زمن الاستجابة. حجم الدفعة ليس إعداد راحة، بل قرار سعة يجب أن يصمد في ساعتك الأكثر ازدحاماً لا في متوسّطك.

والعلاج، حين تستطيع الدفع، أن تطلق دفعة إضافية أولاً وتنهيها في النهاية. فلا تنزل تحت 100 بالمئة من سعة الخدمة أبداً، وتدفع ثمن 3 instances إضافية لمدة 16 دقيقة، ويمتدّ النشر دفعة واحدة أطول.

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

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

immutable وblue/green: ابنِ أولاً ثم حوّل

البديل أن تتوقّف عن لمس الخوادم العاملة أصلاً. أطلق مجموعة جديدة كاملة من التهيئة الجديدة، ودعها تثبت نفسها بفحوصات الصحة، ثم تقاعد عن الأصلية.

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

blue/green هو المبدأ نفسه مطبَّقاً على بيئة كاملة. blue هي الإنتاج، وgreen نسخة موازية كاملة تشغّل الإصدار الجديد: instances خاصة بها، وtarget group خاصة بها، وفحوصات صحة خاصة بها. وحين تبدو green سليمة تنقل مؤشّر الحركة من blue إلى green. وتبقى blue تعمل خاملة ما دمت تريد مسار تراجع.

المؤشّر هو الحيلة كلها، وآليته هي التي تقرّر سرعة تراجعك:

المؤشّرسرعة التراجعالقيد
قاعدة listener أو وزن target group في الـ load balancerتسري على الطلب التالييجب أن تقع البيئتان خلف الـ load balancer نفسه
سجلّ DNS (Route 53 أو تبديل CNAME)محدودة بمدة TTL وبالتخزين المؤقت لدى الـ resolversبعض العملاء يواصلون حلّ الاسم القديم بعد انتهاء TTL بكثير
مؤشّر داخل الخدمة نفسها (alias في Lambda، أو مراجعة خدمة في ECS)تسري فوراًنطاقها تلك الخدمة وحدها لا البيئة كلها

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

canary وlinear: مؤشّر متدرّج بدل مفتاح

canary وlinear ليسا طريقتين مختلفتين لبناء النسخة الجديدة. هما يفترضان أنك بنيتها بالفعل، تماماً كما يفعل blue/green، ولا يغيّران إلا الخطوة الأخيرة: بدل نقل الحركة كلها دفعة واحدة تنقل نسبة محكومة.

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

linear يحوّل بخطوات متساوية على فترات متساوية: 10 بالمئة كل دقيقتين حتى تنتقل الحركة كلها.

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

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

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

المقارنة التي تهمّ

الاستراتيجيةسعة إضافيةالحركة على النسخة الجديدة قبل أن تملك دليلاًالتراجعالنسختان حيّتان معاً
all at onceلا شيء100 بالمئة فوراًانشر النسخة القديمة مرة أخرىلا، بل انقطاع
rollingلا شيءتصعد دفعة بدفعةشغّل rolling على الأسطول مرة أخرىنعم، معظم مدة النشر
rolling بدفعة إضافيةدفعة واحدةتصعد دفعة بدفعةشغّل rolling على الأسطول مرة أخرىنعم، معظم مدة النشر
immutableمجموعة موازية كاملةصفر حتى تنجح فحوصات الصحة، ثم 100 بالمئةأنهِ المجموعة الجديدةعند التسليم فقط
blue/greenبيئة ثانية كاملةصفر حتى التحويل، ثم 100 بالمئةأعِد المؤشّرعند التحويل فقط
canaryبيئة ثانية كاملةنسبة الـ canary وحدهاأعِد الوزننعم، عن قصد
linearبيئة ثانية كاملةتنمو زيادة بزيادةأعِد الوزننعم، عن قصد

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

كيف تختار

القرار يفرضه قيد لا تفضيل غالباً، فابدأ من القيود:

  • نافذة صيانة مقبولة. all at once. أسرع وأرخص، والتعقيد لا يشتري لك شيئاً هنا.
  • لا انقطاع مسموح، ولا ميزانية لسعة إضافية. rolling. اضبط حجم الدفعة كي يحمل الأسطول الباقي حمل الذروة.
  • السعة الكاملة مطلوبة طوال الوقت، ومع بعض الميزانية. rolling بدفعة إضافية، أو immutable.
  • التراجع يجب أن يُقاس بالثواني. blue/green أو أشكاله ذات التحويل التدريجي. ولا شيء يعيد بناء السعة يستطيع بلوغ هذه العتبة.
  • تحتاج دليلاً من حركة حقيقية قبل الالتزام. canary أو linear، بمقياس مسمّى وعتبة محدّدة.

وقيد واحد يعلو على هذه كلها: هل تستطيع نسختان من التطبيق العمل في الوقت نفسه؟ إن كانتا لا تستطيعان فقد خرج rolling وcanary وlinear من الحساب مهما كانت الميزانية، وصار اختيارك بين نافذة صيانة وتحويل blue/green.

الجزء الذي لا تحلّه أي استراتيجية

يُوصَف blue/green بأنه تراجع بلا مخاطرة، وهذا قريب من الصحة لكود تطبيق بلا حالة. وفي اللحظة التي تدخل فيها الحالة يتوقّف عن كونه صحيحاً، ومن هنا تأتي الحوادث الحقيقية.

قاعدة البيانات مشتركة عادةً. لا تحصل green على نسخة خاصة من بيانات الإنتاج، لأن النسخة ستصير قديمة فوراً. فتتحدّث blue وgreen إلى قاعدة البيانات نفسها، وأي تغيير في الـ schema يسري عليهما معاً. اشحن migration يحذف عموداً يقرأه الكود القديم، ويختفي مسار التراجع: الرجوع إلى blue صار رجوعاً إلى كود لا يستطيع الاستعلام من قاعدة بياناته.

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

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

حالة الجلسة يجب أن تعيش خارج الـ instances. مستخدم في منتصف عملية شراء على blue ثم هبط على green يحتاج جلسته موجودة هناك. وإن كانت الجلسات محفوظة في ذاكرة الـ instance فكل هذه الاستراتيجيات تُسقط عملاء في منتصف معاملاتهم، وإعدادات الالتصاق في الـ load balancer لا تخفي ذلك إلا إلى أن تختفي الـ instance.

قل الاعتقاد الخاطئ صراحةً لأنه ينجو من أول تجربة blue/green عند معظم الناس: تحويل الحركة اللحظي ليس تراجعاً لحظياً. هو يلغي التوجيه. ولا يلغي عمليات الكتابة، ولا الـ migrations، ولا محتوى الـ cache، ولا الرسائل التي نُشرت إلى طابور بالفعل.

نصائح الاختبار

  • "أسرع نشر" أو "فترة انقطاع قصيرة مقبولة" تشير إلى all at once. وهي الإجابة الصحيحة أكثر مما يتوقّع الممتحَنون، لأنهم يقرؤون البساطة على أنها خطأ.
  • "بلا انقطاع وبلا تكلفة إضافية" هي rolling. وإضافة "مع الحفاظ على السعة الكاملة طوال الوقت" هي ما يحوّلها إلى rolling بدفعة إضافية.
  • "التراجع بسرعة" أو "العودة فوراً عند وجود مشكلة" تعني أن النسخة القديمة يجب أن تكون ما زالت تعمل: blue/green أو تحويل حركة موزون. وأي إجابة تعيد نشر النسخة السابقة تصف تراجعاً بطيئاً.
  • "اختبر بنسبة صغيرة من حركة الإنتاج" هي canary. و"حوّل الحركة بزيادات متساوية على فترات متساوية" هي linear. والكلمتان الفاصلتان هما النسبة والزيادات، لا عدد البيئات.
  • سيناريو يذكر تبديل DNS أو CNAME ثم يشتكي أن بعض المستخدمين ما زالوا يصلون إلى النسخة القديمة يختبر TTL والتخزين المؤقت لدى الـ resolvers، لا عطلاً في الخدمة.
  • انتبه لتفصيل عن قاعدة بيانات مدفون في سؤال blue/green. الـ migration في الإصدار نفسه هو الفخّ، والإجابة الصحيحة عادةً أن تجعل التغيير متوافقاً مع الخلف أو تنفّذه خطوة سابقة مستقلة.
  • نشر immutable فاشل يترك الـ instances الأصلية تخدم. ونشر rolling فاشل يتركك بخليط من النسخ. والأسئلة عن الحالة بعد الفشل تختبر هذا الفرق بالضبط.

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

والدرس التالي يحوّل كل شكل من هذه الأشكال إلى الإعداد المحدّد في AWS الذي ينتجه، وهو الموضع الذي يعيش فيه الاختبار فعلاً: نسب instance refresh، وسياسات تحديث CloudFormation، واستراتيجيات نشر ECS، وaliases في Lambda، وblue/green المُدار في RDS.