Корень всех зол
Долгое время у меня была проблема — система очень сильно тормозила после старта. У меня ноутбук с жёстким диском (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'у это
#!/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 (который поддерживает классы и приоритеты)
Какие ещё вещи следует учитывать? Расскажите о своём опыте в комментариях.
Комментарии (46)
zloddey
02.05.2016 12:04+1Индикатор load при старте системы стал подниматься выше 11, а процессорная нагрузка стала состоять по большей части из wait.
Это говорит о том, что планировщик deadline работал оптимальнее.
wait
в нагрузке процессора означает, что текущая выполняемая задача ожидает завершения I/O операций. И пока операция не завершится, другие задачи тоже вынуждены ждать, о чём и говорит рост очереди (параметрload
).
Как можно предположить, при использовании Deadline приоритет отдаётся задачам (процессам), не так активно использующим ввод-вывод, они быстрее отрабатывают, и очередь не растёт. Выходит, что при переключении на CFQ произошла деградация, и разумнее вернуться на Deadline.
Revertis
02.05.2016 12:09Но деградация была в промежуточный момент, когда ionice не выставляла правильный приоритет потокам Dropbox'а. Сейчас, скорее всего, всё намного лучше, да, Highstaker?
Highstaker
02.05.2016 15:11Да, стало намного лучше.
Видимо, deadline неправильно выставлял приоритеты процессам, и потоки dropbox в результате съедали много, просто за счёт их количества.
Пришлось через ionice вручную сообщить системе, что все потоки dropbox должны иметь низкий приоритет. И всё полетело какв попу ужаленноеракета 8)a0fs
03.05.2016 13:57А если занизить приоритет на выполнение самого демона dropbox. Не ввод-вывод а именно исполнение. Возможно будет тоже неплохо.
vasilisc
02.05.2016 13:34+12Во многих современных дистрибутивах используется новая система инициализации — systemd. Можно красиво и технично решить вашу задачу. Для Dropbox сделать стартовый юнит, что не сложно и указать там BlockIOReadBandwith
Хорошие примеры
http://0pointer.de/blog/projects/resources.htmlAVX
03.05.2016 13:58В 14.04 и до 15.04 использовалась SysV init, в 15.04 можно было переключиться и использовать systemd, а в 15.10 уже systemd по умолчанию, как и во многих современных дистрибутивах (хотя немало споров вокруг этого идёт).
Gendalph
03.05.2016 17:17В 14.04 используется
upstart
, совместимый сSysV init
,SystemD
выпилен, естьsystemd-shim
, но самогоsystemd
нету — демонами управлять он не может и поставить нормальныйsystemd
не представляется возможным.
Да и насколько я знаю, Dropbox запускается не системой, а DE, то есть запускается не какой-нибудь/etc/init.d/dropbox
, аDropbox.desktop
, так что это обсуждение — бессмысленно.
Self_Perfection
02.05.2016 14:01+7Несколько советов вам по оптимизации этого хозяйства.
Для начала попроще собираем пиды тредов dropbox:
$(ps -LC dropbox -o tid=)
Потом обращаем внимание, что ваше решение приводит к запуску 50 процессов каждые 5 секунд. Это условно ~5% загрузки процессора. Не жалко вам на это тратить ресурсы? ionice может за раз выставить io класс нескольким пидам:
ionice -c3 --pid $(ps -LC dropbox -o tid=)
Так сокращаем количество порождаемых каждые 5 секунд процессов с N тредов dropbox (у меня 51) +2 до 3
Но вообще постоянно висящий фоном скрипт с циклом тоже излишен. Достаточно заменить автозапуск dropbox на автозапуск
ionice -c3 dropbox
io класс процесса наследуется при порождении новых процессов/тредов (как и переменные окружения и практически все свойства процесса). Так что все треды, которые наклепает dropbox, тоже будут с классом idle.Highstaker
02.05.2016 15:26+2ionice -c3 --pid $(ps -LC dropbox -o tid=)
Кстати, не знал, спасибо, учту.
ionice -c3 dropbox не работает, потому что демон ДБ запускается через отдельный скрипт командой dropbox start -i. Я пытался запускать через ionice, эффекта не дало. Можно, конечно, порыться в этом скрипте…
grayich
02.05.2016 15:07Возможно чего-то не понял, но не проще ли было изначально запускать дропбокс через ionice?
ionice -c3 dropbox
Vitaljok
02.05.2016 18:49+1А есть ли что-то подобное для Windows?
Dropbox на пару с GoogleDrive на старте занимают лаптоп на добрых 10 минут.xforce
02.05.2016 20:43+3конкнретно приоритеты занижаются так:
Скрытый текст[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\syncthing.exe] [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\syncthing.exe\PerfOptions] "IoPriority"=dword:00000000 "PagePriority"=dword:00000001 [HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\syncthing.exe] [HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\syncthing.exe\PerfOptions] "IoPriority"=dword:00000000 "PagePriority"=dword:00000001
Vitaljok
02.05.2016 22:07+1Спасибо, попробую.
Это получается настройки берутся по названию exe-шки?
А как быть если разные файлы с одним названием? Какие-нибудь launcher.exe для различных софтов, или вообще java.exe. Просто любопытно.
IRainman
03.05.2016 00:32+1Только IoPriority лучше ставить Low, а не VeryLow ибо при последнем клиент будет вынужденно писать и читать данные маленькими порциями, а это увеличит количество вызовов системных API что плохо скажется на производительности в случае синхронизации большого объёма данных.
"IoPriority"=dword:00000001
и для Vitaljok и MacIn
P.S. да и в целом MS рекомендует выставлять только CPUPriority, который также называется BasePriority ибо IO выставляется тоже, вот тут разъяснения https://bitsum.com//pl_io_priority.php, но ссылки на msdn не приведу.
Ziptar
04.05.2016 00:23-3Выкинуть cd-rom, воткнуть второй hdd, перенести хранилище туда, блаженствовать.
На мой взгляд выносить хранилище таких вот штук на отдельный от системного физический носитель — лучшее из возможных решений. Если нет такой возможности — стартовать ручками по необходимости.
nuklea
02.05.2016 18:49Для периодических бэкапов с помощью rsnapshot использую стратегию Best-effort вместо Idle. Выглядит как `nice -n 19 ionice -c 2 -n 7 rsnapshot`. Почитал man ionice и так и не понял, в каких случаях лучше использовать Best-effort, а в каких Idle. Пробовал раньше использовать Idle, но производительность не устраивает в любом случае. Юниты с таймерами в systemd кажуются самым элегантным решением в сложившейся ситуации.
Romiro_Orimor
02.05.2016 18:50-1Не ради хейтерства, да и хочется понять, что это было и как с этим бороться:
Летом 2015 года, после скачки и установки deb с сайта dropbox'а и после запуска: инсталлятор начал скачивать сам клиента dropbox, попутно выжрав во время! скачивания свободные 7/8гб оперативки, все 4гб свопа(больше 500мб не поднимался прежде) и устроив нагрузку процессора(4ядра) за 50 и не установившись в итоге.
Следующая версия dropbox'а встала без проблем на тот же ноут с HDD и ubuntu 14.04 x64.
Вот такое у меня было первое знакомство с ним, так и не прижился он у меня.Barafu
03.05.2016 13:58Бага это в скрипте была, судя по симптомам. Что-то вызывало само себя бесконечно, в итоге отожрало само у себя все ресурсы и упало дружной толпой.
Я пока учился скрипты писать тоже такое сделал разок.
sim0nsays
02.05.2016 21:04+1Привет, я работаю в Dropbox (правда, в несвязанной с топиком области). Может быть, можно ключевые моменты перевести на английский, чтобы я мог передать фидбек кому надо?
Gendalph
02.05.2016 21:28+2Насколько я понял суть:
Dropbox, at least under Linux, creates ~50 threads, some of which end up competing for disk I/O on Dropbox client startup (i.e. during user login), which in turn, makes system unresponsive for minutes right after logging in.
This behavior was confirmed at least under Ubuntu 14.04.
Some people work around this decreasing I/O priority for Dropbox.
Отсебятина:
But the real fix should be either eliminating need for such massive I/O on startup or adding options to decrease number of threads that do I/O simultaneously or decreasing their priority.
Gendalph
02.05.2016 21:19@Highstaker, напишите, пожалуйста внизу поста всем, что в Ubuntu 14.04 systemd выпилен с потрохами, место под него залито бетоном, обнесено ключей проволокой и по периметру стоят пулеметные вышки.
Юзерские стартап задачи запускаются, обычно, десктопным окружением через
.desktop
файлы. Можно в~/.local
создать свой Dropbox.desktop, сionice
и запускать его. Пробовали?
Grief
02.05.2016 22:03-2Не в обиду никому, но приоритезация не ускорит I/O, а только переместит проблему в другое место, где ее будет не так сильно заметно. Почему бы не приобрести SSD (если бюджет скромный) или не замутить RAID (если деньги позволяют)?
FeNUMe
03.05.2016 01:13+5SSD в данном случае не решение проблемы, а уход от нее. Сама же проблема в плохо спроектированном софте: дропбокс не учитывает разницу между ssd/hdd, спавнит дофига потоков которые долбят диск одновременными запросами, тем самым убивая производительность hdd. Можно ведь запросто сделать только один читающий поток и кучу обрабатывающих и это вероятнее всего почти полностью решит проблему, особенно если добиться чтобы индексы в фс всегда хранились без фрагментации(не знаю возможно ли).
pansa
02.05.2016 23:29Да, костылизм тот ещё.
Если сделать предположение, что демон синхронизации дропбокса нагружает дисковое io синхронно с cpu (ну там же скорее всего диффы/хэши считаются в этот момент), то более красивым может быть решение с планировщиком процессов (не io планировщики, которые вы пытались крутить).
Гуглить по SCHED_BATCH — процесс с таким правилом будет получать свои тики только когда все остальные отдыхают. Предположительно, это даст именно то, что хотите — дропбокс будет работать только когда вы, условно, «отошли от комьютера».Highstaker
03.05.2016 08:43CPU нагружается процессом dropbox по минимуму. Бутылочное горлышко именно в I/O
pansa
03.05.2016 13:31Я понимаю, что проблема в io. Смысл в том, что процесс дропбокса не будет получать управление, когда работают другие процессы, а значит и обращений к диску не будет. Результат не гарантирован, но можно попробовать. Это более прямое решение.
xforce
03.05.2016 14:00Обычно проблема в том, что другие процессы работать не могут, т.к. сидят ждут чтения/записи диска в очереди. Именно поэтому я на ноуте с медленным диском аналогичным образом понижал приоритеты именно i/o некоторым процессам. Отзывчивость системы сильно повышается при этом.
pansa
03.05.2016 14:09Ну что вы мне третий раз одно и то же разными словами говорите? :) Понятно, что iowait. Но дропбокс плодит потоки и каждому нужно переназначать ionice, для чего в бесконечном цикле дёргается команда ionice. Работает, но выглядит костыльно, поэтому я предложил попробовать воркэраунд через планировщик процессов.
nefelim4ag
03.05.2016 08:53Для автовыставления приоритетов CPU и IO, правила можно дописывать самому, в частности для дробокса и пушить в апстрим.
https://github.com/Nefelim4ag/Ananicy
Lelik13a
03.05.2016 10:57А что мешает ограничить процессы dropbox-а с помощью cgroups?
SkazochNik
04.05.2016 13:28Видимо потому что запускается от того же юзера.
Lelik13a
04.05.2016 15:24+1Возможности cgroups не настолько ограничены, а свойство наследования группы cgroup решит проблему с запуском дочерних процессов. Relationships Between Subsystems, Hierarchies, Control Groups and Tasks.
В простейшей схеме, можно поместить запускаемый процесс в нужную группу запустив через cgexec.
youROCK
Я думаю, это скорее косяк утилиты ionice, что дисковый приоритет выставляется только для одного процесса, но не его тредов. Если запускать программу с ionice изначально, приоритет, я думаю, все же должен наследоваться