كيف ولماذا قامت Lyft بتحسين Kubernetes CronJobs

تقريبا. ترجمة. كتب هذا المقال ، المكون من جزأين ، كيفين يانغ ، مهندس برمجيات في Lyft ، المعروف جيدًا في مجتمع Kubernetes لأنه أنشأ Envoy على الأقل. في المادة الجديدة ، يشارك المؤلف تجربة مثيرة للاهتمام لترحيل عدد كبير من مهام cron التقليدية من Linux إلى CronJobs في K8s. يمكنك أن تعرف بالتفصيل المشاكل التي أدت إلى ذلك عبر Lyft وكيف تم حلها بواسطة مهندسي الشركة.







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



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



أولاً ، سنصف أوجه القصور في Kubernetes CronJobs التي واجهناها عند استخدامها في Lyft. ثم (في الجزء الثاني) - سنخبرك بكيفية التخلص من هذه العيوب في حزمة Kubernetes ، وزيادة قابلية الاستخدام وتحسين الموثوقية.



الجزء 1. مقدمة



من سيستفيد من هذه المقالات؟



  • مستخدمو Kubernetes CronJob.
  • , Kubernetes.
  • , Kubernetes .
  • , Kubernetes , .
  • Contributor' Kubernetes.


?



  • , Kubernetes ( , CronJob) .
  • , Kubernetes Lyft , .


:







  • ronjobcontroller — Kubernetes, CronJob'.
  • , cron , ( ).
  • Lyft Engineering , ( «», « », « ») — Lyft ( «», « », «» «»). , , «-» .


CronJob' Lyft



اليوم ، لدينا بيئة إنتاج متعددة المستأجرين لديها ما يقرب من 500 وظيفة كرون تسمى أكثر من 1500 مرة في الساعة.



تستخدم Lyft المهام المجدولة المتكررة على نطاق واسع لمجموعة متنوعة من الأغراض. قبل الانتقال إلى Kubernetes ، تم تشغيلهم مباشرة على أجهزة Linux باستخدام Unix cron العادي. كانت فرق التطوير مسؤولة عن كتابة crontabالتعاريف وتوفير المثيلات ، والتي نفذتها باستخدام خطوط أنابيب البنية التحتية كرمز (IaC) ، وكان فريق البنية التحتية مسؤولاً عن صيانتها.



كجزء من جهد أكبر لحاوية وترحيل أعباء العمل إلى منصة Kubernetes الخاصة بنا ، قررنا الانتقال إلى CronJob * ، واستبدال Unix cron الكلاسيكي بنظيره Kubernetes. مثل العديد من الآخرين ، تم اختيار Kubernetes بسبب مزاياها الهائلة (على الأقل من الناحية النظرية) ، بما في ذلك الاستخدام الفعال للموارد.



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





حدود المسؤولية للمطورين ومهندسي النظام الأساسي في Lyft Stack



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



ومع ذلك ، يبدو كل شيء جيدًا على الورق. في الممارسة العملية ، لقد حددنا العديد من الاختناقات عند الانتقال من بيئة كرون تقليدية مدروسة جيدًا إلى بيئة CronJob الموزعة سريعة الزوال في Kubernetes.



* على الرغم من أن CronJob كان ولا يزال (اعتبارًا من Kubernetes v1.18) في حالة تجريبية ، وجدنا أنه يلبي احتياجاتنا تمامًا في ذلك الوقت ويتناسب تمامًا أيضًا مع بقية مجموعة أدوات البنية التحتية Kubernetes لدينا ...



كيف يختلف Kubernetes CronJob عن Unix cron؟





تسلسل مبسط للأحداث ومكونات برنامج K8s المتضمنة في عمل Kubernetes CronJob



لتوضيح سبب ارتباط العمل مع Kubernetes CronJob في بيئة إنتاج بصعوبات معينة ، دعنا أولاً نحدد كيف تختلف عن تلك الكلاسيكية. من المفترض أن يعمل CronJob بنفس طريقة وظائف Linux أو Unix cron ؛ ومع ذلك، هناك فعلا ما لا يقل عن بضعة اختلافات كبيرة في سلوكهم: سرعة بدء التشغيل و معالجة تحطم .



