Skip to main content
تُعدّ OOM canary ميزة تجريبية وهي معطّلة افتراضيًا. وقد يتغيّر سلوكها بين إصدارات ClickHouse إلى أن يكتمل التحقق منها في بيئات الإنتاج.

نظرة عامة

عندما تنفد الذاكرة لدى مضيف أو لدى cgroup للذاكرة، يُنهي قاتل نفاد الذاكرة (OOM) في Linux عملية باستخدام SIGKILL — وغالبًا ما تكون أكبر مستهلك للذاكرة، والتي تكون في المضيف المخصص هي clickhouse-server نفسه. وبذلك يُفقد الخادوم بالكامل بدلًا من منحه فرصة للتعافي. يغيّر كاناري OOM الجهة التي تموت أولًا. فهو يشغّل عملية فرعية صغيرة تضحية تجعل نفسها الهدف الأكثر ترجيحًا لـ OOM، بحيث تقتلها النواة بدلًا من الخادوم. ثم يكتشف الخادوم هذا التوقف، ويتأكد من أنه كان حدث OOM، ويخفف ضغط الذاكرة لكي يتمكن من الاستمرار. لا يرفع الكناري أي memory limit، وليس بديلًا عن الحدود الصحيحة (انظر memory overcommit و max_server_memory_usage). بل هو خط الدفاع الأخير الذي يبادل مقدارًا صغيرًا وثابتًا من الذاكرة بفرصة النجاة من ارتفاع مفاجئ في استهلاك الذاكرة.

كيف يعمل

الكناري هو عملية clickhouse oom-canary منفصلة. يضبط قيمة oom_score_adj الخاصة به على الحد الأقصى (1000) لكي تستهدفه النواة أولًا، ثم يخصّص oom_canary_size بايت (100 ميغابايت افتراضيًا)، ويلمسها، ويُجري عليها mlock لكي تكون مجموعة الصفحات المقيمة الخاصة به فعلية. ويُنهي تلقائيًا إذا توقّف الخادم. في الخادم، يراقب خيط مراقبة الكناري (عبر pidfd) ويتفاعل عند موته:
  • إذا قُتل بواسطة SIGKILL مع وجود مؤشر OOM من cgroup → تُشغَّل استجابة OOM، ثم يُعاد تشغيل كناري جديد.
  • إذا قُتل من دون وجود مؤشر OOM (على سبيل المثال، kill -9 يدوي)، أو خرج بسبب فشل عابر → تُعاد عملية التشغيل فقط، من دون استجابة.
  • عند فشل دائم في الإعداد، أو عند إيقاف الخادم → يعطّل الكناري نفسه.
لا يأتي مؤشر OOM إلا من العداد oom_kill في memory.events.local ضمن cgroup v2. وقد صُمِّم عمدًا ليكون محليًا على مستوى cgroup: إذ يمكن للعدادات الهرمية أو على مستوى المضيف أن تزداد بسبب عمليات غير ذات صلة، ما قد يؤدي إلى إطلاق استجابات خاطئة. عند تأكيد حدوث OOM، تُنفَّذ هذه الخطوات المستقلة ضمن الاستجابة: تسجيل رسالة FATAL، وتنقية ساحات المُخصِّص (jemalloc)، ومحاولة إلغاء جميع الاستعلامات الجارية بأفضل جهد ممكن، وإلغاء جميع عمليات الدمج وعمليات mutation، ووضع حدث في system.crash_log. لا تُفرَّغ سجلات النظام تفريغًا متزامنًا، لأن فرض عمليات I/O تحت ضغط الذاكرة قد يزيد الأمور سوءًا.

المتطلبات

  • Linux ≥ 5.3. تمتلك أداة المراقبة العملية الكناري عبر pidfd_open؛ وفي الإصدارات الأقدم من النواة تُعطِّل العملية الكناري نفسها عند بدء التشغيل. ويكون ذلك بلا تأثير على المنصات غير Linux.
  • cgroup v2 مع memory.events.local من أجل استجابة OOM. وبدونه تظل العملية الكناري تُعاد تشغيلها بعد SIGKILL، لكنها لا تستطيع تأكيد وقوع OOM، لذلك لا تُنفَّذ الاستجابة مطلقًا (ويُسجَّل تحذير عند بدء التشغيل).
  • صلاحية mlock (اختيارية). يتطلّب قفل ذاكرة العملية الكناري CAP_IPC_LOCK أو قيمة RLIMIT_MEMLOCK كافية؛ وإذا فشل ذلك، تسجّل العملية الكناري تحذيرًا، وقد تُرحَّل ذاكرتها إلى swap، مما يضعفها كهدف لـ OOM.
memory.oom.groupإذا كان memory.oom.group في cgroup v2 مفعّلًا لـ cgroup الخاص بالخادم، فإن النواة تقتل cgroup بالكامل كوحدة واحدة عند حدوث OOM — فيتوقف الخادم مع العملية الكناري معًا، ولا تُنفَّذ الاستجابة مطلقًا. ولا تستطيع العملية الكناري حماية الخادم في هذا الوضع؛ ويُسجَّل تحذير عند بدء التشغيل.

التهيئة

تخضع عملية الكناري للتحكم عبر إعدادات الخادم، وتُحدَّد كعناصر من المستوى الأعلى في تهيئة الخادم وتُطبَّق عند إعادة التشغيل.

الرصد

تؤدي حالة OOM مؤكدة إلى إنشاء صف في system.crash_log حيث تكون قيمة signal = 9 ويتضمن signal_description إشارة إلى OOM Canary:
كما تُسجَّل دورة حياة الكاناري وكل خطوة من خطوات الاستجابة لحالة نفاد الذاكرة في سجل الخادم.
آخر تعديل في ٢٤ يوليو ٢٠٢٦