Linux DEPCYCLКритическая

Разрешение циклической зависимости systemd: причины и решения

Статья объясняет, что такое циклическая зависимость в systemd, почему она возникает и как её исправить. Вы узнаете, как анализировать зависимости юнитов и вносить правки для восстановления работы системы.

Обновлено 16 февраля 2026 г.
15-30 мин
Средняя
FixPedia Team
Применимо к:systemd v239+Ubuntu 18.04+Debian 10+Fedora 30+

Что означает ошибка циклической зависимости systemd

При загрузке systemd строит граф зависимостей между юнитами (службами, таргетами, сокетами и т.д.). Циклическая зависимость возникает, когда два или более юнита указывают друг на друга как на требуемые (через Requires, Wants, PartOf или After в сочетании с другими директивами), образуя замкнутый цикл. Systemd не может определить порядок запуска таких юнитов и прерывает процесс, выводя ошибку.

Типичные симптомы:

  • В логах (journalctl -xe или systemctl status <юнит>) появляется сообщение: Dependency cycle detected: foo.service → bar.service → foo.service.
  • Службы, вовлечённые в цикл, переходят в состояние failed или dead.
  • Система может зависнуть на этапе загрузки (например, на Starting...).
  • Команда systemctl list-dependencies для проблемного юнита завершается с ошибкой или покажет зацикленную цепочку.

Эта ошибка критична: она предотвращает запуск как минимум одной службы, а в худшем случае — всю загрузку системы.

Причины возникновения

  1. Неправильно настроенные директивы зависимостей в юнит-файлах. Например, serviceA.service имеет Requires=serviceB.service, а serviceB.serviceRequires=serviceA.service.
  2. Цепочка зависимостей через целевые юниты (targets). Например, multi-user.target зависит от network.target, который зависит от службы, требующей multi-user.target.
  3. Конфликтующие директивы. Сочетание Requires/Wants с Conflicts или Before/After может создать неявный цикл.
  4. Ошибки в пакетах. При установке стороннего ПО его юнит-файлы могут содержать циклы, особенно если пакет некорректно объявляет зависимости.
  5. Ручное редактирование без проверки. Администратор мог добавить зависимость, не учтя уже существующие связи.

Способы решения

Способ 1: Ручной анализ и исправление юнит-файлов

Этот метод подходит, когда вы знаете примерные имена проблемных юнитов.

  1. Определите юниты, участвующие в цикле. Используйте:
    systemd-analyze critical-chain
    

    Команда покажет цепочку загрузки и укажет, где возникает задержка или цикл. Ищите повторяющиеся имена.
    Или для конкретного юнита:
    systemctl list-dependencies <имя_юнита> --all
    

    Если есть цикл, вывод будет прерываться или содержать одни и те же юниты несколько раз.
  2. Визуализируйте граф зависимостей (опционально, но полезно). Установите graphviz:
    sudo apt install graphviz   # Debian/Ubuntu
    sudo yum install graphviz   # CentOS/RHEL
    

    Затем сгенерируйте SVG-файл:
    systemd-analyze plot > dependencies.svg
    

    Откройте dependencies.svg в браузере и найдите цикл (замкнутый контур стрелок).
  3. Найдите файлы юнитов. Для каждого юнита в цикле определите, откуда он загружен:
    systemctl status <имя_юнита> | grep Loaded
    

    Вывод покажет путь: /etc/systemd/system/ (пользовательские переопределения) или /lib/systemd/system/ (из пакета).
  4. Отредактируйте юнит-файлы. Откройте каждый файл в редакторе (например, sudo nano /path/to/unit.service). Найдите директивы Requires=, Wants=, After=, Before=. Уберите или измените ссылку, которая замыкает цикл. Например, если serviceA требует serviceB, а serviceB требует serviceA, удалите одну из этих зависимостей (часто можно оставить Wants= вместо Requires= или убрать After=).
  5. Перезагрузите конфигурацию systemd:
    sudo systemctl daemon-reload
    
  6. Проверьте результат:
    systemctl status <имя_юнита>
    systemd-analyze critical-chain
    

    Ошибка должна исчезнуть.

Способ 2: Использование systemd-analyze verify для автоматической проверки

