7. Поиск виновных

Fedora 15 является первым релизом Fedora, использующим systemd в качестве системы инициализации по умолчанию. Основной нашей целью при работе над выпуском F15 является обеспечение полной взаимной интеграции и корректной работы всех компонентов. При подготовке следующего релиза, F16, мы сконцентрируемся на дальнейшей полировке и ускорении системы. Для этого мы подготовили ряд инструментов (доступных уже в F15), которые должны помочь нам в поиске проблем, связанных с процессом загрузки. В этой статье я попытаюсь рассказать о том, как найти виновников медленной загрузки вашей системы, и о том, что с ними делать дальше.
Первый инструмент, который мы можем вам предложить, очень прост: по завершении загрузки, systemd регистрирует в системном журнале информацию о суммарном времени загрузки:


systemd[1]: Startup finished in 2s 65ms 924us (kernel) + 2s 828ms 195us (initrd) + 11s 900ms 471us (userspace) = 16s 794ms 590us.


Эта запись означает следующее: на инициализацию ядра (до момента запуска initrd, т.е. dracut) ушло 2 секунды. Далее, чуть менее трех секунд работал initrd. И наконец, почти 12 секунд было потрачено systemd на запуск программ из пространства пользователя. Итоговое время, начиная с того момента, как загрузчик передал управление коду ядра, до того момента, как systemd завершил все операции, связанные с загрузкой системы, составило почти 17 секунд. Казалось бы, смысл этого числа вполне очевиден. . . Однако не стоит делать поспешных выводов. Прежде всего, сюда не входит время, затраченное на инициализацию вашего сеанса в GNOME, так как эта задача уже выходит за рамки задач процесса init. Кроме того, в этом показателе учитывается только время работы systemd, хотя часто бывает так, что некоторые демоны продолжают свою работу по инициализации уже после того, как секундомер остановлен. Проще говоря: приведенные числа позволяют лишь оценить общую скорость загрузки, однако они не являются точной характеристикой длительности процесса.
Кроме того, эта информация носит поверхностный характер: она не сообщает, какие именно системные компоненты заставляют systemd ждать так долго. Чтобы исправить это упущение, мы ввели команду systemd-analyze blame:

Она выводит список юнитов systemd, активированных при загрузке, с указанием времени инициализации для каждого из них. Список отсортирован по убыванию этого времени, поэтому наибольший интерес для нас представляют первые строчки. В нашем случае это udev-settle.service и cryptsetup@luks\x2d9899b85d\x2df790\x2d4d2a\x2da650\x2d8b7d2fb92cc3.service, инициализация которых занимает более одной секунды. Стоит отметить, что к анализу вывода команды systemd-analyze blame тоже следует подходить с осторожностью: она не поясняет, почему тот или иной юнит тратит столько-то времени, она лишь констатирует факт, что время было затрачено. Кроме того, не стоит забывать, что юниты могут запускаться параллельно. В частности, если две службы были запущены одновременно, то время их инициализации будет значительно меньше, чем сумма времен инициализации каждой из них.
Рассмотрим повнимательнее первого осквернителя нашей загрузки: службу udev-settle.service (Прим. перев.: После объединения проектов systemd и udev, эта служба называется systemd-udev-settle.service). Почему ей требуется так много времени для запуска, и что мы можем с этим сделать? Данная служба выполняет очень простую функцию: она ожидает, пока udev завершит опрос устройств, после чего завершается. Опрос же устройств может занимать довольно много времени. Например, в нашем случае опрос устройств длится более 6 секунд из-за подключенного к компьютеру 3G-модема, в котором отсутствует SIM-карта. Этот модем очень долго отвечает на запросы udev. Опрос устройств является частью схемы, обеспечивающей работу ModemManager’а и позволяющей NetworkManager’у упростить для вас настройку 3G. Казалось бы, очевидно, что виновником задержки является именно ModemManager, так как опрос устройств для него занимает слишком много времени. Но такое обвинение будет заведомо ошибочным. Дело в том, что опрос устройств очень часто оказывается довольно длительной процедурой. Медленный опрос 3G-устройств для ModemManager является частным случаем, отражающим это общее правило. Хорошая система опроса устройств обязательно должна учитывать тот факт, что операция опроса любого из устройств может затянуться надолго. Истинной причиной наших проблем является необходимость ожидать завершения опроса, т.е., наличие службы udev-settle.service как обязательной части нашего процесса загрузки.
Но почему эта служба вообще присутствует в нашем процессе загрузки? На самом деле, мы можем прекрасно обойтись и без нее. Она нужна лишь как часть используемой в Fedora схемы инициализации устройств хранения, а именно, набора скриптов, выполняющих настройку LVM, RAID и multipath-устройств. На сегодняшний день, реализация этих систем не поддерживает собственного механизма поиска и опроса устройств, и поэтому их запуск должен производиться только после того, как эта работа уже проделана — тогда они могут просто последовательно перебирать все диски. Однако, такой подход противоречит одному из фундаментальных требований к современным компьютерам: возможности подключать и отключать оборудование в любой момент, как при выключенном компьютере, так и при включенном. Для некоторых технологий невозможно точно определить момент завершения формирования списка устройств (например, это характерно для USB и iSCSI), и поэтому процесс опроса таких устройств обязательно должен включать некоторую фиксированную задержку, гарантирующую, что все подключенные устройства успеют отозваться. С точки зрения скорости загрузки это, безусловно, негативный эффект: соответствующие скрипты заставляют нас ожидать завершения опроса устройств, хотя большинство этих устройств не являются необходимыми на данной стадии загрузки. В частности, в рассматриваемой нами системе LVM, RAID и multipath вообще не используются!

