Данные теряются при перезапуске службы
Если при перезапуске теряются данные, дело в остановке, а не в запуске. systemd посылает сигнал и ждёт ограниченное время; программа, которая не успевает сохраниться или не понимает сигнал, будет добита.
Вероятные причины
По порядку: сверху то, что встречается чаще.
-
Таймаут остановки меньше времени сохранения
Служба с большим объёмом состояния не успевает записать его за отведённое время и добивается сигналом.
-
Программа ждёт другой сигнал
Часть программ считает корректным завершением не TERM, а INT или QUIT. На TERM они завершаются мгновенно, без сохранения.
-
Завершаются все процессы группы сразу
При
KillMode=control-groupсигнал получают все процессы. Если сохранением занимается дочерний процесс, он может быть убит раньше, чем закончит.
Диагностика
Команды идут в том порядке, в котором их стоит выполнять: каждая следующая проверяет то, что осталось после предыдущей.
Как проходила последняя остановка.
journalctl -u myapp.service --no-pager | grep -iE "stopping|stopped|SIGKILL" | tail -20Три параметра, определяющие поведение при остановке.
systemctl show myapp.service -p TimeoutStopSec -p KillSignal -p KillModeРешение
Решение своё для каждой причины. Сначала определите, какая из них ваша, — иначе правки наложатся друг на друга.
- Почему происходит
- Служба с большим объёмом состояния не успевает записать его за отведённое время и добивается сигналом.
- Как проверить
-
Посмотрите таймаут и сообщения об остановке.
systemctl show myapp.service -p TimeoutStopSec journalctl -u myapp.service --no-pager | grep -iE "SIGKILL|timed out" | tail
- Как исправить
-
Увеличьте
TimeoutStopSec=до времени, которое нужно на сохранение, с запасом.
- Почему происходит
- Часть программ считает корректным завершением не TERM, а INT или QUIT. На TERM они завершаются мгновенно, без сохранения.
- Как проверить
-
Посмотрите документацию программы и заданный сигнал.
systemctl show myapp.service -p KillSignal
- Как исправить
-
Задайте нужный сигнал через
KillSignal=.
- Почему происходит
- При
KillMode=control-groupсигнал получают все процессы. Если сохранением занимается дочерний процесс, он может быть убит раньше, чем закончит.
- Как проверить
-
Посмотрите режим завершения и дерево процессов службы.
systemctl show myapp.service -p KillMode systemctl status myapp.service --no-pager | tail -8
- Как исправить
-
Используйте
KillMode=mixed: сигнал завершения получит только главный процесс, и он сам решит, когда остановить остальные.
Пример вывода
Служба добита, не успев сохранить состояние. Пример показательный: он собран на тестовой машине специально для этой страницы, а не взят из чужого журнала.
systemd[1]: Stopping myapp.service - My application...
myapp[1200]: saving state (0/24000 records)
systemd[1]: myapp.service: State 'stop-sigterm' timed out. Killing.
systemd[1]: myapp.service: Killing process 1200 (myapp) with signal SIGKILL.
Связанные ошибки
- signal=KILL (status=9/KILL) в systemd Процесс службы убит сигналом KILL. Кто мог его послать: OOM-killer, таймаут остановки systemd, администратор.
- Failed with result 'timeout' Состояние timeout: служба не уложилась в отведённое время при запуске, остановке или перезагрузке настроек.
- A stop job is running: выключение висит Перезагрузка останавливается с обратным отсчётом: служба не завершается. Как найти и сократить ожидание.
- signal=TERM (status=15/TERM) в systemd Процесс службы завершён сигналом TERM. Когда это нормальная остановка, а когда признак проблемы.
- A start job is running: загрузка висит на одной службе Загрузка останавливается с обратным отсчётом: служба не укладывается в таймаут. Как найти виновника и не ждать.
- Address already in use при запуске службы Порт или адрес уже занят: bind() failed (98: Address already in use). Как найти владельца порта и что делать с остатками прежнего процесса.
- Apache: Invalid command — не включён модуль Apache не запускается: директива требует модуль, который не подключён. Как найти нужный модуль и включить.
- Cannot assign requested address при привязке Ошибка 99 при привязке: адрес не принадлежит машине или ещё не поднят. Разбор с network-online.target и ip_nonlocal_bind.
Где встречается чаще всего
Источники
-
systemd.kill(5)
KillMode=, KillSignal= и порядок завершения. -
Воспроизведено на тестовой машине, systemd 255 (Ubuntu 24.04)
Воспроизведено службой с длительным сохранением при TimeoutStopSec=5s.