systemd-analyze verify проверяет синтаксис и логику юнит-файлов, включая циклы.

  1. Запустите проверку для всех юнитов:
    sudo systemd-analyze verify --fail --no-pager
    

    Флаг --fail заставит команду выходить с ненулевым кодом при ошибках, а --no-pager отключит постраничный вывод. В выводе будут указаны файлы и строки с проблемами, включая циклические зависимости.
  2. Если вывод слишком длинный, проверяйте по одному юниту:
    sudo systemd-analyze verify /etc/systemd/system/foo.service
    
  3. Исправьте указанные файлы как в Способе 1.
  4. Перезагрузите демон и проверьте.

Способ 3: Временное отключение проблемных юнитов (mask)

Если цикл предотвращает загрузку системы (например, вы не можете получить доступ к shell), загрузитесь в recovery mode или используйте live-USB.

  1. Определите цикл через systemd-analyze из recovery-режима или, если система частично загружена, через journalctl -b -1 (логи предыдущей загрузки).
  2. Временно заблокируйте (mask) один из юнитов в цикле:
    sudo systemctl mask <имя_юнита>
    

    Это создаст символическую ссылку на /dev/null, предотвратив загрузку юнита.
  3. Перезагрузите систему. Она должна загрузиться без ошибки (хотя функциональность, связанная с заблокированным юнитом, будет недоступна).
  4. После загрузки исправьте юнит-файлы (Способ 1), затем разблокируйте:
    sudo systemctl unmask <имя_юнита>
    sudo systemctl daemon-reload
    sudo systemctl restart <имя_юнита>
    

Способ 4: Обновление или переустановка пакета

Если цикл вызван пакетом из репозитория (например, после обновления):

  1. Найдите пакет, которому принадлежит юнит:
    dpkg -S /lib/systemd/system/foo.service   # Debian/Ubuntu
    rpm -qf /usr/lib/systemd/system/foo.service   # CentOS/RHEL
    
  2. Обновите пакет до последней версии — ошибка могла быть исправлена в новом релизе:
    sudo apt update && sudo apt upgrade <имя_пакета>   # Debian/Ubuntu
    sudo yum update <имя_пакета>   # CentOS/RHEL
    
  3. Если обновление не помогло, переустановите пакет:
    sudo apt install --reinstall <имя_пакета>   # Debian/Ubuntu
    sudo yum reinstall <имя_пакета>   # CentOS/RHEL
    

    Переустановка заменит юнит-файлы на стандартные, возможно, без цикла.
  4. Перезагрузите systemd и проверьте.

Способ 5: Использование systemd-analyze dump для глубокого анализа

Если предыдущие методы не дали результата, получите полный дамп состояния systemd:

  1. Создайте дамп:
    sudo systemd-analyze dump > systemd-dump.txt
    
  2. Ищите циклы вручную. Откройте файл и найдите все вхождения Requires=, Wants=, After= для подозреваемых юнитов. Постройте цепочку на бумаге или в графическом редакторе.
  3. Особое внимание на "want" и "require" цепочки. Часто цикл образуется через WantedBy= в секциях [Install]. Например, serviceA имеет WantedBy=multi-user.target, а serviceB (который зависит от serviceA) также имеет WantedBy=multi-user.target и при этом Requires=serviceA. Это не всегда цикл, но если serviceA также требует serviceB — цикл возникнет.
  4. Исправьте файлы и перезагрузите демон.

Профилактика

  • Тестируйте юнит-файлы перед установкой. Используйте systemd-analyze verify <файл>.
  • Избегайте взаимных Requires=. Если службе A нужна служба B, достаточно Requires=B в A. Не добавляйте обратную зависимость в B, если это не абсолютно необходимо.
  • Используйте Wants= вместо Requires=, если зависимость не критична. Это снизит риск цикла.
  • Группируйте службы через таргеты. Создайте целевой юнит (например, myapp.target) и добавляйте в него службы через WantedBy=. Затем включайте только таргет.
  • Регулярно проверяйте зависимости после изменений: systemctl list-dependencies <ключевой_юнит>.
  • При обновлении пакетов внимательно читайте changelog — там могут быть изменения в зависимостях.
  • Держите systemd обновлённым. В новых версиях улучшена обработка зависимостей и добавлены предупреждения.

Эта статья должна помочь вам быстро диагностировать и устранить циклические зависимости в systemd, восстановив работу служб и системы.

Часто задаваемые вопросы

Что такое циклическая зависимость в systemd?
Как обнаружить циклическую зависимость?
Можно ли автоматически исправить циклическую зависимость?
Как предотвратить циклические зависимости при создании юнит-файлов?

Полезное

Анализ зависимостей
Визуализация графа
Поиск проблемных юнит-файлов
Редактирование юнит-файлов
Перезагрузка демона systemd
Проверка и запуск