Корень всех зол
Долгое время у меня была проблема — система очень сильно тормозила после старта. У меня ноутбук с жёстким диском (HDD) и Ubuntu 14.04.
Как выяснилось, причина крылась в одной лишь программе — демоне Dropbox. Dropbox — это онлайновое файловое хранилище, а его демон — программка, синхронизирующая файлы, расположенные в определённой папке, с онлайн-хранилищем. На старте демон начинает считывать свой кэш. У меня он занимает не одну сотню мегабайт, а удалять его вручную не стоит — есть вероятность потерять данные. Учитывая, что у меня жёсткий диск — устройство с механическими частями — демон начинал потреблять время доступа к нему настолько, что пользоваться компьютером и запускать приложения становилось малореально, пока он не прогрузится. Убрать его из автозапуска и запускать вручную? Неприятное решение, у меня и так есть вещи, которые я на старте вынужден запускать сам (например, iotop, он без прав суперпользователя не запускается). Нужно было найти способ сделать приложение менее прожорливым именно на диск.
ionice нам в помощь. Или нет?
Первое, о чём я услышал по этой теме, была утилитка ionice. Она позволяет изменять приоритет доступа к диску для заданного процесса. Согласно мануалу, существуют три класса приоритетности ввода/вывода. Меня интересовал idle, поскольку он, как я понял из описания, нейтрализует прожорливость приложения, пропуская всегда вперёд него процессы других классов приоритета. Казалось, дело в шляпе, и всё, что надо сделать, это:
ionice -c3 -p $(pgrep dropbox)
Сделано. Эффекта — ноль. Как же так? Ладно, роем дальше.
Scheduler'ы, или «я ничего не понял, но звучит круто»
Как выяснилось, по умолчанию ionice на моей системе вообще не функционирует, поскольку должен быть включён планировщик CFQ. А по умолчанию в новых Убунтах включён планировщик deadline. Не стану вдаваться в подробности, чем они отличаются, ибо сам не до конца въехал. В общем, читаю краткое пояснение по этому делу, а потом меняю планировщик командой (вернее, я добавил эту команду в /etc/rc.local, чтобы планировщик GFQ выставлялся на старте автоматически):
echo cfq > /sys/block/sda/queue/scheduler
Что-то в системе слегка изменилось. Индикатор load при старте системы стал подниматься выше 11, а процессорная нагрузка стала состоять по большей части из wait. Не уверен, что это всё значит в долгосрочной перспективе, но проблема осталась — переключение на CFQ и последующее применение ionice на процесс dropbox на производительность системы на старте никакого заметного эффекта не произвело: ни положительного, ни отрицательного.
Ну кто столько потоков запускает?! О специфике демона Dropbox.
Я уж было разочаровался, но тут я заметил, что в top показан только один процесс dropbox, а iotop показывает несколько. И кстати, почему в top колонка идентификаторов процессов называется PID, а в iotop — TID? В чём разница между ними? Ответ быстро нашёлся. В моём же случае самое важное открытие: демон Dropbox для своих дел запускает несколько потоков. Много потоков. Выяснилось, что не один десяток. И диск начинают читать иногда по нескольку одновременно. Так вот откуда такие тормоза! А ionice не работал потому, что, присвоив класс приоритета основному процессу, он не передаёт этот класс приоритета дочерним потокам. Поэтому они как были со стандартным классом приоритета, так с ним и остались.
Что ж, как говорят британцы, будем применять bodging. По-нашему, «костыли». Сделаем скриптик, который будет засекать процесс dropbox и все его дочерние потоки, брать их идентификаторы (PID или TID, в данном случае ionice'у это изофаллично до лампочки без особой разницы), и присваивать всем класс idle время от времени (на случай, если dropbox убивает часть дочерних потоков и/или создаёт новые).
#!/bin/bash
while true
do
#собираем список дочерних потоков
TIDS=( $(ps -L --pid $(pgrep -x dropbox) -o tid=) )
for i in "${TIDS[@]}"
do
echo $i
#присваиваем приоритет idle
ionice -c3 -p $i
done
sleep 5
done
Добавляем в автозапуск, перезагружаемся.
И всё заработало почти как будто демона Dropbox вообще нету. Эврика!
Итоги
Таким образом можно работать с любым процессом, потребляющим много дискового времени. Достаточно задать приоритет с помощью ionice и не забывать о подводных камнях, в частности:
- следить, не запускает ли процесс прожорливые дочерние потоки
- иметь в виду, что на некоторых системах планировщик ввода/вывода по умолчанию — не CFQ (который поддерживает классы и приоритеты)
Какие ещё вещи следует учитывать? Расскажите о своём опыте в комментариях.
Автор: Highstaker