حدود وحدة المعالجة المركزية والاختناق العدواني في Kubernetes

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



هل سبق لك أن واجهت حقيقة أن التطبيق "عالق" في مكانه ، وتوقف عن الاستجابة لطلبات الفحص الصحي ، ولم تتمكن من فهم سبب هذا السلوك؟ أحد التفسيرات المحتملة هو حد الحصة النسبية لموارد وحدة المعالجة المركزية. سيتم مناقشته في هذه المقالة.

TL ؛ DR:
نوصي بشدة بإلغاء الاشتراك في حدود CPU في Kubernetes (أو تعطيل حصص CFS في Kubelet) إذا كنت تستخدم إصدار Linux kernel مع وجود خطأ في حصة CFS. في صميم هناكخطأ جسيم ومعروف يؤدي إلى اختناق مفرط وتأخير
.

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

ملخص المقال:

  • بضع كلمات حول الحاويات و Kubernetes ؛
  • كيف يتم تنفيذ طلبات وحدود وحدة المعالجة المركزية ؛
  • كيف يعمل حد وحدة المعالجة المركزية في البيئات متعددة النواة ؛
  • كيفية تتبع وحدة المعالجة المركزية الخانقة ؛
  • حل المشكلة والفروق الدقيقة.

بضع كلمات حول الحاويات و Kubernetes


في الواقع ، Kubernetes هو المعيار الحديث في عالم البنية التحتية. مهمتها الرئيسية هي تنسيق الحاويات.

حاويات


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

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

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

Kubernetes


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


Kubernetes من وجهة نظر شخص عادي بسيط

ما هو الطلب والحد في Kubernetes


حسنًا ، اكتشفنا الحاويات و Kubernetes. نحن نعلم أيضًا أن العديد من الحاويات يمكن أن تكون على نفس الجهاز.

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

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

كيف يتم تنفيذ الطلبات والحدود في Kubernetes


تستخدم Kubernetes آلية اختناق kernel (تخطي الساعة) لتطبيق حدود CPU. إذا تجاوز التطبيق الحد ، يتم تمكين التحكم (أي أنه يتلقى عدد أقل من دورات وحدة المعالجة المركزية). يتم تنظيم طلبات الذاكرة وحدودها بشكل مختلف ، بحيث يسهل اكتشافها. للقيام بذلك ، يكفي التحقق من حالة إعادة تشغيل البودرة الأخيرة: سواء كانت "OOMKilled". مع اختناق وحدة المعالجة المركزية ، كل شيء ليس بهذه البساطة ، لأن K8s توفر فقط المقاييس المتاحة للاستخدام ، وليس للمجموعات.

طلب وحدة المعالجة المركزية



كيفية تنفيذ طلب وحدة المعالجة المركزية من

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