سرعة الإطلاق



يتم تعريف تأخير البدء (تأخير البدء) على أنه الوقت المنقضي من تاريخ البدء المجدول حتى البداية الفعلية لكود التطبيق. بمعنى آخر ، إذا تمت جدولة cron للبدء في 00:00:00 وبدأ تشغيل التطبيق في 00:00:22 ، فسيكون التأخير في بدء هذا cron المحدد 22 ثانية.



في حالة Unix crons الكلاسيكية ، يكون تأخير بدء التشغيل ضئيلًا. عندما يحين الوقت المناسب ، يتم تنفيذ هذه الأوامر ببساطة. دعنا نؤكد ذلك بالمثال التالي:



#   date    
0 0 * * * date >> date-cron.log


باستخدام تكوين cron مثل هذا ، سنحصل على الأرجح على المخرجات التالية في date-cron.log:



Mon Jun 22 00:00:00 PDT 2020
Tue Jun 23 00:00:00 PDT 2020


من ناحية أخرى ، يمكن أن يواجه Kubernetes CronJob تأخيرات كبيرة في بدء التشغيل لأن التطبيق يسبقه عدد من الأحداث. فيما يلي بعض منهم:



  1. cronjobcontroller العمليات وتقرر استدعاء CronJob ؛
  2. cronjobcontroller إنشاء وظيفة بناءً على مواصفات وظيفة CronJob ؛
  3. jobcontroller يلاحظ وظيفة جديدة ويقوم بإنشاء جراب ؛
  4. تُدرج وحدة التحكم في الدخول بيانات الحاوية الجانبية في مواصفات Pod * ؛
  5. kube-scheduler تخطيط قرنة على kubelet ؛
  6. kubelet يطلق Pod (جلب جميع صور الحاويات) ؛
  7. kubelet يبدأ جميع حاويات السيارة الجانبية * ؛
  8. kubelet يبدأ حاوية التطبيق *.


* هذه المراحل خاصة بمكدس Lyft Kubernetes.



لقد وجدنا أن العناصر 1 و 5 و 7 تقدم المساهمة الأكثر أهمية في زمن الانتقال بمجرد وصولنا إلى مقياس معين من CronJob في بيئة Kubernetes.



تأخير بسبب العمل cronjobcontroller'



لفهم مصدر وقت الاستجابة بشكل أفضل ، دعنا نفحص شفرة المصدر المضمنة cronjobcontroller'. في Kubernetes 1.18 ، cronjobcontrollerيتحقق فقط من جميع CronJob كل 10 ثوانٍ ويدير بعض المنطق في كل منها.



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



تؤدي دورة الاقتراع التي تبلغ 10 ثوانٍ واستدعاءات واجهة برمجة التطبيقات من جانب العميل إلى زيادة ملحوظة في تأخير إطلاق CronJob.



جدولة القرون مع كرونز



نظرًا لطبيعة جدول cron ، يعمل معظمهم في بداية الدقيقة (XX: YY: 00). على سبيل المثال ، @hourlyيعمل cron (كل ساعة) في 01:00:00 ، 02:00:00 ، إلخ في حالة نظام cron متعدد المستأجرين مع تشغيل العديد من crons كل ساعة ، كل ربع ساعة ، كل 5 دقائق ، وما إلى ذلك ، يؤدي هذا إلى اختناقات (نقاط ساخنة) عند بدء تشغيل العديد من crons في نفس الوقت. لاحظنا في Lyft أن أحد هذه الأماكن هو بداية الساعة (XX: 00: 00). تخلق هذه النقاط الفعالة حملًا وتؤدي إلى زيادة الحد من تكرار الطلبات في مكونات طبقة التحكم المشاركة في تنفيذ CronJob ، مثل kube-schedulerو kube-apiserver، مما يؤدي إلى زيادة ملحوظة في تأخير بدء التشغيل.



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



إطلاق جراب: حاويات مساعدة



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



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



