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

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

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

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

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

الإستراتيجيات الاحتياطية للجهاز المفرد

انظر إلى هذا الجزء من التعليمات البرمجية C التالية التي توضح نمطًا شائعًا لمعالجة فشل تخصيص الذاكرة في العديد من التطبيقات. تخصص هذه التعليمات البرمجية الذاكرة باستخدام وظيفة malloc، ثم تقوم بنسخ الصورة المخزنة مؤقتًا إلى تلك الذاكرة أثناء إجراء نوع ما من التحويل:
pixel_ranges = malloc(image_size); // allocates memory
if (pixel_ranges == NULL) {
  // On error, malloc returns NULL
  exit(1);
}
for (i = 0; i < image_size; i++) {
  pixel_ranges[i] = xform(original_image[i]);
}

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

pixel_ranges = malloc(image_size);
if (pixel_ranges == NULL) {
  pixel_ranges = malloc2(image_size);
}

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

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

بالإضافة إلى ذلك، إذا كان التوافر هو أولويتنا القصوى فقد لا تكون الإستراتيجية الاحتياطية تستحق المخاطرة. لماذا نهتم بـ malloc على الإطلاق إذا كان لدى malloc2 فرصة أكبر للنجاح؟ منطقيا، يجب أن تتم مقايضة malloc2 مقابل توافر أعلى. ربما تقوم بتخصيص ذاكرة عالية الوصول ولكن أكبر ومعتمدة على محرك الأقراص ذات الحالة الصلبة (SSD). لكن هذا يطرح سؤالاً، لماذا من المقبول أن تقوم وظيفة malloc2 بعمل هذه المقايضة؟ لنأخذ في الاعتبار تسلسل الأحداث المحتمل الذي قد يتم مع هذه الإستراتيجية الاحتياطية. أولاً، يقوم العميل باستخدام التطبيق. فجأة (بسبب فشل malloc)، يبدأ عمل malloc2 ويبطئ التطبيق. وهذا سيئ: فهل من المقبول يصبح أبطأ؟ ولا تتوقف المشكلات عند هذا الحد. ضع في اعتبارك أن مساحة ذاكرة الجهاز ممتلئة (أو المساحة المتاحة صغيرة للغاية) على الأرجح. يواجه العميل الآن مشكلتين (تطبيق أبطأ وجهاز أبطأ) بدلاً من مشكلة واحدة. بل يمكن أن تؤدي الآثار الجانبية للتحول إلى malloc2 إلى تفاقم المشكلة الإجمالية. على سبيل المثال، قد تكون الأنظمة الفرعية الأخرى أيضًا في حالة تنافس مع نفس وحدة التخزين المستندة إلى محرك الأقراص ذات الحالة الصلبة (SSD).

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

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

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

بالنسبة لتطبيقات الجهاز المفرد المهمة التي يجب أن تعمل في حالة فشل تخصيص الذاكرة، يتمثل أحد الحلول في التخصيص المسبق لذاكرة متكدسة بالكامل عند بدء التشغيل وعدم الاعتماد مطلقًا على malloc مرة أخرى، حتى في ظل حدوث خطأ. وقد نفذت Amazon هذه الإستراتيجية عدة مرات؛ على سبيل المثال، في مراقبة البرامج التي تعمل على خوادم الإنتاج وبرامج Amazon Elastic Compute Cloud (Amazon EC2)والبرامج التي تراقب عمليات تدفق وحدات المعالجة المركزية الخاصة بالعملاء.

الإستراتيجية الاحتياطية الموزعة

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

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

قد تفشل الإستراتيجيات الاحتياطية الموزعة. بينما قد تبدو الإستراتيجيات الاحتياطية ضمانًا للنجاح، إلا أنها، في تجربتنا، تعمل عادةً على تحسين احتمالات النجاح فقط.

غالبًا ما تؤدي الإستراتيجيات الاحتياطية الموزعة إلى زيادة سوء العطل. في تجربتنا، تزيد الإستراتيجيات الاحتياطية من نطاق تأثير الأعطال فضلاً عن زيادة أوقات المعالجة.

غالبًا ما لا تستحق الإستراتيجيات الاحتياطية الموزعة المخاطرة.. وكما هو الحال مع malloc2، غالبًا ما تقوم الإستراتيجية الاحتياطية بنوع ما من المقايضة؛ وإلا، سنستخدمها طوال الوقت. لماذا نستخدم إجراءً احتياطيًا يعتبر سيئًا، عندما يكون هناك خطأ بالفعل؟

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

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

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

if (cache_healthy) {
  shipping_speed = get_speed_via_cache(sku);
} else {
  shipping_speed = get_speed_from_database(sku);
}

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

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

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

كيف تتجنب Amazon الإجراء الاحتياطي

بسبب هذه الأخطاء التي واجهناها مع الإجراء الاحتياطي الموزع، نفضل الآن دائمًا تقريبًا استخدام البدائل فضلاً عن الإجراء الاحتياطي. نعرضها فيما يلي.

تحسين موثوقية حالات عدم استخدام الإجراء الاحتياطي

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

ترك الوسيط يتعامل مع الأعطال

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

دفع البيانات بشكل استباقي

نستخدم طريقة أخرى لتجنب الحاجة إلى الإجراء الاحتياطي وهي تقليل عدد الأجزاء المنتقلة عند الرد على الطلبات. على سبيل المثال، إذا احتاجت خدمة بيانات لتنفيذ طلب ما، وكانت البيانات موجودة محليًا بالفعل (لا نحتاج لإحضارها)، فلا حاجة إلى إستراتيجية تجاوز الأعطال. يمثل تنفيذ أدوار AWS Identity and Access Management (IAM)من أجل Amazon EC2‏ مثالاً ناجحًا على هذا. تحتاج خدمة IAM إلى تقديم بيانات اعتماد موقعة تم تدويرها إلى التعليمات البرمجية التي تعمل على مثيلات EC2. لتجنب الحاجة إلى الإجراء الاحتياطي بشكل دائم، يتم دفع بيانات الاعتماد بشكل استباقي لكل مثيل وتظل صالحة للعديد من الساعات. يعني هذا أن دور IAM المتعلق بالطلبات يبقى قيد العمل في حالة تعطل آلية الدفع غير المحتملة. 

تحويل الإجراء الاحتياطي إلى إجراء لتجاوز العطل

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

التأكد من أن المهلات الزمنية وإعادة المحاولات لا تصبح إجراءً احتياطيًا

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

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

الخاتمة

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

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

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


نبذة عن المؤلف

يشغل جاكوب غابرييلسون منصب كبير المهندسين الأساسيين في Amazon Web Services. يعمل جاكوب غابرييلسون في شركة Amazon منذ 17 عامًا، في المقام الأول على النظم الأساسية للخدمات المصغرة الداخلية. وعلى مدار الأعوام الثمانية الماضية، عمل في EC2 وECS، بما في ذلك أنظمة نشر البرامج، وخدمات مستوى التحكم، وسوق Spot، وLightsail، ومؤخرًا الحاويات. إن شغف جاكوب يكمن في برمجة النظم ولغات البرمجة والحوسبة الموزعة. وأكثر ما لا يرغب به هو السلوك ثنائي النمط، خاصة في حالات الفشل. وهو حاصل على درجة البكالوريوس في علوم الكمبيوتر من جامعة واشنطن في سياتل.

المهلات وإعادة المحاولات والتراجع مع تقلقل الشبكة تحديات التخزين المؤقت وإستراتيجياته