Наши партнеры

UnixForum





Библиотека сайта rus-linux.net

systemd: зависимости и порядок запуска юнитов

Оригинал: systemd: Unit dependencies and order
Автор: Paul W. Frields
Дата публикации: 25 ноября 2015 г.
Перевод: А. Панин
Дата перевода: 22 декабря 2015 г.

systemd: зависимости и порядок запуска юнитов

И снова добро пожаловать в нашу серию статей о возможностях системы инициализации systemd. Как вы уже наверняка догадались, прочитав предыдущие статьи серии, systemd является мощной и гибкой системой инициализации, позволяющей использовать новые механизмы для запуска системных служб и управления ими. Одно из наиболее важных отличий systemd от устаревшей системы инициализации SysVinit заключается в механизме запуска юнитов.

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

Зависимости юнитов

Юнит-файлы позволяют описывать зависимости юнитов. В юнит-файле каждого юнита могут использоваться списки нужных и необходимых юнитов, которые должны быть запущены перед запуском данного юнита. Для объявления данных списков используются директивы Wants и Requires, а сами списки позволяют сформировать список зависимостей юнита. Разница между двумя упомянутыми директивами достаточно проста:

  • Если в юнит-файле юнита unit1 для описания зависимостей используется директива Wants=unit2, при запуске юнита unit1 будет автоматически запущен unit2. Но при этом результат запуска юнита unit2 ни коим образом не будет влиять на результат запуска юнита unit1.
  • Если в юнит-файле юнита unit1 для описания зависимостей используется директива Requires=unit2, то, как и в прошлый раз, будут запущены оба юнита, но в том случае, если юнит unit2 не будет успешно запущен, юнит unit1 будет автоматически деактивирован. Это произойдет вне зависимости от того, корректно ли будет функционировать процесс, соответствующий юниту unit1.

Вы не заметили каких-либо странностей в данном описании? Да, в нем не говорится ни слова о порядке запуска юнитов. В момент загрузки системы systemd загружает все юнит-файлы и составляет дерево зависимостей на основе описанных правил. В данных примерах при запуске юнита unit1 происходит одновременный запуск юнита unit2. Важно знать, что зависимости и порядок запуска юнитов являются двумя отдельными концепциями в рамках systemd.

А это пример описания зависимостей юнита в рамках юнит-файла sshd.service:

Wants=sshd-keygen.service

В соответствии с ним, при запуске юнита sshd.service также будет запущен юнит sshd-keygen.service. Однако, для успешного запуска юнита sshd.service не требуется обязательного успешного запуска юнита sshd-keygen.service.

Для чего же существуют подобные зависимости? В данном случае юнит sshd-keygen.service создает новые ключи SSH для сервера, если их не было создано заблаговременно. Наличие этих ключей следует проверять при каждом запуске сервера. Если они уже существуют, этот вспомогательный юнит завершит свою работу с возвратом информации о соответствующей ошибке. Но и вы этом случае сервер SSH будет запущен в обычном режиме.

Порядок запуска юнитов

Все описанное выше абсолютно не значит, что вы не сможете установить порядок запуска юнитов самостоятельно. При отсутствии каких-либо дополнительных инструкций, systemd действительно будет запускать группы юнитов одновременно. Скорее всего, именно по этой причине некоторые люди уверены в том, что systemd запускает все системные службы одновременно (или в "параллельном режиме"). Но, разумеется, иногда необходимо запускать процессы в определенном порядке.

К счастью, systemd также поддерживает директивы, предназначенные для решения подобных задач, а именно, Before и After. Эти директивы работают так, как вы можете предположить:

  • Если юнит-файл юнита unit1 содержит директиву Before=unit2, то при запуске обоих юнитов юнит unit1 будет запущен до момента запуска юнита unit2.
  • Если юнит-файл юнита unit1 содержит директиву After=unit2, то при запуске обоих юнитов процесс запуска юнита unit2 будет полностью завершен перед запуском юнита unit1.

И снова обратите внимание на то, что порядок запуска юнитов никак не влияет на зависимости юнитов. Ведь с помощью описанных в данном разделе директив ни в каком из случаев не будет осуществляться запуск юнита unit2. Давайте снова рассмотрим юнит-файл sshd.service:

Wants=sshd-keygen.service
After=network.target sshd-keygen.service

Директива After, регламентирующая порядок запуска юнитов, позволяет гарантированно запустить сервер SSH только после того, как окончит свою работу юнит генерации ключей для узла и будет установлено сетевое соединение. (Юнит network.target позволяет осуществить гарантированный запуск юнитов, необходимых для организации сетевого соединения.) Директивы зависимостей Wants и Requires обычно используются вместе с директивой After для корректного описания как зависимостей юнитов, так и порядка их запуска.

Уменьшение времени загрузки системы

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

Данный механизм обработки информации о юнитах является одной из причин ускорения загрузки системы при использовании systemd. Уменьшение времени загрузки системы не являлось основной целью разработки systemd, но является одним из преимуществ ее механизма обработки информации о юнитах.