التعامل مع تحطم الحاويات



بشكل عام ، يوصى بمراقبة عمل crons. بالنسبة لأنظمة Unix ، من السهل جدًا القيام بذلك. يفسر crones في Unix الأمر المحدد باستخدام الغلاف المحدد $SHELL، وبعد خروج الأمر (ناجحًا أم لا) ، تعتبر هذه المكالمة الخاصة مكتملة. يمكنك تتبع تنفيذ cron على نظام Unix باستخدام برنامج نصي بسيط مثل هذا:



#!/bin/sh

my-cron-command
exitcode=$?

if [[ $exitcode -ne 0 ]]; then
    # stat-and-log is pseudocode for emitting metrics and logs
    stat-and-log "failure"
else
    stat-and-log "success"
fi

exit $exitcode


في حالة نظام Unix ، stat-and-logسيتم تشغيل cron مرة واحدة بالضبط لكل مكالمة cron - بغض النظر عن $exitcode. لذلك ، يمكن استخدام هذه المقاييس لتنظيم أبسط الإخطارات حول المكالمات غير الناجحة.



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



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



يمكنك تنفيذ التنبيهات على مستوى الوظيفة ، وليس على مستوى حاوية التطبيق. لهذا ، تتوفر مقاييس مستوى API لفشل الوظيفة ، مثل kube_job_status_failedمن kube-state-metrics. عيب هذا النهج هو أن المهندس المناوب لا يدرك المشكلة إلا بعد أن تصل الوظيفة إلى "مرحلة الفشل النهائي" وتصل إلى الحد الأقصى BackoffLimit، وهو ما يمكن أن يحدث في وقت متأخر كثيرًا عن الفشل الأول لحاوية التطبيق.



CronJob'



تؤدي دورات تأخير البدء وإعادة التشغيل الكبيرة إلى زمن انتقال إضافي يمكن أن يمنع إعادة تنفيذ Kubernetes CronJob. في حالة CronJob's التي يتم استدعاؤها بشكل متكرر ، أو تلك التي تحتوي على أوقات تشغيل أطول بكثير من وقت الخمول ، يمكن أن يتسبب هذا التأخير الإضافي في حدوث مشكلات في المكالمة المجدولة التالية. إذا كان CronJob لديها سياسة ConcurrencyPolicy: Forbidالتي تحظر التزامن ، نتائج تأخير في المستقبل مكالمات لم يتم الانتهاء في الوقت المحدد وتأخر.





مثال على جدول زمني (من وجهة نظر cronjobcontroller) يتم فيه تجاوز startDeadlineSeconds لساعة معينة CronJob: يتخطى بدايته المجدولة ولن يتم استدعاؤه حتى الوقت المجدول التالي



هناك أيضًا سيناريو غير سارٍ (واجهناه في Lyft) ، والذي بسببه يمكن لـ CronJob تخطي المكالمات تمامًا - هذا عندما يتم تثبيت CronJob startingDeadlineSeconds. في هذا السيناريو ، إذا تجاوز تأخير بدء التشغيل startingDeadlineSeconds، فسيتخطى CronJob البدء تمامًا.



بالإضافة إلى ذلك ، إذا ConcurrencyPolicyتم تعيين CronJob على Forbid، فإن دورة إعادة التشغيل عند الفشل للمكالمة السابقة يمكن أن تتداخل أيضًا مع مكالمة CronJob التالية.



مشاكل في تشغيل Kubernetes CronJob في ظروف الحياة الواقعية



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



المطورون استغلال CronJob وتهيئتهم ، ولكن نتيجة لذلك ، جاءوا إلينا مع الكثير من الشكاوى والأسئلة مثل هذه:



  • لماذا لا يعمل كرون الخاص بي؟
  • يبدو أن كرون الخاص بي قد توقف عن العمل. كيف يمكنك التأكد من أنه يعمل بالفعل؟
  • لم أكن أعرف أن كرون لا يعمل واعتقدت أن كل شيء على ما يرام.
  • كيف يمكنني "إصلاح" كرون مفقود؟ لا يمكنني فقط تسجيل الدخول عبر SSH وتشغيل الأمر بنفسي.
  • هل يمكن أن تخبرني لماذا يبدو أن هذا الكرون قد فاته عدة دورات بين X إلى Y؟
  • لدينا X (عدد كبير) من crons ، ولكل منها إشعاراتها الخاصة ، ويصبح من الصعب جدًا / من الصعب الحفاظ عليها جميعًا.
  • جراب ، أيوب ، عربة جانبية - أي نوع من الهراء هذا؟