يستخدم K8s آلية cgroups للتحكم في تخصيص الموارد (الذاكرة والمعالج). يتوفر له نموذج هرمي: السليل يرث حدود المجموعة الأم. يتم تخزين تفاصيل التوزيع في نظام الملفات الظاهري ( /sys/fs/cgroup). في حالة المعالج ، هذا /sys/fs/cgroup/cpu,cpuacct/*.

يستخدم K8s الملف cpu.shareلتخصيص موارد المعالج. في حالتنا ، تتلقى مجموعة التحكم الجذر 4096 مشاركة من موارد وحدة المعالجة المركزية - 100 ٪ من طاقة المعالج المتاحة (1 الأساسية = 1024 ؛ هذه قيمة ثابتة). توزع مجموعة الجذر الموارد بشكل متناسب اعتمادًا على حصص المنحدرين الموصوفة فيcpu.share، وهؤلاء بدورهم يفعلون نفس الشيء مع أحفادهم ، إلخ. عادة Kubernetes الجذر المجموعة الضابطة عقدة لديه ثلاثة أطفال: system.slice، user.sliceو kubepods. يتم استخدام أول مجموعتين فرعيتين لتوزيع الموارد بين أحمال النظام الحرجة وبرامج المستخدم خارج K8s. آخر - - kubepodsتم إنشاؤها بواسطة Kubernetes لتوزيع الموارد بين القرون.

يوضح الرسم البياني أعلاه أن المجموعتين الفرعيتين الأولى والثانية تلقت 1024 سهمًا ، مع تخصيص 4096 سهمًا للمجموعة الفرعية kuberpod . كيف يكون ذلك ممكنًا: بعد كل شيء ، لا تملك مجموعة الجذر سوى 4096 سهمًا ، ويتجاوز مجموع أسهم أحفادها هذا الرقم بشكل ملحوظ ( 6144)؟ والحقيقة هي أن القيمة منطقية ، لذلك يستخدمها Linux Scheduler (CFS) لتخصيص موارد وحدة المعالجة المركزية بشكل متناسب. في حالتنا ، تحصل المجموعتان الأوليان على 680 سهمًا حقيقيًا (16.6٪ من 4096) ، وتتلقى kubepod الأسهم الـ 2736 المتبقية . في حالة التوقف ، لن تستخدم المجموعتان الأوليان الموارد المخصصة.

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

تضمن هذه الآلية التوزيع العادل لقوة المعالج وتضمن عدم قيام أي عملية "بسرقة" الموارد من الآخرين.

حد وحدة المعالجة المركزية


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

يستخدم K8s آلية الحصص CFS لتطبيق الحدود. يتم تحديد إعداداتهم في الملفات cfs_period_usوفي cfs_quota_usدليل cgroup (يوجد الملف أيضًا هناك cpu.share).

في المقابل cpu.share، تعتمد الحصة على فترة زمنية ، وليس على قوة المعالج المتاحة. cfs_period_usيحدد مدة الفترة (العصر) - دائمًا ما تكون 100000 μs (100 مللي ثانية). K8s لديها القدرة على تغيير هذه القيمة ، لكنها متوفرة حاليًا فقط في إصدار ألفا. يستخدم المجدول العصر لإعادة تشغيل الحصص المستخدمة. الملف الثانيcfs_quota_us، يحدد الوقت المتاح (الحصة النسبية) في كل عصر. يرجى ملاحظة أنه يشار إليه أيضًا بالميكروثانية. قد تتجاوز الحصة مدة العصر ؛ بمعنى آخر ، يمكن أن يكون أكثر من 100 مللي ثانية.

دعونا نلقي نظرة على سيناريوهين على أجهزة 16 نواة (أكثر أنواع أجهزة الكمبيوتر شيوعًا في Omio):


سيناريوهات السيناريو 1: 2 وحد 200 مللي ثانية. بدون اختناق


السيناريو 2: 10 تدفقات وحد 200 مللي ثانية. اختناق يبدأ بعد 20 مللي ثانية، والوصول إلى موارد المعالج يستأنف بعد 80 مللي آخر.

لنفترض انك تعيين الحد CPU إلى 2 النوى. سيترجم Kubernetes هذه القيمة إلى 200 مللي ثانية. وهذا يعني أنه يمكن للحاوية أن تستخدم وقت CPU بحد أقصى 200 مللي ثانية دون اختناق.

وهنا يبدأ المرح. كما هو مذكور أعلاه ، تبلغ الحصة المتوفرة 200 مللي ثانية. إذا كان لديك عشرة خيوط تعمل بالتوازي على جهاز من 12 نواة (انظر الشكل التوضيحي للسيناريو 2) ، في حين أن جميع القرون الأخرى خاملة ، سيتم استنفاد الحصة في 20 مللي ثانية فقط (منذ 10 * 20 مللي ثانية = 200 مللي ثانية) ، وجميع سلاسل المحادثات من هذا جراب هو خنق لمدة 80 مللي ثانية. خطأ المجدول المذكور بالفعل يزيد من تفاقم الحالة ، بسبب حدوث اختناق مفرط ولا يمكن للحاوية حتى أن تعمل على الحصة الحالية.

كيفية تقييم الاختناق في القرون؟


فقط اذهب لجراب وركض cat /sys/fs/cgroup/cpu/cpu.stat.

  • nr_periods - العدد الإجمالي لفترات المجدول ؛
  • nr_throttled- عدد فترات الاختناق في التكوين nr_periods؛
  • throttled_time - اختناق الوقت التراكمي بالنانو ثانية.



ما الذي يحدث حقا؟


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

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

القرار والعواقب


كل شيء بسيط هنا. تخلينا عن حدود CPU وبدأنا في تحديث نواة نظام التشغيل في مجموعات إلى أحدث إصدار تم فيه إصلاح الخطأ. انخفض عدد الأخطاء (HTTP 5xx) في خدماتنا بشكل ملحوظ:

أخطاء HTTP 5xx



أخطاء HTTP 5xx لخدمة حرجة واحدة

زمن الاستجابة P95



تأخير طلب الخدمة الحرجة ، المئين 95

تكاليف التشغيل



عدد الساعات التي تم قضاؤها

ما هو الصيد؟


كما جاء في بداية المقال:

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

هذا هو الصيد. يمكن لحاوية واحدة مهملة أن تمتص جميع موارد المعالج المتاحة على الجهاز. إذا كان لديك مجموعة تطبيقات ذكية (على سبيل المثال ، تم تكوين JVM و Go و Node VM بشكل صحيح) ، فهذه ليست مشكلة: يمكنك العمل في مثل هذه الظروف لفترة طويلة. ولكن إذا كانت التطبيقات محسنة بشكل سيئ أو لم يتم تحسينها على الإطلاق ( FROM java:latest) ، فقد يخرج الوضع عن السيطرة. نحن في Omio لدينا ملفات Dockerfiles أساسية تلقائية مع إعدادات افتراضية مناسبة لمجموعة اللغات الرئيسية ، لذلك لم يكن هناك مثل هذه المشكلة.

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

المراجع


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


الإبلاغ عن أخطاء Kubernetes:


هل واجهت مشاكل مماثلة في ممارستك أو لديك خبرة في الاختناق في بيئات الإنتاج بالحاويات؟ شارك قصتك في التعليقات!

ملاحظة من المترجم


اقرأ أيضا في مدونتنا:


All Articles