تكوين برنامج Out-Of-Memory Killer على Linux لـ PostgreSQL

تكوين برنامج Out-Of-Memory Killer على Linux لـ PostgreSQL

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

قاتل نفاد الذاكرة

عندما تنفد ذاكرة الخادم أو العملية، يقدم Linux حلين: تعطل النظام بأكمله أو إنهاء العملية (التطبيق) التي تستهلك الذاكرة. من الأفضل بالطبع إنهاء العملية وإنقاذ نظام التشغيل من الانهيار. باختصار، Out-Of-Memory Killer هي عملية تقتل أحد التطبيقات لحفظ النواة من التعطل. إنه يضحي بالتطبيق للحفاظ على تشغيل نظام التشغيل. دعونا نناقش أولاً كيفية عمل OOM وكيفية التحكم فيه، ثم نرى كيف يقرر OOM Killer التطبيق الذي سيتم إنهاؤه.

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

Out of Memory: Killed process 12345 (postgres).

إذا كانت ذاكرة النظام منخفضة ولا يمكن تحريرها، فسيتم استدعاء الوظيفة out_of_memory. في هذه المرحلة، لم يتبق لها سوى شيء واحد للقيام به - إكمال عملية واحدة أو أكثر. هل يجب على OOM-killer إنهاء العملية فورًا أم يمكنه الانتظار؟ من الواضح أنه عند استدعاء out_of_memory، يكون ذلك بسبب انتظار عملية الإدخال/الإخراج أو الترحيل إلى القرص. لذلك، يجب على OOM Killer إجراء عمليات التحقق أولاً، وبناءً عليها، تحديد ضرورة إنهاء العملية. إذا كانت كافة الاختبارات أدناه إيجابية، فسوف يقوم OOM بإنهاء العملية.

اختيار العملية

عند نفاد الذاكرة، يتم استدعاء الدالة out_of_memory(). لديها وظيفة select_bad_process()، الذي يتلقى تقييمًا من الوظيفة badness(). سيتم استهداف العملية "الأسوأ". وظيفة badness() يختار عملية وفقا لقواعد معينة.

  1. تحتاج النواة إلى الحد الأدنى من الذاكرة لنفسها.
  2. تحتاج إلى تحرير الكثير من الذاكرة.
  3. ليست هناك حاجة لإنهاء العمليات التي تستخدم القليل من الذاكرة.
  4. يجب إكمال الحد الأدنى من العمليات.
  5. خوارزميات معقدة تزيد من فرص إكمال تلك العمليات التي يريد المستخدم نفسه إكمالها.

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

postgres=# SELECT pg_backend_pid();
pg_backend_pid 
----------------
    3813
(1 row)

معرف عملية Postgres هو 3813، لذلك في غلاف آخر من الممكن الحصول على النتيجة باستخدام معلمة kernel هذه oom_score:

vagrant@vagrant:~$ sudo cat /proc/3813/oom_score
2

إذا كنت لا تريد أن يقوم OOM-Killer بإنهاء العملية على الإطلاق، فهناك خيار آخر للنواة: oom_score_adj. أضف قيمة سلبية كبيرة لتقليل فرص إكمال العملية التي تقدرها.

sudo echo -100 > /proc/3813/oom_score_adj

لتعيين قيمة oom_score_adj، قم بتعيين OOMScoreAdjust في كتلة الخدمة:

[Service]
OOMScoreAdjust=-1000

او استعمل oomprotect في فريق rcctl.

rcctl set <i>servicename</i> oomprotect -1000

فرض إنهاء العملية

عند تحديد عملية واحدة أو أكثر بالفعل، يستدعي OOM-Killer الوظيفة oom_kill_task(). ترسل هذه الوظيفة إشارة إنهاء للعملية. في حالة نقص الذاكرة oom_kill() تستدعي هذه الوظيفة لإرسال إشارة SIGKILL إلى العملية. تتم كتابة رسالة إلى سجل kernel.

Out of Memory: Killed process [pid] [name].

