
عند إيقاف تشغيل خادم قاعدة البيانات بشكل غير متوقع على نظام 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()
عملية وفقًا لقواعد معينة.
- يحتاج النواة إلى الحد الأدنى من الذاكرة لنفسه.
- تحتاج إلى تحرير الكثير من الذاكرة.
- لا حاجة لإنهاء العمليات التي تستخدم القليل من الذاكرة.
- تحتاج إلى إكمال الحد الأدنى من العمليات.
- خوارزميات معقدة تزيد من فرص الإكمال لتلك العمليات التي يريد المستخدم نفسه إكمالها.
بعد إكمال كل هذه الفحوصات ، تفحص 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 القسرية.