Если monitoring-snmp-sync.service застрял в activating, не перезапускайте его по кругу. Сначала проверьте, не ждут ли друг друга скрипт синхронизации и экспортёр.
В опубликованном на Хабре разборе «Как systemd превратил обычный скрипт перезапуска в бесконечный дедлок» цепочка выглядела так:
таймер
→ monitoring-snmp-sync.service
→ snmp-sync.sh
→ systemctl try-restart monitoring-snmp-exporter
→ monitoring-snmp-exporter.service
→ After=monitoring-snmp-sync.service
Скрипт ждал перезапуска экспортёра. Экспортёр ждал завершения скрипта. Таймаут не прерывал ожидание, поэтому мониторинг мог молчать неделями.
Задача администратора — проверить не отдельную службу, а всю цепочку. После исправления нужно доказать, что список целей снова обновляется и конечная метрика относится к существующему устройству.
Сначала найдите, на каком звене остановилась цепочка
Начните с двух юнитов:
systemctl status monitoring-snmp-sync.service
systemctl status monitoring-snmp-exporter.service
Затем откройте их журналы:
journalctl -u monitoring-snmp-sync.service
journalctl -u monitoring-snmp-exporter.service
systemctl status показывает состояние юнита и результат последней попытки запуска. journalctl -u выводит сообщения выбранной службы. Такой порядок диагностики описан в руководстве Fastfox по циклам перезапуска systemd.
| Наблюдаемый признак | Что происходит в systemd | Команда проверки | Что искать |
|---|---|---|---|
sync.service долго остаётся в activating | oneshot-скрипт не завершился | systemctl status monitoring-snmp-sync.service | активный процесс systemctl, который ждёт другую службу |
Экспортёр не переходит в active | запуск поставлен после незавершённого sync-юнита | systemctl status monitoring-snmp-exporter.service | ожидание задания либо зависимость от monitoring-snmp-sync.service |
| Экспортёр несколько раз запускается и падает | сработала политика Restart=on-failure | journalctl -u monitoring-snmp-exporter.service | первая ошибка приложения перед повторными запусками |
Экспортёр остаётся в failed | systemd остановил новые попытки запуска | systemctl show monitoring-snmp-exporter.service -p StartLimitIntervalUSec -p StartLimitBurst | эффективный интервал и число разрешённых запусков |
Состояние activating без конечного таймаута требует проверки зависимостей. Ещё один перезапуск лишь запускает ту же цепочку заново.
Если службы активны, но пользователи или внешняя система не получают ожидаемый результат, пройдите проверку сервиса за зелёными серверными метриками. Состояние active подтверждает работу процесса, но не всей операции.
Как четыре обычные настройки образовали дедлок
Таймер раз в минуту запускал monitoring-snmp-sync.service. Это был юнит Type=oneshot: он выполнял snmp-sync.sh, обновлял /etc/snmp/snmp.yml, а при изменении файла вызывал:
systemctl try-restart monitoring-snmp-exporter.service
Вызов работал синхронно. Скрипт не мог завершиться, пока systemd не закончит перезапуск экспортёра.
У экспортёра при этом стояла зависимость:
After=monitoring-snmp-sync.service
По systemd.unit(5), на который ссылается автор разбора на Хабре, After= задаёт порядок запуска, когда оба юнита запускаются одновременно. В этой схеме экспортёр получил задание на запуск до завершения sync-юнита и встал в очередь за ним.
Получился замкнутый граф:
monitoring-snmp-sync.service
ждёт завершения systemctl try-restart
↓
monitoring-snmp-exporter.service
ждёт завершения monitoring-snmp-sync.service
↓
monitoring-snmp-sync.service
Каждая настройка по отдельности выглядит разумно. Таймер обновляет конфигурацию, скрипт перезапускает процесс, а After= удерживает порядок старта. Ошибка появляется только в полном графе.
Поэтому unit-файлы нельзя проверять изолированно. Выпишите последовательность от таймера до конечной службы и отметьте каждый синхронный переход.
Почему systemd не остановил операцию через 90 секунд
Общий DefaultTimeoutStartSec= в systemd равен 90 секундам. Но у Type=oneshot значение TimeoutStartSec= по умолчанию отключено: systemd использует infinity.
Оба параметра приведены в разборе инцидента на Хабре со ссылкой на документацию systemd. Из-за исключения для oneshot ожидание могло продолжаться неограниченно.
Проверьте эффективное значение, а не только текст unit-файла:
systemctl show monitoring-snmp-sync.service -p Type -p TimeoutStartUSec
Если команда показывает TimeoutStartUSec=infinity, systemd не завершит зависший запуск по стандартному 90-секундному пределу.
Явный таймаут ограничит последствия, но не исправит граф. После его срабатывания перезапуск экспортёра всё равно не выполнится. Основная правка должна разорвать синхронное ожидание.
try-restart создаёт другой сбой, когда экспортёр уже остановлен
systemctl try-restart перезапускает только работающий юнит. Если экспортёр остановлен, команда ничего не запускает. Такое поведение описано в том же разборе инцидента на Хабре.
На одном из четырёх хостов именно это и произошло. Скрипт обновил конфигурацию, вызвал try-restart, но экспортёр уже не работал. Команда не вернула ошибку запуска, потому что запуска не было.
Здесь нужен выбор по требуемому результату:
- Если экспортёр должен работать после каждого обновления, вызывайте
restart. - Если остановленное состояние нужно сохранить, оставляйте
try-restart. - Если вызов идёт из юнита, завершения которого ждёт экспортёр, добавляйте
--no-block.
Для обязательного запуска команда будет выглядеть так:
systemctl --no-block restart monitoring-snmp-exporter.service
Флаг --no-block ставит задание в очередь и сразу возвращает управление скрипту. Этот механизм описан в разборе на Хабре. Sync-юнит завершится, после чего systemd сможет выполнить отложенный запуск экспортёра.
Команду без блокировки нельзя считать подтверждением успешного запуска. Она подтверждает только приём задания. Результат проверяют отдельным шагом — так же, как при контроле результата автоматического перезапуска 1С.
Цикл перезапуска — не дедлок
Дедлок и цикл перезапусков выглядят похоже только снаружи: служба не работает, а systemd занят. Механика у них разная.
При дедлоке два задания ждут друг друга. Процесс может долго оставаться в activating, не переходя к новой попытке.
При цикле экспортёр запускается, завершается с ошибкой, а Restart=on-failure просит systemd повторить запуск. Руководство Fastfox описывает этот маршрут как старт → ошибка → рестарт.
В исследованном случае один экспортёр завершался из-за ошибки YAML:
line 12: mapping values are not allowed in this context
После нескольких быстрых попыток systemd прекратил запускать службу. В разборе на Хабре приведены стандартные значения: StartLimitBurst=5 попыток за StartLimitIntervalSec=10s.
| Сценарий | Что видно в status или журнале | Чего не делать | Исправление |
|---|---|---|---|
| Дедлок sync-юнита и экспортёра | sync.service остаётся в activating, экспортёр ждёт запуска | перезапускать оба юнита по кругу | разорвать зависимость либо вызвать systemctl --no-block restart |
try-restart встретил остановленный экспортёр | команда завершилась, но экспортёр остался inactive | считать нулевой код подтверждением работающей службы | заменить try-restart на restart, если служба обязана работать |
| Экспортёр падает сразу после запуска | в журнале повторяется ошибка приложения | увеличивать число попыток до проверки первой ошибки | исправить конфигурацию, права или окружение |
| Сработал предел запусков | failed, start-limit-hit, Start request repeated too quickly | выполнять только reset-failed | устранить причину падения, затем сбросить состояние |
reset-failed снова разрешает запуск. Конфигурацию, права и ошибку приложения команда не исправляет.
Как восстановить экспортёр после start-limit-hit
Сначала найдите первую содержательную ошибку. Последние сообщения о лимите показывают следствие, а не причину:
journalctl -u monitoring-snmp-exporter.service
Для ошибки YAML исправьте сам файл /etc/snmp/snmp.yml. Затем запустите экспортёр вручную через systemd и снова проверьте журнал.
После устранения причины сбросьте состояние:
systemctl reset-failed monitoring-snmp-exporter.service
systemctl restart monitoring-snmp-exporter.service
systemctl status monitoring-snmp-exporter.service
По руководству Fastfox, systemctl reset-failed очищает состояние failed и счётчик лимита запусков. Та же последовательность нужна при сообщении Start request repeated too quickly: сначала причина, затем сброс.
Если меняли unit-файл, перечитайте конфигурацию systemd:
systemctl daemon-reload
daemon-reload нужен после изменения unit-файлов, что также указано в руководстве Fastfox. Изменение только /etc/snmp/snmp.yml такой команды не требует: этот файл читает экспортёр, а не менеджер systemd.
После исправления проверьте данные, а не зелёный статус
Работающий процесс ещё не доказывает, что мониторинг видит актуальные цели. В разобранном инциденте метрика
up{snmp_device="..."} = 0
оставалась для устройства, удалённого неделей ранее. Скрипт синхронизации завис, список целей замёрз, а старая временная серия продолжала попадать в мониторинг.
Проверка должна пройти по тому же маршруту, что и данные:
- Таймер запускает
monitoring-snmp-sync.service. - Скрипт завершает работу.
- Файл целей получает ожидаемое содержимое.
- systemd принимает и выполняет перезапуск экспортёра.
- Экспортёр отвечает на запрос.
- Мониторинг получает метрики по текущему списку устройств.
Последний пункт отделяет восстановленную службу от восстановленного наблюдения. Если график продолжает показывать удалённую цель, цепочка ещё сломана.
В инфраструктуре 1С применяйте тот же принцип: связывайте пользовательскую операцию с журналами приложения и показателями сервера. Отдельный маршрут описан в материале о поиске задержки по APDEX, техжурналу и метрикам.
Мониторинг должен следить за возрастом собственных данных
Сбой оставался незамеченным две–три недели. Мониторинг проверял удалённые устройства, но не контролировал работу механизма, который обновлял их список.
Добавьте отдельный признак свежести. Это может быть время последнего успешного выполнения sync-юнита либо метка времени последнего принятого файла целей. Порог выберите из расписания: если таймер работает раз в минуту, несколько пропущенных запусков уже требуют проверки.
Такое оповещение не должно зависеть от экспортёра, который оно контролирует. Иначе при общем отказе исчезнут одновременно данные и сигнал об их отсутствии.
Правило для скриптов перезапуска под systemd
Юнит не должен синхронно перезапускать службу, которая через After= ждёт завершения этого же юнита. Разорвите зависимость либо поставьте перезапуск в очередь через --no-block.
Перед возвратом мониторинга в работу проверьте пять пунктов:
- Выпишите цепочку
таймер → скрипт → systemctl → служба. - Проверьте
Type,After,Restart,TimeoutStartSecи лимиты запусков. - Устраните первую ошибку приложения до
reset-failed. - Подтвердите обновление целей и конечной метрики.
- Настройте оповещение о возрасте последнего успешного обновления.