Результат oom-kill в systemd отражает «грязный сигнал» или «грязный код выхода»?

Вопрос или проблема

Недавно у меня отключился сервис из-за oom-kill.

$ systemctl status my-server.service
● my-server.service - "General purposes load-independent HTTP server"
     Loaded: loaded (/lib/systemd/system/my-server.service; enabled; vendor preset: enabled)
     Active: failed (Result: oom-kill) since Thu 2025-02-27 12:47:44 CST; 17h ago
    Process: 636 ExecStart=/usr/bin/my-server --listen-http :13668 --threads 10 (code=exited, status=0/SUCCESS)
   Main PID: 636 (code=exited, status=0/SUCCESS)
        CPU: 52min 57.893s

Feb 27 12:47:44 ios systemd[1]: my-server.service: A process of this unit has been killed by the OOM killer.
Feb 27 12:47:44 ios my-server[636]: Received signal to stop (15). Stopping...
Feb 27 12:47:44 ios systemd[1]: my-server.service: Failed with result 'oom-kill'.
Feb 27 12:47:44 ios systemd[1]: my-server.service: Consumed 52min 57.893s CPU time.

man systemd.exec говорит, что $SERVICE_RESULT устанавливается в oom-kill, когда “Процесс службы был завершен из-за недостатка памяти (OOM killer).”

Это была утечка памяти в длительно работающем дочернем процессе /usr/bin/my-server. Когда это происходит, я бы хотел использовать Restart= для перезапуска сервиса.

Вопрос:

Вызывает ли $SERVICE_RESULT=oom-kill неочищенный код завершения или неочищенный сигнал?

Я бы хотел как можно больше ограничить свой Restart=. Поэтому я хочу выбрать первое условие, которое соответствует критериям oom-kill из списка ниже:

  • Restart=on-abort можно использовать, если это был неочищенный сигнал.
  • Restart=on-abnormal может быть использован для вышеуказанного случая, или если это вызывает тайм-аут или причину срабатывания watchdog (вероятно, неприменимо).
  • Restart=on-failure работает для всех вышеперечисленных случаев, плюс неочищенный код завершения.
  • Restart=always теоретически покрывает все случаи

Из man systemd.service:

Table 2. Exit causes and the effect of the Restart= settings
┌──────────────────────┬────┬────────┬────────────┬────────────┬─────────────┬──────────┬─────────────┐
│Restart settings/Exit │ no │ always │ on-success │ on-failure │ on-abnormal │ on-abort │ on-watchdog │
│causes                │    │        │            │            │             │          │             │
├──────────────────────┼────┼────────┼────────────┼────────────┼─────────────┼──────────┼─────────────┤
│Clean exit code or    │    │ X      │ X          │            │             │          │             │
│signal                │    │        │            │            │             │          │             │
├──────────────────────┼────┼────────┼────────────┼────────────┼─────────────┼──────────┼─────────────┤
│Unclean exit code     │    │ X      │            │ X          │             │          │             │
├──────────────────────┼────┼────────┼────────────┼────────────┼─────────────┼──────────┼─────────────┤
│Unclean signal        │    │ X      │            │ X          │ X           │ X        │             │
├──────────────────────┼────┼────────┼────────────┼────────────┼─────────────┼──────────┼─────────────┤
│Timeout               │    │ X      │            │ X          │ X           │          │             │
├──────────────────────┼────┼────────┼────────────┼────────────┼─────────────┼──────────┼─────────────┤
│Watchdog              │    │ X      │            │ X          │ X           │          │ X           │
└──────────────────────┴────┴────────┴────────────┴────────────┴─────────────┴──────────┴─────────────┘

Ответ или решение

Вопрос о том, является ли результат вызова Out-Of-Memory (OOM) Killer в systemd "нечистым сигналом" или "нечистым кодом завершения", требует рассмотрения некоторых технических подробностей, связанных с работой systemd и поведения процессов в операционной системе Linux.

Теория

Systemd выполняет роль системы инициализации в большинстве дистрибутивов Linux, управляя сервисами и сопутствующими процессами. Когда какая-либо программа потребляет слишком много памяти, Linux может активировать OOM Killer, чтобы освободить ресурсы убив проблемный процесс. В контексте systemd, если OOM Killer прекращает выполнение одного из процессов службы, соответствующий $SERVICE_RESULT будет равен "oom-kill".

Когда процесс погибает от OOM Killer, он получает сигнал SIGKILL (сигнал 9), который считается "нечистым" (или "unclean"), так как этот сигнал не может быть обработан самим процессом с целью корректного завершения текущих операций. Следовательно, убитый процесс не имеет возможности возвратить код завершения. Это подводит к выводу, что результат "oom-kill" отображает сценарий "нечистого сигнала", а не "нечистого кода завершения".

Пример

Рассматривая предоставленный сценарий, ваш сервис "my-server" был убит OOM Killer из-за утечки памяти в дочернем процессе. В результате команды systemctl status показано:

my-server.service: A process of this unit has been killed by the OOM killer.

Здесь видно, что systemd однозначно идентифицировал причину остановки — процесс был убит OOM Killer. Это именно то, что понимается под "нечистым сигналом", поскольку был получен сигнал SIGKILL.

Применение

Теперь, если вы хотите правильно настроить поведение вашего сервиса в случае таких ситуаций, следует выбрать наиболее подходящее значение для параметра Restart= в вашем unit-файле systemd.

  1. Restart=on-abort: Это значение перезапустит сервис только если он завершился от "нечистого сигнала", что идеально подходит в случае использования OOM Killer.

  2. Restart=on-abnormal: Это более широкая категория, включающая также сценарии тайм-аута и проблемы с watchdog. Хотя это значение перезагружается при нечистом завершении, оно добавляет возможности, которые вам могут быть не нужны.

  3. Restart=on-failure: Это значение запускается при всех сценариях, когда служба аварийно завершилась, в том числе и по причинам "нечистого кода завершения". Будет избыточным, если ваш текущий запрос направлен только на обработку OOM Killer.

  4. Restart=always: Самое широкое значение, которое перезапустит сервис в любых случаях. Оно может быть слишком большим охватом для вашего конкретного сценария.

На основании вышеизложенного, для вашей конкретной задачи "Restart=on-abort" кажется наиболее подходящим, чтобы минимизировать количество ненужных перезапусков и четко зарегистрировать и использовать именно тот сценарий, с которым вы столкнулись.

В дополнение к исправлению текущих настроек, рекомендуется также исследовать и устранить первичную причину проблем с памятью, чтобы снизить вероятность повторения проблем и зависимости исключительно от перезагрузок для поддержания доступности сервиса. Оптимизация потребления памяти приложением или установка предельных значений через cgroups может быть полезным в этой ситуации.

Оцените материал
Добавить комментарий

Капча загружается...