إعداد برنامج قتل نفاد الذاكرة في Linux لـ PostgreSQL

إعداد برنامج قتل نفاد الذاكرة في Linux لـ PostgreSQL

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

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

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

إحدى المهام الرئيسية 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 يمكنك تفعيل أو تعطيل قاتل العمليات خارج الذاكرة (مع أن الخيار الأخير غير مستحسن). لتفعيله أو تعطيله، استخدم المعامل 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المتغير هو المسؤول عن ذلك. 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

شراء استضافة موثوقة للمواقع مع حماية DDoS وخوادم VPS VDS 🔥 اشترِ استضافة مواقع ويب موثوقة مع حماية من هجمات DDoS، وخوادم VPS وVDS | ProHoster