
مرحبا يا هبر! أنا أرتيوم كراميشيف ، رئيس فريق إدارة النظام في
Mail.Ru Cloud Solutions (MCS) . خلال العام الماضي ، كان لدينا العديد من إطلاق منتجات جديدة. أردنا توسيع نطاق خدمات واجهة برمجة التطبيقات (API) بسهولة ، والتسامح مع الأعطال ، وجاهز للزيادة السريعة في حمل المستخدم. يتم تطبيق نظامنا الأساسي على OpenStack ، وأريد أن أخبركم بمشاكل التسامح مع الخطأ المكون الذي كان علينا إغلاقه من أجل الحصول على نظام يتحمل العيوب. أعتقد أن هذا سيكون مثيراً للاهتمام لأولئك الذين يقومون أيضًا بتطوير المنتجات على OpenStack.
يتكون التسامح مع الخطأ الإجمالي للمنصة من ثبات مكوناته. لذلك سوف نذهب تدريجياً إلى جميع المستويات التي اكتشفنا فيها المخاطر وأغلقناها.
يمكن مشاهدة إصدار فيديو لهذه القصة ، كان المصدر الأصلي للتقرير في مؤتمر Uptime day 4 الذي نظمته
ITSumma ،
على قناة Uptime Community على YouTube .
خطأ التسامح الهندسة المعمارية المادية
يوجد الجزء العام من سحابة MCS الآن في مركزين من مراكز البيانات من المستوى الثالث ، يوجد بينهما ألياف مظلمة خاصة بها ، محجوزة على الطبقة المادية بطرق مختلفة ، بإنتاجية تبلغ 200 جيجابايت / ثانية. يوفر المستوى الثالث المستوى اللازم من مرونة البنية التحتية المادية.
محجوز الألياف الظلام على الصعيدين البدني والمنطقي. كانت عملية حجز القناة تكرارية ، نشأت مشاكل ، ونحن نعمل باستمرار على تحسين التواصل بين مراكز البيانات.
على سبيل المثال ، منذ وقت ليس ببعيد ، عند العمل في بئر بجوار أحد مراكز البيانات ، قام حفارة بحفر أنبوب ، داخل هذا الأنبوب كان هناك كبل بصري رئيسي ونسخ احتياطي. تحولت قناة الاتصال التي نتحمل الأخطاء مع مركز البيانات إلى نقطة ضعف في نقطة ما في البئر. وفقا لذلك ، فقدنا بعض البنية التحتية. لقد توصلنا إلى استنتاجات ، واتخذنا عددًا من الإجراءات ، بما في ذلك وضع البصريات الإضافية على طول البئر المجاور.
في مراكز البيانات ، هناك نقاط لوجود مزودي الاتصالات الذين نبث لهم بادئاتنا عبر BGP. لكل اتجاه شبكة ، يتم تحديد أفضل مقياس ، والذي يسمح للعملاء المختلفين بتوفير أفضل جودة اتصال. إذا تم قطع الاتصال من خلال مزود واحد ، فإننا نعيد بناء التوجيه لدينا من خلال مقدمي المتاحة.
في حالة فشل الموفر ، ننتقل تلقائيًا إلى الخيار التالي. في حالة فشل أحد مراكز البيانات ، لدينا نسخة طبق الأصل من خدماتنا في مركز البيانات الثاني ، والذي يتحمل كل العبء على أنفسهم.
مرونة البنية التحتية الماديةما نستخدمه للتسامح مع الخطأ على مستوى التطبيق
بنيت خدمتنا على عدد من مكونات مفتوحة المصدر.
ExaBGP هي خدمة تنفذ عددًا من الوظائف باستخدام بروتوكول التوجيه الديناميكي القائم على BGP. نستخدمها بنشاط للإعلان عن عناوين IP البيضاء الخاصة بنا والتي يمكن للمستخدمين من خلالها الوصول إلى واجهة برمجة التطبيقات.
HAProxy عبارة عن موازن تم تحميله بدرجة عالية يسمح لك بتكوين قواعد مرنة للغاية لموازنة حركة المرور على مستويات مختلفة من نموذج OSI. نستخدمها لتحقيق التوازن بين جميع الخدمات: قواعد البيانات ، وسماسرة الرسائل ، وخدمات API ، وخدمات الويب ، ومشاريعنا الداخلية - كل شيء وراء HAProxy.
تطبيق API -
تطبيق ويب مكتوب ببيثون ، يتحكم به المستخدم في بنيته التحتية ، خدمته.
تطبيق العامل (المشار إليه فيما يلي بكل بساطة باسم العامل) - في خدمات OpenStack ، يعد البرنامج خفيًا للبنية التحتية يسمح لك بترجمة أوامر API إلى البنية التحتية. على سبيل المثال ، يتم إنشاء قرص في العامل ، ويكون طلب الإنشاء في واجهة برمجة تطبيقات التطبيق.
بنية تطبيق OpenStack القياسية
تحاول معظم الخدمات التي تم تطويرها لـ OpenStack اتباع نموذج واحد. تتكون الخدمة عادةً من جزأين: واجهة برمجة التطبيقات (API) والعمال (منفذي الواجهة الخلفية). عادةً ما تكون واجهة برمجة التطبيقات (API) عبارة عن تطبيق بيثون WSGI يعمل إما كعملية قائمة بذاتها (خفي) أو باستخدام خادم ويب جاهز Nginx ، Apache. تقوم واجهة برمجة التطبيقات بمعالجة طلب المستخدم وتمرير المزيد من الإرشادات إلى التطبيق العامل. يحدث انتقال باستخدام وسيط الرسائل ، وعادة RabbitMQ ، والباقي معتمدة بشكل سيء. عندما تصل الرسائل إلى الوسيط ، تتم معالجتها بواسطة العمال ، وإذا لزم الأمر ، تُرجع ردًا.
يتضمن هذا النموذج نقاط الفشل الشائعة المعزولة: RabbitMQ وقاعدة البيانات. لكن RabbitMQ معزول داخل خدمة واحدة ، ومن الناحية النظرية ، يمكن أن يكون فرديًا لكل خدمة. لذلك نحن في MCS نشارك هذه الخدمات قدر الإمكان ، لكل مشروع فردي نقوم بإنشاء قاعدة بيانات منفصلة ، RabbitMQ منفصلة. هذا النهج جيد لأنه في حالة وقوع حادث في بعض نقاط الضعف ، لا تنقطع جميع الخدمات فحسب ، بل جزء منها فقط.
عدد التطبيقات المنفذة غير محدود ، لذلك يمكن لواجهة برمجة التطبيقات (API) الانتقال بسهولة أفقياً وراء الموازنات من أجل زيادة الإنتاجية والتسامح مع الخطأ.
تتطلب بعض الخدمات التنسيق داخل الخدمة - عندما تحدث عمليات متتابعة معقدة بين واجهات برمجة التطبيقات والعمال. في هذه الحالة ، يتم استخدام مركز تنسيق واحد ، وهو نظام مجموعة مثل Redis و Memcache و etcd ، والذي يسمح لأحد العاملين بإخبار الآخر بأن هذه المهمة قد تم تعيينه له ("من فضلك لا تأخذها"). نستخدم الخ كقاعدة عامة ، يتواصل العمال بنشاط مع قاعدة البيانات ، ويكتبوا ويقرأوا المعلومات من هناك. كقاعدة بيانات ، نستخدم mariadb ، الذي لدينا في مجموعة multimaster.
يتم تنظيم مثل هذه الخدمة الكلاسيكية للمستخدم المفرد بطريقة مقبولة عمومًا لـ OpenStack. يمكن اعتباره نظامًا مغلقًا ، حيث تكون طرق القياس والتسامح مع الأخطاء واضحة تمامًا. على سبيل المثال ، من أجل التسامح مع الخطأ لـ API ، يكفي وضع موازن أمامهم. يتم تحقيق تحجيم العمال بزيادة عددهم.
نقاط الضعف في المخطط بأكمله هي RabbitMQ و MariaDB. إن بنيتها المعمارية تستحق مقالاً منفصلاً ، أريد في هذه المقالة التركيز على التسامح مع الخطأ في واجهة برمجة التطبيقات.
هندسة تطبيق Openstack سحابة منصة التوازن والمرونةجعل HAProxy الموازن مرونة مع ExaBGP
لجعل واجهات برمجة التطبيقات (APIs) قابلة للتوسعة وسريعة ومتسامحة مع الأخطاء ، قمنا بتعيين موازن أمامها. اخترنا هابروكسي. في رأيي ، فإنه يحتوي على كل الخصائص الضرورية لمهمتنا: الموازنة على عدة مستويات OSI ، واجهة الإدارة ، المرونة وقابلية التوسع ، عدد كبير من أساليب الموازنة ، دعم جداول جلسات العمل.
المشكلة الأولى التي تحتاج إلى حل كانت التسامح مع الخطأ من الموازن نفسه. يؤدي تثبيت الموازن أيضًا إلى إنشاء نقطة عطل: فواصل الموازن - تسقط الخدمة. لمنع هذا ، استخدمنا HAProxy مع ExaBGP.
يتيح لك ExaBGP تطبيق آلية للتحقق من حالة الخدمة. استخدمنا هذه الآلية للتحقق من وظائف HAProxy وفي حالة حدوث مشاكل ، قم بتعطيل خدمة HAProxy من BGP.
مخطط ExaBGP + HAProxy- نقوم بتثبيت البرنامج الضروري على ثلاثة خوادم ، ExaBGP و HAProxy.
- على كل من الخوادم نقوم بإنشاء واجهة الاسترجاع.
- على الخوادم الثلاثة ، نقوم بتعيين نفس عنوان IP الأبيض لهذه الواجهة.
- يتم الإعلان عن عنوان IP أبيض على الإنترنت من خلال ExaBGP.
يتم تحقيق التسامح مع الخطأ عن طريق الإعلان عن نفس عنوان IP من الخوادم الثلاثة. من وجهة نظر الشبكة ، يمكن الوصول إلى نفس العنوان من ثلاثة آمال تالية مختلفة. يرى الموجّه ثلاثة مسارات متماثلة ، ويحدد الأولوية القصوى لها وفقًا لقياسه الخاص (عادةً ما يكون هذا هو الخيار نفسه) ، وتنتقل حركة المرور فقط إلى أحد الخوادم.
في حالة حدوث مشكلات في تشغيل HAProxy أو فشل الخادم ، يتوقف ExaBGP عن الإعلان عن المسار ، ويتحول المرور بسلاسة إلى خادم آخر.
وهكذا ، حققنا التسامح مع الخطأ من الموازن.
خطأ التسامح من موازين HAProxyتبين أن المخطط غير كامل: لقد تعلمنا كيفية حجز HAProxy ، لكننا لم نتعلم كيفية توزيع التحميل داخل الخدمات. لذلك ، قمنا بتوسيع هذا المخطط قليلاً: انتقلنا إلى تحقيق التوازن بين عدة عناوين IP بيضاء.
DNS استنادا موازنة زائد BGP
ظلت مسألة موازنة التحميل قبل HAProxy لدينا دون حل. ومع ذلك ، يمكن حلها ببساطة شديدة ، كما فعلنا في المنزل.
لتحقيق التوازن بين الخوادم الثلاثة ، ستحتاج إلى 3 عناوين IP بيضاء و DNS قديم جيد. يتم تعريف كل من هذه العناوين على واجهة الاسترجاع لكل HAProxy ويتم الإعلان عنها على الإنترنت.
يستخدم OpenStack كتالوج خدمة لإدارة الموارد ، والذي يعين واجهة برمجة تطبيقات نقطة النهاية للخدمة. في هذا الدليل ، نصف اسم النطاق - public.infra.mail.ru ، والذي يحل من خلال DNS مع ثلاثة عناوين IP مختلفة. نتيجة لذلك ، نحصل على موازنة تحميل بين العناوين الثلاثة من خلال DNS.
ولكن منذ الإعلان عن عناوين IP البيضاء ، لا نتحكم في أولويات اختيار الخادم ، وهذا لا يتوازن حتى الآن. كقاعدة عامة ، سيتم اختيار خادم واحد فقط بأسبقية عنوان IP ، وسيكون الخادمان الآخران في وضع الخمول ، نظرًا لعدم تحديد مقاييس في BGP.
بدأنا في إعطاء طرق عبر ExaBGP بمقاييس مختلفة. يعلن كل موازن عن جميع عناوين IP البيضاء الثلاثة ، ولكن يتم الإعلان عن واحد منها ، وهو العنوان الرئيسي لهذا الموازن ، بأقل قدر من القياس. لذلك أثناء تشغيل الموازنات الثلاثة ، تقع المكالمات إلى عنوان IP الأول على الموازن الأول ، والمكالمات إلى الثانية إلى الثانية ، إلى الثالثة إلى الثالثة.
ماذا يحدث عندما يسقط أحد الموازنات؟ في حالة فشل أي موازن من حيث الأساس ، لا يزال يتم الإعلان عن العنوان من الاثنين الآخرين ، ويتم إعادة توزيع حركة المرور بينهما. وبالتالي ، فإننا نقدم للمستخدم من خلال DNS عدة عناوين IP في وقت واحد. من خلال الموازنة على DNS والمقاييس المختلفة ، نحصل على توزيع موحد للحمل على جميع الموازنات الثلاثة. وفي الوقت نفسه نحن لا نفقد التسامح مع الخطأ.
HAProxy Balancing بناءً على DNS + BGPالتفاعل بين ExaBGP و HAProxy
لذلك ، قمنا بتنفيذ التسامح مع الخطأ في حالة ترك الخادم ، بناءً على إنهاء الإعلان عن الطرق. ولكن يمكن أيضًا فصل HAProxy لأسباب أخرى غير فشل الخادم: أخطاء الإدارة ، فشل الخدمة. نريد إزالة الموازن المكسور من تحت الحمل وفي هذه الحالات ، نحتاج إلى آلية أخرى.
لذلك ، بتوسيع المخطط السابق ، قمنا بتطبيق دقات قلب بين ExaBGP و HAProxy. هذا هو تطبيق برنامج للتفاعل بين ExaBGP و HAProxy ، عندما يستخدم ExaBGP نصوصًا مخصصة للتحقق من حالة التطبيقات.
للقيام بذلك ، في تكوين ExaBGP ، يجب عليك تكوين مدقق صحة يمكنه التحقق من حالة HAProxy. في حالتنا ، قمنا بتهيئة الخلفية الصحية في HAProxy ، ومن جانب ExaBGP نتحقق من طلب GET البسيط. إذا توقف الإعلان عن الحدوث ، فلن يعمل HAProxy على الأرجح ، وليس من الضروري الإعلان عنه.
هابروكسي الصحة تحققأقران HAProxy: مزامنة الجلسة
الشيء التالي الذي يجب فعله هو مزامنة الجلسات. عند العمل من خلال الموازنات الموزعة ، من الصعب تنظيم تخزين المعلومات حول جلسات العميل. لكن HAProxy هو أحد الموازنات القليلة التي يمكنها القيام بذلك بسبب وظيفة النظراء - القدرة على نقل جداول جلسات العمل بين عمليات HAProxy المختلفة.
هناك طرق موازنة مختلفة: بسيطة ، مثل
round-robin ، ومتقدمة ، عندما يتم تذكر جلسة عميل ، وفي كل مرة يتم الوصول إلى نفس الخادم كما كان من قبل. أردنا تنفيذ الخيار الثاني.
يستخدم HAProxy الجداول الملصقة لحفظ جلسات عمل العميل لهذه الآلية. يحفظون عنوان IP المصدر للعميل ، والعنوان الهدف المحدد (الواجهة الخلفية) وبعض معلومات الخدمة. عادةً ما يتم استخدام الجداول الثابتة لحفظ زوج source-IP + source-IP ، وهو أمر مفيد بشكل خاص للتطبيقات التي لا يمكنها نقل سياق جلسة المستخدم عند التبديل إلى موازن آخر ، على سبيل المثال ، في وضع موازنة RoundRobin.
إذا تم تعليم طاولة الالتصاق للتنقل بين عمليات HAProxy المختلفة (التي تحدث الموازنة بينها) ، فسيتمكن موازنتنا من العمل مع مجموعة واحدة من طاولات العصا. سيمكن هذا من التبديل بين شبكة العميل بسلاسة عند سقوط أحد الموازنات ، وسيستمر العمل مع جلسات العميل على نفس الخلفية التي تم تحديدها مسبقًا.
للتشغيل السليم ، يجب حل عنوان IP المصدر للموازن الذي تم تأسيس الجلسة منه. في حالتنا ، هذا عنوان ديناميكي على واجهة الاسترجاع.
لا يتحقق التشغيل الصحيح للأقران إلا في ظروف معينة. بمعنى ، يجب أن تكون مهلات TCP كبيرة بما يكفي أو يجب أن يكون المحول سريعًا بدرجة كافية بحيث لا يكون لجلسة TCP وقت للكسر. ومع ذلك ، وهذا يسمح التبديل السلس.
لدينا في IaaS خدمة مبنية على نفس التكنولوجيا. هذا هو
Load Balancer كخدمة لـ OpenStack تسمى Octavia. يعتمد على عمليتين من HAProxy ، وقد تضمن أصلاً دعم الأقران. لقد أثبتوا أنفسهم في هذه الخدمة.
تُظهر الصورة بشكل تخطيطي حركة جداول الأقران بين ثلاث حالات HAProxy ، ويُقترح تكوين ، وكيف يمكن تكوين هذا:
أقران HAProxy (تزامن الجلسة)إذا قمت بتنفيذ نفس المخطط ، فيجب اختبار عمله بعناية. ليس حقيقة أن هذا سوف يعمل بنفس الطريقة في 100 ٪ من الحالات. لكن على الأقل لن تفقد طاولات الالتصاق عندما تحتاج إلى تذكر عنوان IP المصدر للعميل.
الحد من عدد الطلبات المتزامنة من نفس العميل
قد تخضع أي خدمات موجودة في المجال العام ، بما في ذلك واجهات برمجة التطبيقات الخاصة بنا ، لتهديدات الطلبات. يمكن أن تكون أسبابها مختلفة تمامًا ، من أخطاء المستخدم ، إلى الهجمات المستهدفة. نحن نستخدم نقاط DDoS بشكل دوري في عناوين IP. غالبًا ما يرتكب العملاء أخطاء في البرامج النصية الخاصة بهم ؛ فهم يرغموننا على استخدام DDoS مصغرة.
بطريقة أو بأخرى ، يجب توفير حماية إضافية. الحل الواضح هو الحد من عدد طلبات API وعدم إضاعة وقت وحدة المعالجة المركزية في معالجة الطلبات الضارة.
لتنفيذ هذه القيود ، نستخدم حدود الأسعار ، المنظمة على أساس HAProxy ، باستخدام نفس الجداول العصي. يتم تكوين الحدود ببساطة شديدة وتسمح لك بتحديد المستخدم بعدد الطلبات على واجهة برمجة التطبيقات. تتذكر الخوارزمية عنوان IP المصدر الذي يتم تقديم الطلبات منه ، وتحد من عدد الطلبات المتزامنة من مستخدم واحد. بالطبع ، قمنا بحساب ملف تعريف تحميل واجهة برمجة التطبيقات (API) لكل خدمة ، وحدد الحد الأقصى ≈ 10 أضعاف هذه القيمة. حتى الآن ، نواصل مراقبة الوضع عن كثب ، ونضع إصبعنا على النبض.
كيف تبدو في الممارسة العملية؟ لدينا عملاء يستخدمون واجهات برمجة التطبيقات autoscale باستمرار. يقومون بإنشاء ما يقرب من مائتي أو ثلاثمائة جهاز افتراضي أقرب إلى الصباح وحذفها أقرب إلى المساء. بالنسبة إلى OpenStack ، قم بإنشاء جهاز افتراضي ، مع خدمات PaaS ، على الأقل 1000 من طلبات API ، حيث يحدث التفاعل بين الخدمات أيضًا من خلال واجهة برمجة التطبيقات.
مثل هذه المهمة تسبب حمولة كبيرة إلى حد ما. قدرنا هذا الحمل ، الذي تم جمعه القمم اليومية ، وزادها بعشرة أضعاف ، وأصبح هذا الحد الأقصى لسعرنا. نبقي إصبعنا على النبض. غالبًا ما نرى روبوتات وماسحات ضوئية تحاول أن تنظر إلينا ، فهل لدينا أي نصوص CGA يمكن تشغيلها ، ونقطعها فعليًا.
كيفية تحديث قاعدة الشفرة تكتم للمستخدمين
كما نقوم بتنفيذ التسامح مع الخطأ على مستوى عمليات نشر التعليمات البرمجية. هناك تعطل أثناء النشرات ، ولكن يمكن تقليل تأثيرها على توفر الخدمة.
نقوم باستمرار بتحديث خدماتنا ويجب أن نضمن عملية تحديث قاعدة الشفرة دون تأثير للمستخدمين. لقد نجحنا في حل هذه المشكلة باستخدام إمكانات إدارة HAProxy وتنفيذ إيقاف التشغيل الرشيق في خدماتنا.
لحل هذه المشكلة ، كان من الضروري توفير التحكم في الموازن والإغلاق "الصحيح" للخدمات:
- في حالة HAProxy ، يتم التحكم من خلال ملف الإحصائيات ، والذي هو في الأساس مأخذ توصيل ويتم تعريفه في تكوين HAProxy. يمكنك إرسال الأوامر إليها من خلال stdio. لكن أداة التحكم في التكوين الرئيسية الخاصة بنا هي أداة مرئية ، لذلك فهي تحتوي على وحدة مدمجة لإدارة HAProxy. الذي نستخدمه بنشاط.
- تدعم معظم خدمات API و Engine الخاصة بنا تقنيات إيقاف التشغيل الرائعة: عند إيقاف التشغيل ، تنتظر المهمة الحالية لإكمالها ، سواء أكان ذلك طلب http أو مهمة من نوع الأداة المساعدة. نفس الشيء يحدث مع العامل. إنه يعرف كل المهام التي يقوم بها ، وينتهي عندما ينهي كل شيء بنجاح.
بفضل هاتين النقطتين ، فإن الخوارزمية الآمنة لنشرنا هي كما يلي.
- يقوم المطور بإنشاء حزمة تعليمات برمجية جديدة (لدينا RPM) ، واختبارات في بيئة dev ، واختبارات في المرحلة ، ويتركها في مستودع المرحلة.
- يضع المطور المهمة على عملية النشر مع الوصف الأكثر تفصيلا لـ "الأعمال الفنية": إصدار الحزمة الجديدة ، ووصف للوظيفة الجديدة وتفاصيل أخرى حول النشر ، إذا لزم الأمر.
- يبدأ مسؤول النظام الترقية. يقوم بتشغيل كتاب Ansible ، والذي بدوره يقوم بما يلي:
- يستغرق حزمة من مستودع المرحلة ، وتحديث إصدار الحزمة في مستودع المنتج معها.
- يجعل قائمة من الخلفية للخدمة المحدثة.
- يتم إيقاف تشغيل الخدمة المحدثة الأولى في HAProxy وينتظر انتهاء عملياتها. بفضل الإغلاق الرشيق ، نحن على ثقة من أن جميع طلبات العميل الحالية ستكتمل بنجاح.
- بعد توقف API والعمال و HAProxy تمامًا ، يتم تحديث الرمز.
- Ansible تطلق الخدمات.
- لكل خدمة ، تقوم بسحب بعض "الأقلام" التي تقوم باختبار الوحدة لعدد من اختبارات المفاتيح المحددة مسبقًا. يحدث فحص أساسي للرمز الجديد.
- إذا لم يتم العثور على أخطاء في الخطوة السابقة ، يتم تنشيط الواجهة الخلفية.
- انتقل إلى الخلفية التالية.
- بعد تحديث جميع الخلفية ، يتم إطلاق اختبارات وظيفية. إذا لم تكن كافية ، فسيقوم المطور بالبحث عن أي وظائف جديدة قام بها.
على هذا النشر اكتمال.
دورة تحديث الخدمةلن يعمل هذا المخطط إذا لم يكن لدينا قاعدة واحدة. نحن ندعم كل من الإصدارات القديمة والجديدة في المعركة. مقدما ، في مرحلة تطوير البرمجيات ، يتم توضيح أنه حتى لو كانت هناك تغييرات في قاعدة بيانات الخدمة ، فلن يخرقوا الكود السابق. نتيجة لذلك ، يتم تحديث قاعدة الشفرة تدريجياً.
استنتاج
بمشاركة أفكاري الخاصة حول بنية WEB المتسامحة مع الأخطاء ، أود أن أشير مرة أخرى إلى النقاط الرئيسية:
- خطأ جسدي التسامح.
- خطأ شبكة التسامح (الموازن ، BGP) ؛
- خطأ التسامح من البرامج المستخدمة والمطورة.
كل الجهوزية مستقرة!