Центр Диагностики & База Системных Ошибок

Решения для Windows Server, Active Directory, 1С, СУБД, Linux, Cisco, MikroTik и IP-телефонии.

⚠️ Важная информация Все материалы, инструкции, команды и скрипты предоставлены исключительно в ознакомительных целях. Их применение может повлиять на работу операционной системы, баз данных и сетевого оборудования. Перед выполнением действий обязательно создайте резервную копию. При отсутствии необходимой квалификации обратитесь к ИТ-специалистам.
LINUX-SYSTEMD-ORDERING-CYCLES Linux / DevOps

Гайд: Траблшутинг циклов зависимостей (Ordering Cycles) в unit-файлах systemd

Обновлено: 21.08.2026  ·  Официальная база знаний

Природа циклических зависимостей (Deadlock Ordering Cycles) в systemd

При построении дерева запуска системный менеджер systemd создает ориентированный ациклический граф (Directed Acyclic Graph, DAG), узлами которого являются юниты (.service, .mount, .socket, .target), а ребрами — директивы порядка исполнения (After=, Before=) и требования зависимостей (Requires=, Wants=, BindsTo=). Если в конфигурациях пользовательских или системных юнитов возникает взаимно противоположный порядок ожидания (например, Сервис A должен стартовать После Сервиса B, а Сервис B настроен стартовать После Сервиса A), образуется неразрешимый замкнутый цикл:

«systemd[1]: Found ordering cycle on custom-app.service/start
systemd[1]: Found dependency on network-online.target/start
systemd[1]: Found dependency on custom-app.service/start
systemd[1]: Breaking ordering cycle by deleting job network-online.target/start»

Бизнес-риски

Непредсказуемое поведение сервера при загрузке: systemd принудительно удаляет случайную задачу из графа («Breaking ordering cycle»), что приводит к внезапному незапуску критических сервисов (баз данных, сети или стораджа).

Сравнение директив зависимостей и очередности в systemd

ДирективаКатегорияНазначение
Wants= / Requires=Зависимость требованияОпределяет, ЧТО должно быть запущено (Wants — мягкая связь, Requires — жесткая). НЕ ЗАДАЕТ ПОРЯДОК!
After= / Before=Очередность исполненияОпределяет строго КОГДА юнит должен запуститься относительно другого (After — после, Before — до).
DefaultDependencies=yesНеявные зависимостиПо умолчанию автоматически добавляет Requires=basic.target и After=basic.target.

Регламент локализации и исправления циклов зависимостей

Сценарий 1: Локализация цикла в системном журнале journalctl

Найдите точный список юнитов, вовлеченных в замкнутое кольцо:

# 1. Поиск сообщений об обнаружении циклов в журнале загрузки:
journalctl -b -u init.scope | grep -i "ordering cycle"

# 2. Просмотр полной трассировки разорванного цикла:
journalctl -b | grep -B 2 -A 8 "Found ordering cycle"

Сценарий 2: Построение и валидация графа зависимостей через systemd-analyze

# 1. Синтаксическая валидация всех unit-файлов на сервере:
sudo systemd-analyze verify /etc/systemd/system/*.service

# 2. Построение графа зависимостей конкретного проблемного сервиса в формате DOT:
systemd-analyze dot custom-app.service | dot -Tsvg -o /tmp/dependencies_graph.svg

Сценарий 3: Разрешение конфликта между early-boot и late-boot юнитами

Самая распространенная причина цикла: сервис должен стартовать на раннем этапе (например, до монтирования локальных дисков или инициализации сокетов), но имеет включенный флаг DefaultDependencies=yes:

# Пример ошибочного unit-файла (/etc/systemd/system/early-logger.service):
[Unit]
Description=Early Boot Logger
Before=sysinit.target   # Хотим запуститься до инициализации системы
# ОШИБКА: По умолчанию включен DefaultDependencies=yes, который неявно добавляет After=sysinit.target!
# Возникает моментальный цикл: Before=sysinit.target + After=sysinit.target

# ПРАВИЛЬНОЕ ИСПРАВЛЕНИЕ:
[Unit]
Description=Early Boot Logger
DefaultDependencies=no   # Явно отключаем стандартные скрытые зависимости
After=local-fs.target
Before=sysinit.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/early-logger.sh

[Install]
WantedBy=sysinit.target

Сценарий 4: Применение изменений в systemd

# 1. Перезагрузка конфигурации systemd менеджера:
sudo systemctl daemon-reload

# 2. Проверка статуса сервиса:
sudo systemctl restart custom-app.service
sudo systemctl status custom-app.service

Типовые ошибки администраторов

  • Путаница между Requires= и After=: Объявление Requires=service-b.service без указания After=service-b.service приведет к одновременному параллельному старту обоих сервисов без гарантии очередности.
  • Использование циклических After= в связках сокетов: Добавление After=app.service внутри app.socket, когда app.service уже зависит от app.socket.
Службы запускаются через раз после перезагрузки сервера?
Специалисты ITSTM проведут аудит системных юнитов, развяжут скрытые циклы зависимостей и обеспечат детерминированный порядок старта сервисов.
Практический опыт инженера: При написании кастомных unit-файлов всегда четко разделяйте жесткие зависимости (BindsTo/Requires) и логические зависимости (Wants). Использование Wants= в паре с After= обеспечивает максимальную отказоустойчивость: если вспомогательный сервис упадет, основное приложение все равно успешно запустится.

Частые вопросы (FAQ)

Почему systemd удаляет именно нужный мне сервис при разрыве цикла?

Алгоритм эвристики systemd выбирает для удаления задание с наименьшим системным приоритетом или то, которое проще всего исключить из транзакции запуска, не зная о бизнес-важности вашего приложения.

Что входит в DefaultDependencies=yes для сервисов?

Неявно добавляются зависимости: Requires=sysinit.target, After=sysinit.target, After=basic.target, Before=shutdown.target, Conflicts=shutdown.target.

Как сделать, чтобы сервис запускался строго после полной инициализации сети и базы данных?

Укажите в секции [Unit]: After=network-online.target mysql.service и Wants=network-online.target.

Можно ли увидеть граф зависимостей в текстовом виде в консоли?

Да, выполните: systemctl list-dependencies my-service.service --all.