قائمة التحقق: ما الذي يجب القيام به قبل بدء خدمات micros في همز

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


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


إذا كنت تشعر أن الوقت قد حان لإطلاق تطبيق آخر في Kubernetes / ECS / مهما كان الأمر ، عندها لدي شيء لأعترض عليه.


إصدار اللغة الإنجليزية هو متاح أيضا .


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


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


دعنا نذهب ....


ملاحظة: ترتيب العناصر لا يهم. على أي حال ، بالنسبة لي.


التمهيدي وصف قصير


يحتوي على وصف قصير لنفسه في بداية Readme.md في مستودعها.

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


التكامل مع نظام الرصد


يرسل مقاييس إلى DataDog و NewRelic و Prometheus وما إلى ذلك.

تحليل استهلاك الموارد ، وتسريبات الذاكرة ، والمكدس ، وترابط الخدمة ، ومعدل الخطأ - دون فهم كل هذا (وليس فقط) ، من الصعب للغاية التحكم في ما يحدث في تطبيق كبير موزع.


تنبيهات تكوينها


تتضمن الخدمة تنبيهات تغطي جميع المواقف القياسية بالإضافة إلى مواقف فريدة معروفة.

المقاييس جيدة ، لكن لا أحد سيتابعها. لذلك ، نتلقى المكالمات / push / sms تلقائيًا إذا:


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

Runbooks التي تم إنشاؤها


تم إنشاء مستند للخدمة التي تصف حالات الطوارئ المعروفة أو المتوقعة.

  • كيفية التأكد من أن الخطأ داخلي ولا يعتمد على جهة خارجية ؛
  • إذا كان يعتمد على من ولمن وماذا يكتب ؛
  • كيفية إعادة تشغيله بأمان ؛
  • كيفية استعادة من النسخ الاحتياطي وأين تكمن النسخ الاحتياطية ؛
  • ما هي لوحات / استعلامات خاصة يتم إنشاؤها لمراقبة هذه الخدمة ؛
  • هل لدى الخدمة لوحة إدارة خاصة بها وكيف تصل إلى هناك ؛
  • هل هناك API / CLI وكيفية استخدامها لإصلاح المشكلات المعروفة ؛
  • و هكذا.

يمكن أن تختلف القائمة اختلافًا كبيرًا بين المنظمات ، ولكن يجب أن تكون هناك أشياء أساسية على الأقل.


تتم كتابة جميع السجلات في STDOUT / STDERR


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

عندما ينشئ تطبيق ملفات السجل ، تكون هذه السجلات عديمة الفائدة. لن تذهب إلى 5 حاويات تعمل على التوازي ، على أمل اكتشاف الخطأ الذي تحتاجه (وهنا تبكي ...). ستؤدي إعادة تشغيل الحاوية إلى فقد كامل لهذه السجلات.


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


يكتب التطبيق جزءًا من السجلات إلى الملفات ، وجزءًا إلى stdout لأنه مناسب للمطور لرؤية INFO في وحدة التحكم ، و DEBUG في الملفات؟ هذا هو عموما الخيار الأسوأ. لا أحد يحتاج إلى تعقيد ورمز وتكوينات زائدة عن الحاجة بالكامل تحتاج إلى معرفتها وصيانتها.


سجلات هي Json


كل سطر سجل مكتوب بتنسيق Json ويحتوي على مجموعة متسقة من الحقول

حتى الآن ، الجميع تقريبا يكتب سجلات في نص عادي. هذه كارثة حقيقية. سأكون سعيدًا بمعرفة أنماط Grok . أحلم بها أحيانًا وأتجمد ، وأحاول ألا أتحرك ، حتى لا تجذب انتباههم. مجرد محاولة لتحليل استثناءات جافا في سجلات مرة واحدة.


Json جيد ، إنه نار من السماء. فقط أضف هناك:


  • مللي ثانية الطابع الزمني وفقا ل RFC 3339 ؛
  • المستوى: معلومات ، تحذير ، خطأ ، تصحيح
  • user_id ؛
  • app_name
  • وغيرها من المجالات.

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


(ويمكنك إضافة طلب معرف والحصول على تتبع ...)


سجلات مع مستويات اللامع


يجب أن يدعم التطبيق متغير بيئة ، على سبيل المثال LOG_LEVEL ، مع وضعي تشغيل على الأقل: ERRORS و DEBUG.

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