Лирическое отступление автора:
Наиболее правильным решением в данном случае будет ожидание событий подключения устройств (реализованное через libudev или аналогичную технологию) с соответствующей обработкой каждого такого события — подобный подход позволит нам продолжить загрузку, как только будут готовы все устройства, необходимые для ее продолжения. Для того, чтобы загрузка была быстрой, мы должны ожидать завершения инициализации только тех устройств, которые действительно необходимы для ее продолжения на данной стадии. Ожидать остальные устройства в данном случае смысла нет. Кроме того, стоит отметить, что в числе программ, не приспособленных для работы с динамически меняющимся оборудованием и построенных в предположении о неизменности списка устройств, кроме служб хранения, есть и другие подсистемы. Например, в нашем случае работа initrd занимает так много времени главным образом из-за того, что для запуска Plymouth необходимо дождаться завершения инициализации всех устройств видеовывода. По неизвестной причине (во всяком случае, неизвестной для меня) подгрузка модулей для моих видеокарт Intel занимает довольно продолжительное время, что приводит к беспричинной задержке процесса загрузки. Я возражаю не против опроса устройств как такового, но против необходимости ожидать его завершения, чтобы продолжить загрузку.

С учетом вышесказанного, мы можем спокойно исключить udev-settle.service из нашего процесса загрузки, так как мы не используем ни LVM, ни RAID, ни multipath.
Замаскируем эти службы, чтобы увеличить скорость загрузки:


# ln -s /dev/null /etc/systemd/system/udev-settle.service
# ln -s /dev/null /etc/systemd/system/fedora-wait-storage.service
# ln -s /dev/null /etc/systemd/system/fedora-storage-init.service
# systemctl daemon-reload


После перезагрузки мы видим, что загрузка стала на одну секунду быстрее. Но почему выигрыш оказался таким маленьким? Из-за второго осквернителя нашей загрузки — cryptsetup. На рассматриваемой нами системе зашифрован раздел /home. Специально для нашего тестирования я записал пароль в файл, чтобы исключить влияние скорости ручного набора пароля. К сожалению, для подключения шифрованного раздела cryptsetup требует более пяти секунд. Будем ленивы, и вместо того, чтобы исправлять ошибку в cryptsetup, попробуем найти обходной путь. Во время загрузки systemd должен дождаться, пока все файловые системы, перечисленные в /etc/fstab (кроме помеченных как noauto) будут обнаружены, проверены и смонтированы. Только после этого systemd может продолжить загрузку и приступить к запуску служб. Но первое
обращение к /home (в отличие, например, от /var), происходит на поздней стадии процесса загрузки (когда пользователь входит в систему). Следовательно, нам нужно сделать так, чтобы этот каталог автоматически монтировался при загрузке, но процесс загрузки не ожидал завершения работы cryptsetup, fsck и mount для этого раздела. Как же сделать точку монтирования доступной, не ожидая, пока завершится процесс монтирования? Этого можно достичь, воспользовавшись магической силой systemd — просто добавим опцию монтирования comment=systemd.automount в /etc/fstab. После этого, systemd будет создавать в /home точку автоматического монтирования, и при первом же обращении к этому каталогу, если файловая система еще не будет готова к работе, systemd подготовит соответствующее устройство, проверит и смонтирует ее.