كفريق منصة ، لم نتمكن من الإجابة على أسئلة مثل:



  • كيف يمكن قياس أداء منصة Kubernetes cron؟
  • كيف سيؤثر تمكين CronJob's الإضافية على بيئة Kubernetes؟
  • Kubernetes CronJob' ( multi-tenant) single-tenant cron' Unix?
  • Service-Level-Objectives (SLOs — ) ?
  • , , , ?


تصحيح أخطاء CronJob ليست مهمة سهلة. غالبًا ما يتطلب الأمر الحدس لفهم مكان حدوث الفشل وأين يتم البحث عن الأدلة. في بعض الأحيان يصعب الحصول على هذه القرائن - على سبيل المثال ، السجلات cronjobcontroller'التي يتم تسجيلها فقط في حالة تمكين المستوى العالي من التفاصيل. بالإضافة إلى ذلك ، يمكن أن تختفي الآثار ببساطة بعد فترة زمنية معينة ، مما يجعل تصحيح الأخطاء مشابهًا للعبة "Kick a mole" (حول هذا - الترجمة تقريبًا) - على سبيل المثال ، أحداث Kubernetes لـ CronJob'ov و Job'ov و Pod'ov والتي يتم الاحتفاظ بها افتراضيًا لمدة ساعة فقط. لا تعتبر أي من هذه الطرق سهلة الاستخدام ، ولا يتسع أي منها بشكل جيد من حيث الدعم مع تزايد عدد CronJob's على النظام الأساسي.



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



يختتم هذا غوصتي في المشكلات الفنية والتشغيلية التي واجهناها عند استخدام Kubernetes CronJob في مشروع مزدحم. في الجزء الثاني ، سنتحدث عن كيفية التخلص من Kubernetes في مجموعتنا ، وتحسين قابلية الاستخدام وتحسين موثوقية CronJob.



الجزء 2. مقدمة



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



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



التي استغرقها رمز التطبيق؟) 2. تبسيط صيانة النظام الأساسي من خلال جعل CronJob أكثر قابلية للفهم ودورة حياتها أكثر شفافية وحدود النظام الأساسي / التطبيق أكثر وضوحًا.



3. استكمل منصتنا بمقاييس وتنبيهات قياسية لتقليل مقدار تكوين التنبيه المخصص وتقليل عدد روابط cron المكررة التي يتعين على المطورين كتابتها والحفاظ عليها.



4. تطوير أدوات للتعافي السهل واختبار تكوينات CronJob الجديدة.



5. إصلاح المشكلات الفنية طويلة الأمد في Kubernetes ، مثل خطأ TooManyMissedStarts الذي يتطلب تدخلًا يدويًا لإصلاحه ويسبب تعطلًا في أحد سيناريوهات الفشل المهمة ( عندما لا يتم تعيين قيمة startDeadlineSeconds ) دون أن يلاحظها أحد.



القرار



لقد حللنا كل هذه المشاكل على النحو التالي:



  1. (observability). CronJob', (Service Level Objectives, SLOs) .
  2. CronJob' « » Kubernetes.
  3. Kubernetes.


CronJob'





مثال على لوحة معلومات تم إنشاؤها بواسطة النظام الأساسي لمراقبة CronJob معين



لقد أضفنا المقاييس التالية إلى مكدس Kubernetes (تم تعريفها لجميع CronJob في Lyft):



1. started.count- تتم زيادة هذا العداد عند تشغيل حاوية التطبيق لأول مرة عند استدعاء CronJob. يساعد في الإجابة على السؤال ، " هل تم تشغيل كود التطبيق؟ ".