إصدارات التبعية الثابتة


يتم إصلاح التبعيات لمديري الحزم ، بما في ذلك الإصدارات الثانوية (على سبيل المثال ، cool_framework = 2.5.3).

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


مرسى


يحتوي المستودع على Dockerfile جاهز للإنتاج و docker-compose.yml

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


تكوين البيئة


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

لن يرغب أحد في قراءة ملفات التكوين الخاصة بك ودراسة تنسيقها. فقط اقبلها.


مزيد من التفاصيل هنا: https://12factor.net/config


تحقيقات والاستعداد الصلاحيات


يحتوي على نقاط نهاية مناسبة أو أوامر cli لاختبار الاستعداد لخدمة الطلبات عند بدء التشغيل ووقت التشغيل طوال الحياة.

إذا كان التطبيق يخدم طلبات HTTP ، فيجب أن يكون له واجهاتان افتراضيًا:


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


  2. للتحقق من أن التطبيق لم يبدأ ، ولكنه جاهز لقبول الطلبات ، يتم إجراء اختبار الجاهزية. إذا كان التطبيق قد أنشأ اتصالًا بقاعدة البيانات ونظام انتظار الانتظار وما إلى ذلك ، فيجب أن يستجيب بحالة من 200 إلى 400 (بالنسبة إلى Kubernetes).



حدود الموارد


يحتوي على قيود على استهلاك الذاكرة ووحدة المعالجة المركزية ومساحة القرص وأي موارد أخرى متاحة بتنسيق ثابت.

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


التجميع والتسليم الآلي


تم تكوين نظام CI / CD المستخدم في مؤسستك أو مشروعك ويمكنه تسليم التطبيق إلى البيئة المطلوبة وفقًا لسير العمل المقبول.

لا يتم تسليم أي شيء إلى الإنتاج يدويًا.


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


إغلاق رشيقة - الاغلاق الصحيح


يمكن للتطبيق معالجة SIGTERM وإشارات أخرى ومقاطعة عمله بشكل منهجي بعد نهاية معالجة المهمة الحالية.

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


إذا كنت لا تتحكم في أي من التبعيات ولا يمكنك ضمان أن الكود الخاص بك سيعالج SIGTERM بشكل صحيح ، فاستخدم شيئًا مثل dumb-init .


مزيد من المعلومات هنا:



فحص اتصال قاعدة البيانات بانتظام


يدقق التطبيق باستمرار في قاعدة البيانات ويستجيب تلقائيًا لاستثناء "فقد الاتصال" لأي طلبات ، أو يحاول استعادتها من تلقاء نفسه أو إنهاء عمله بشكل صحيح

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


تحجيم أفقيا


مع زيادة التحميل ، يكفي تشغيل المزيد من مثيلات التطبيق لضمان معالجة جميع الطلبات أو المهام.

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


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


طوابير الرسائل الميتة ومرونة الرسائل السيئة


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

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


الأسوأ من ذلك ، عندما يتم تدمير رسالة ببساطة في حالة الفشل.


قيود على عدد الرسائل والمهام التي تمت معالجتها لكل عملية


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

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


لا يستخدم تكامل الجهات الخارجية مع التصفية حسب عناوين IP


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

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


واضح وكيل المستخدم HTTP


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

عندما يكون لديك 100 تطبيق مختلف يتحدثون مع بعضهم البعض ، يمكنك بالجنون رؤية في سجلات شيء مثل "Go-http-client / 1.1" وعنوان IP الحيوي لحاوية Kubernetes. حدد دائمًا طلبك وإصداره بشكل صريح.


لا ينتهك الترخيص


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

هذه حالة بديهية ، ولكن حدث أن نرى أنه حتى المحامي الذي كتب NDA الآن الفواق.


لا يستخدم التبعيات غير المدعومة


عند بدء تشغيل الخدمة لأول مرة ، لا يشمل التبعيات التي عفا عليها الزمن بالفعل.

إذا لم يعد أي شخص يدعم المكتبة التي أخذتها في المشروع - فابحث عن طريقة أخرى لتحقيق الهدف أو تطوير المكتبة نفسها.


الخاتمة


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

Source: https://habr.com/ru/post/ar438064/


All Articles