После внесения изменений в /etc/fstab и перезагрузки мы получаем:


systemd[1]: Startup finished in 2s 47ms 112us (kernel) + 2s 663ms 942us (initrd) + 5s 540ms 522us (userspace) = 10s 251ms 576us.


Прекрасно! Несколькими простыми действиями мы выиграли почти семь секунд. И эти два изменения исправляют только две наиболее очевидные проблемы. При более аккуратном и детальном исследовании, обнаружится еще множество моментов, которые можно улучшить. Например, на другом моем компьютере, лаптопе X300 двухлетней давности (и даже два года назад он был не самым быстрым на Земле), после небольшой доработки, время загрузки до полноценной среды GNOME составило около четырех секунд, и это еще не предел совершенства.
systemd-analyze blame — простой и удобный инструмент для поиска медленно запускающихся служб, однако он обладает одним существенным недостатком: он не показывает, насколько эффективно параллельный запуск снижает потерю времени для медленно запускающихся служб. Чтобы вы могли наглядно оценить этот фактор, мы подготовили команду systemd-analyze plot. Использовать ее очень просто:


$ systemd-analyze plot > plot.svg
$ eog plot.svg


Она создает наглядные диаграммы, показывающие моменты запуска служб и время, затраченное на их запуск, по отношению к другим службам. На текущий момент, она не показывает явно, кто кого ожидает, но догадаться обычно несложно. У наиболее эрудированных читателей может возникнуть вопрос: как это соотносится с программой bootchart? Действительно, systemd-analyze plot и bootchart рисуют похожие графики. Однако, bootchart является намного более мощным инструментом — он детально показывает, что именно происходило во время загрузки, и отображает соответствующие графики использования процессора и ввода-вывода. systemd-analyze plot оперирует более высокоуровневой информацией: сколько времени затратила та или иная служба во время запуска, и какие службы были вынуждены ее ожидать. Используя оба
этих инструмента, вы значительно упростите себе поиск причин замедления вашей загрузки.
Но прежде, чем вы вооружитесь описанными здесь средствами и начнете отправлять багрепорты авторам и сопровождающим программ, которые замедляют вашу загрузку, обдумайте все еще раз. Эти инструменты предоставляют вам «сырую» информацию.
Постарайтесь не ошибиться, интерпретируя ее. Например, в при рассмотрении приведенного выше примера я показал, что проблема была вовсе не в udev-settle.service, и не в опросе устройств для ModemManager’а, а в неудачной реализации подсистемы хранения, требующей ожидать окончания опроса устройств для продолжения загрузки.
Именно эту проблему и нужно исправлять. Поэтому постарайтесь правильно определить источник проблем. Возлагайте вину на тех, кто действительно виноват.

Как уже говорилось выше, все три описанных здесь инструмента доступны в Fedora 15 «из коробки».

Итак, какие же выводы мы можем сделать из этой истории?
* systemd-analyze — отличный инструмент. Фактически, это встроенный профилировщик systemd.
* Постарайтесь не ошибиться, интерпретируя вывод профилировщика!
* Всего два небольших изменения могут ускорить загрузку системы на семь секунд.
* Программное обеспечение, не способное работать с динамически меняющимся набором устройств, создает проблемы, и должно быть исправлено.
* Принудительное использование в стандартной установке Fedora 15 промышленной реализации подсистем хранения, возможно, является не самым правильным решением.

Содержание
Вперед - Новые конфигурационные файлы
Назад - Смена корня