2. {success, failure}.count- تتم زيادة هذه العدادات عندما تصل مكالمة CronJob معينة إلى الحالة النهائية (أي أن الوظيفة أنهت وظيفتها jobcontrollerولم تعد تحاول تنفيذها). يجيبون على السؤال: " هل كان الإطلاق ناجحًا؟ ".



3. scheduling-decision.{invoke, skip}.count- هذه العداداتتسمح لك بمعرفة القرارات التي يتم اتخاذها cronjobcontrollerعند الاتصال بـ CronJob. على وجه الخصوص ، من المفيد skip.countالإجابة على السؤال: " لماذا لا يعمل cron الخاص بي؟ ". تعمل التسميات التالية كمعلمات لها reason:



  • reason = concurrencyPolicy- cronjobcontrollerفاتته المكالمة إلى CronJob ، وإلا فإنه سيؤدي إلى كسرها ConcurrencyPolicy؛
  • reason = missedDeadline- cronjobcontrollerرفض الاتصال بـ CronJob ، لأنه فاته نافذة الاتصال المحددة .spec.startingDeadlineSeconds؛
  • reason = error هي معلمة مشتركة لجميع الأخطاء الأخرى التي تحدث عند محاولة استدعاء CronJob.


4. app-container-duration.seconds- يقيس هذا المؤقت عمر حاوية التطبيق. يساعد في الإجابة على السؤال: "ما هي مدة تشغيل رمز التطبيق؟ ". في هذا الموقت ، لم نقم بتضمين الوقت اللازم لجدولة البودات ، وإطلاق الحاويات الجانبية ، وما إلى ذلك ، نظرًا لأنها مسؤولية فريق النظام الأساسي ويتم تضمينها في تأخير الإطلاق.



5. start-delay.seconds- يقيس هذا المؤقت تأخير البدء. هذا المقياس ، عند تجميعه عبر النظام الأساسي ، يسمح للمهندسين الذين يقومون بصيانته ليس فقط بتقييم أداء النظام الأساسي ومراقبته وضبطه ، ولكنه يعمل أيضًا كأساس لتحديد SLO للمعلمات مثل تأخير بدء التشغيل والحد الأقصى لتردد جدول cron.



بناءً على هذه المقاييس ، أنشأنا تنبيهات افتراضية. يخطرون المطورين عندما:



  • لم يبدأ CronJob الخاص بهم في الموعد المحدد ( rate(scheduling-decision.skip.count) > 0) ؛
  • فشل CronJob الخاص بهم ( rate(failure.count) > 0).


لم يعد المطورون بحاجة إلى تحديد التنبيهات والمقاييس الخاصة بهم للكرونات في Kubernetes - يوفر النظام الأساسي نظرائهم الجاهزين.



تشغيل كرونز إذا لزم الأمر