كيفية التحكم في OOM-Killer

في نظام التشغيل Linux، يمكنك تمكين أو تعطيل OOM-Killer (على الرغم من عدم التوصية بهذا الأخير). لتمكين أو تعطيل استخدام المعلمة vm.oom-kill. لتمكين OOM-Killer في وقت التشغيل، قم بتشغيل الأمر sysctl.

sudo -s sysctl -w vm.oom-kill = 1

لتعطيل OOM-Killer، حدد القيمة 0 في نفس الأمر:

sudo -s sysctl -w vm.oom-kill = 0

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

echo vm.oom-kill = 1 >>/etc/sysctl.conf

هناك طريقة أخرى للتمكين والتعطيل وهي كتابة متغير panic_on_oom. يمكن دائمًا التحقق من القيمة /proc.

$ cat /proc/sys/vm/panic_on_oom
0

إذا قمت بتعيين القيمة على 0، فلن يكون هناك ذعر في kernel عند نفاد الذاكرة.

$ echo 0 > /proc/sys/vm/panic_on_oom

إذا قمت بتعيين القيمة على 1، فعند نفاد الذاكرة، سيحدث ذعر kernel.

echo 1 > /proc/sys/vm/panic_on_oom

لا يمكن تشغيل وإيقاف OOM-Killer فقط. لقد قلنا بالفعل أن Linux يمكنه حجز ذاكرة للعمليات أكبر مما هو متاح دون تخصيصها فعليًا، ويتم التحكم في هذا السلوك بواسطة معلمة Linux kernel. المتغير هو المسؤول عن هذا vm.overcommit_memory.

يمكنك تحديد القيم التالية له:

0: تقرر النواة نفسها ما إذا كانت ستحجز قدرًا كبيرًا من الذاكرة أم لا. هذا هو الإعداد الافتراضي في معظم إصدارات Linux.
1: ستحتفظ النواة دائمًا بذاكرة إضافية. وهذا أمر محفوف بالمخاطر، لأن الذاكرة قد تنفد، لأنه على الأرجح، في يوم من الأيام، ستتطلب العمليات ذلك.
2: لن تقوم النواة بحجز ذاكرة أكبر من تلك المحددة في المعلمة overcommit_ratio.

باستخدام هذه المعلمة، يمكنك تحديد النسبة المئوية للذاكرة المسموح بحجزها بشكل زائد. إذا لم يكن هناك مكان لذلك، فلن يتم تخصيص ذاكرة، وسيتم رفض الحجز. هذا هو الخيار الأكثر أمانًا الموصى به لـ PostgreSQL. يتأثر OOM-Killer بعنصر آخر - وهو إمكانية التبديل، والتي يتحكم فيها المتغير cat /proc/sys/vm/swappiness. تخبر هذه القيم النواة بكيفية التعامل مع الترحيل. كلما ارتفعت القيمة، قل احتمال قيام OOM بإنهاء العملية، ولكن بسبب عمليات الإدخال/الإخراج، يكون لها تأثير سلبي على قاعدة البيانات. والعكس صحيح - كلما انخفضت القيمة، زاد احتمال تدخل OOM-Killer، ولكن أداء قاعدة البيانات أعلى أيضًا. القيمة الافتراضية هي 60، ولكن إذا كانت قاعدة البيانات بأكملها مناسبة للذاكرة، فمن الأفضل تعيين القيمة إلى 1.

نتائج

لا تدع "القاتل" في OOM-Killer يخيفك. في هذه الحالة، سيكون القاتل هو المنقذ لنظامك. إنه "يقتل" أسوأ العمليات ويحفظ النظام من الانهيار. لتجنب الاضطرار إلى استخدام OOM-Killer لإنهاء PostgreSQL، اضبط على vm.overcommit_memory القيمة 2. هذا لا يضمن عدم اضطرار OOM-Killer إلى التدخل، ولكنه سيقلل من احتمالية إجبار عملية PostgreSQL على الإنهاء.

المصدر: www.habr.com

إضافة تعليق