تكوين خارج الذاكرة القاتل على لينكس ل PostgreSQL


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


قاتل خارج الذاكرة


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


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


Out of Memory: Killed process 12345 (postgres). 

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


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


عند نفاد الذاكرة ، يتم out_of_memory() الدالة 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 ، لذلك في غلاف آخر ، يمكنك الحصول على تقدير باستخدام هذه oom_score kernel:


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

إذا كنت لا ترغب في إكمال OOM-Killer العملية على الإطلاق ، فهناك معلمة kernel أخرى: 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- القاتل


على نظام 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 يمكنه حجز ذاكرة أكبر للعمليات أكثر من ذلك ، لكن ليس تخصيصها في الواقع ، ويتم التحكم في هذا السلوك بواسطة معلمة kernel Linux. المتغير vm.overcommit_memory مسؤول عن هذا.


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


0: النواة نفسها تقرر ما إذا كنت تريد حجز الكثير من الذاكرة. هذه هي القيمة الافتراضية في معظم إصدارات Linux.
1: ستحتفظ النواة دائمًا بذاكرة إضافية. هذا أمر محفوف بالمخاطر ، لأن الذاكرة يمكن أن تنتهي ، لأنه على الأرجح ، ستحتاج العمليات في يوم ما إلى ما يفترض أن تكون.
2: لن يحجز kernel ذاكرة أكثر من المحدد في المعلمة 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 القسرية.

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


All Articles