قمنا بتكييفه مع kubectl create job test-job --from=cronjob/<your-cronjob>أداة CLI الداخلية الخاصة بنا. يستخدمه المهندسون في Lyft للتفاعل مع خدماتهم على Kubernetes للاتصال بـ CronJob عند الحاجة إلى:



  • التعافي من حوادث CronJob المتقطعة ؛
  • runtime- , 3:00 ( , CronJob', Job' Pod' ), — , ;
  • runtime- CronJob' Unix cron', , .


TooManyMissedStarts



لقد أصلحنا الخلل في TooManyMissedStarts بحيث لا "يتعطل" الآن CronJob بعد 100 بداية متتالية فائتة. هذا التصحيح ليس فقط لإزالة الحاجة إلى التدخل اليدوي، ولكن يسمح لك فعلا تتبع عند الوقت startingDeadlineSeconds تجاوز . بفضل Vallery Lancey لتصميم وبناء هذا التصحيح ، ساعد Tom Wanielista في تصميم الخوارزمية. لقد فتحنا PR لإحضار هذا التصحيح إلى فرع Kubernetes الرئيسي (ومع ذلك ، لم يتم اعتماده مطلقًا ، وتم إغلاقه بسبب عدم النشاط - الترجمة تقريبًا) .



تنفيذ مراقبة كرون





في أي مراحل من دورة حياة Kubernetes CronJob أضفنا آليات تصدير المقاييس



التنبيهات التي لا تعتمد على جداول كرون



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



#   5 
*/5 * * * *


يمكنك عمل العداد لهذه الزيادة في كرون في كل مرة يخرج فيها (أو استخدم ربط كرون ). بعد ذلك ، في نظام الإشعارات ، يمكنك كتابة تعبير شرطي للنموذج: "انظر إلى الدقائق الستين السابقة وأخبرني إذا زاد العداد بأقل من 12". تم حل المشكلة ، أليس كذلك؟



ولكن ماذا لو كان جدولك يبدو كالتالي:



#       9  17
#        .
#  ,    (9-17, -)
0 9–17 * * 1–5


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



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


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



هناك طريقة أخرى للنظر إلى المشكلة وهي أن تسأل نفسك: ما الذي يعنيه أن cron كان يجب أن يبدأ ولكنه لم يبدأ؟



في Kubernetes ، إذا نسيت الأخطاء فيcronjobcontroller'أو احتمال السقوط في مستوى التحكم نفسه (على الرغم من أنه يجب أن ترى هذا فورًا إذا cronjobcontrollerتتبعت حالة الكتلة بشكل صحيح) - هذا يعني أن CronJob قيمت وقررت (وفقًا لجدول cron) أنه يجب استدعائها ، ولكن لسبب ما السبب في أنني قررت عمدا عدم القيام بذلك .



يبدوا مألوفا؟ هذا بالضبط ما يفعله مقياسنا scheduling-decision.skip.count! الآن نحتاج فقط إلى تتبع التغيير rate(scheduling-decision.skip.count)لإخطار المستخدم بأنه كان يجب تشغيل CronJob الخاص به ، لكنه لم يحدث.



يفصل هذا الحل جدول cron عن الإشعار نفسه ، مما يوفر العديد من الفوائد:



  • الآن لا تحتاج إلى إعادة تكوين التنبيهات عند تغيير الجداول.
  • ليست هناك حاجة لطلبات وشروط زمنية معقدة.
  • يمكنك بسهولة إنشاء تنبيهات افتراضية لجميع CronJob's على النظام الأساسي.


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



تنفيذ موقت تأخير البدء



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



  • T1: متى يجب بدء تشغيل cron (وفقًا لجدولها الزمني).
  • T2: عندما يبدأ تنفيذ التعليمات البرمجية للتطبيق بالفعل.


في هذه الحالة start delay(تأخير البدء) = 2 — 1. لإصلاح اللحظة T1 ، قمنا بتضمين الكود في منطق استدعاء cron في ملف cronjobcontroller'. يسجل وقت البدء المتوقع مثل .metadata.Annotationكائنات الوظيفة التي cronjobcontrollerيتم إنشاؤها عند استدعاء CronJob. يمكن استرجاعها الآن باستخدام أي عميل API باستخدام طلب عادي GET Job.



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



النتائج



بعد طرح وظائف جديدة وإصلاح الأخطاء ، تلقينا الكثير من التعليقات الإيجابية من المطورين. يستخدم المطورون الآن منصة Kubernetes CronJob الخاصة بنا:



  • لم تعد مضطرًا إلى التفكير في أدوات المراقبة والتنبيهات الخاصة بهم ؛
  • , CronJob' , .. alert' , ;
  • CronJob' , CronJob' « »;
  • ( app-container-duration.seconds).


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



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



خاتمة



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



ملاحظة: يوجد اقتراح تحسين Kubernetes مفتوح (KEP) لإصلاح أوجه القصور في CronJob وترجمة نسختهم المحدثة إلى GA.



بفضل Rithu John و Scott Lau و Scarlett Perry و Julien Silland و Tom Wanielista لمساعدتهم في مراجعة هذه السلسلة من المقالات.



PS من المترجم



اقرأ أيضًا على مدونتنا:






All Articles