Разбор высокой I/O-задержки (I/O Wait) в Linux
У Linux куча инструментов для диагностики — какие-то простые, а какие-то посерьёзнее. Проблемы с I/O Wait как раз из тех случаев, где нужны продвинутые утилиты и умение выжать максимум даже из базовых инструментов.
Разбираться с I/O Wait непросто, потому что в стандартной поставке есть масса средств, которые могут сказать вам одно: система упирается в ввод-вывод, и что-то не так.
Но вот pinpoint-ить конкретный процесс (или несколько), который всё тормозит, — умеют далеко не все.
Определяем, виноват ли I/O в том, что система тормозит
Есть несколько способов понять, вызывает ли медлительность системы именно ввод-вывод, но самый простой — команда top.
В строке CPU(s) видно, как загружен процессор и на что уходит его время.
В приведённом выше примере видно, что процессор 96% времени просто ждёт, пока завершится доступ к устройствам ввода-вывода. Это показатель wa (wait), который, как указано в man-странице top, означает «время, которое CPU проводит в ожидании завершения операций ввода-вывода».
Определяем, на какой диск идёт нагрузка
В примере выше команда top показывает общую I/O-задержку по системе, но не говорит, какой именно диск страдает. Чтобы это выяснить, используем iostat.
$ iostat -x 2 5 avg-cpu: %user %nice %system %iowait %steal %idle 3.66 0.00 47.64 48.69 0.00 0.00 Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util sda 44.50 39.27 117.28 29.32 11220.94 13126.70 332.17 65.77 462.79 9.80 2274.71 7.60 111.41 dm-0 0.00 0.00 83.25 9.95 10515.18 4295.29 317.84 57.01 648.54 16.73 5935.79 11.48 107.02 dm-1 0.00 0.00 57.07 40.84 228.27 163.35 8.00 93.84 979.61 13.94 2329.08 10.93 107.02
В приведённой команде iostat выводит отчёт каждые 2 секунды, всего 5 раз. Ключ -x включает расширенный отчёт.
Первый отчёт iostat показывает статистику с момента последней загрузки системы — поэтому его обычно можно просто проигнорировать. Все последующие отчёты показывают данные за интервал с момента предыдущего.
Например, если мы просим вывести отчёт 5 раз, то второй будет собран на основе изменений после первого, третий — после второго и так далее.
В нашем примере видно, что процент использования диска sda — 111.41%, что явно указывает: проблема связана с процессами, активно пишущими на sda.
В тестовой системе из примера всего один диск, но такая информация особенно полезна, если дисков несколько — это помогает сузить круг поиска до конкретного устройства, которое загружено I/O-операциями.
Кроме процента использования, в выводе iostat есть масса полезных метрик: количество объединённых запросов чтения и записи в миллисекунду (rrqm/s и wrqm/s), операции чтения и записи в секунду (r/s и w/s) и многое другое.
В нашем случае программа активно и читает, и пишет, — и эта информация пригодится, когда будем искать конкретный процесс, создающий нагрузку.
Определяем процессы, которые создают высокую I/O-нагрузку
Отличный инструмент, чтобы понять, какие процессы активно работают с диском, — это iotop.
# iotop Total DISK READ: 8.00 M/s | Total DISK WRITE: 20.36 M/s TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND 15758 be/4 root 7.99 M/s 8.01 M/s 0.00 % 61.97 % bonnie++ -n 0 -u 0 -r 239 -s 478 -f -b -d /tmp
Посмотрев на его вывод, сразу видно, что программа bonnie++ больше всех грузит подсистему ввода-вывода на этой машине.
Хотя iotop прост в использовании и действительно удобен, он по умолчанию установлен далеко не во всех (а часто и вовсе не в основных) дистрибутивах Linux. Лично я стараюсь не полагаться на утилиты, которых нет «из коробки».
Системный администратор может оказаться в ситуации, когда нельзя поставить дополнительные пакеты до запланированного окна обслуживания или завершения важного процесса — а к тому времени проблема может стать уже критичной.
Если iotop недоступен, не страшно: шаги ниже помогут сузить поиск и без него — до одного или нескольких процессов, создающих нагрузку.
Состояние процессов (“state”)
Команду ps знают почти все, но не все догадываются, что она умеет показывать статистику по памяти и CPU.
К сожалению, отдельной метрики для дискового ввода-вывода у неё нет, но зато она отображает состояние процесса — и по нему можно понять, ждёт ли процесс операций I/O.
Поле state в выводе ps даёт наглядное представление о том, чем занят процесс в данный момент. Чтобы было понятнее, разберём возможные состояния по man-странице ps:
D: uninterruptible sleep (обычно связано с I/O)
R: running или runnable (в очереди на выполнение)
S: interruptible sleep (ждёт завершения какого-то события)
T: stopped (остановлен сигналом управления задачами или трассировкой)
W: paging (устаревшее, не используется со времён ядра 2.6.xx)
X: dead (мертвый процесс, не должен появляться)
Z: defunct ("зомби" — завершён, но не убран родительским процессом)
Процессы, застрявшие в ожидании I/O, чаще всего находятся в состоянии D (uninterruptible sleep).
Зная это, можно легко вычислить процессы, которые постоянно висят в этом состоянии — при помощи пары строк на Bash.
# for x in `seq 1 1 10`; do ps -eo state,pid,cmd | grep "^D"; echo "----"; sleep 5; done D 248 [jbd2/dm-0-8] D 16528 bonnie++ -n 0 -u 0 -r 239 -s 478 -f -b -d /tmp ---- D 22 [kswapd0] D 16528 bonnie++ -n 0 -u 0 -r 239 -s 478 -f -b -d /tmp ---- D 22 [kswapd0] D 16528 bonnie++ -n 0 -u 0 -r 239 -s 478 -f -b -d /tmp ---- D 22 [kswapd0] D 16528 bonnie++ -n 0 -u 0 -r 239 -s 478 -f -b -d /tmp ---- D 16528 bonnie++ -n 0 -u 0 -r 239 -s 478 -f -b -d /tmp ----
Этот цикл for выводит список процессов, находящихся в состоянии D, каждые 5 секунд, всего 10 раз.
Из результата видно, что процесс bonnie++ с PID 16528 чаще других оказывается в ожидании I/O.
На этом этапе можно предположить, что именно он вызывает повышенный I/O Wait. Но важно понимать: сам по себе факт, что процесс находится в состоянии uninterruptible sleep, ещё не доказывает, что именно он виноват в задержках ввода-вывода.
Чтобы подтвердить догадку, можно воспользоваться файловой системой /proc.
У каждого процесса в каталоге /proc/<pid>/ есть файл io, который содержит статистику по I/O — ту же самую, что использует iotop.
# cat /proc/16528/io rchar: 48752567 wchar: 549961789 syscr: 5967 syscw: 67138 read_bytes: 49020928 write_bytes: 549961728 cancelled_write_bytes:
Поля read_bytes и write_bytes показывают, сколько байт конкретный процесс прочитал и записал на устройство хранения.
В нашем случае процесс bonnie++ прочитал около 46 МБ и записал 524 МБ.
Для некоторых программ это мелочь, но в нашем примере этого объёма достаточно, чтобы создать ту самую высокую I/O-задержку, которую мы наблюдаем в системе.
Определяем, какие файлы перегружаются записью
Когда мы уже нашли подозрительный процесс (или несколько), можно использовать команду lsof, чтобы посмотреть, какие файлы этот процесс держит открытыми.
Список открытых файлов позволит прикинуть, какие из них чаще всего подвергаются записи.
В примере ниже вывод lsof отфильтрован с помощью флага -p <pid>, который показывает только файлы, открытые конкретным процессом:
# lsof -p 16528 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME bonnie++ 16528 root cwd DIR 252,0 4096 130597 /tmp <truncated> bonnie++ 16528 root 8u REG 252,0 501219328 131869 /tmp/Bonnie.16528 bonnie++ 16528 root 9u REG 252,0 501219328 131869 /tmp/Bonnie.16528 bonnie++ 16528 root 10u REG 252,0 501219328 131869 /tmp/Bonnie.16528 bonnie++ 16528 root 11u REG 252,0 501219328 131869 /tmp/Bonnie.16528 bonnie++ 16528 root 12u REG 252,0 501219328 131869 /tmp/Bonnie.16528
Чтобы убедиться, что именно эти файлы активно пишутся, можно посмотреть, на каком диске находится файловая система /tmp:
# df /tmp Filesystem 1K-blocks Used Available Use% Mounted on /dev/mapper/workstation-root 7667140 2628608 4653920 37% /
Из этого вывода видно, что /tmp — часть корневого логического тома (workstation-root) в группе томов workstation.
Проверим, где физически расположен этот том:
# pvdisplay --- Physical volume --- PV Name /dev/sda5 VG Name workstation PV Size 7.76 GiB / not usable 2.00 MiB Allocatable yes PE Size 4.00 MiB Total PE 1986 Free PE 8 Allocated PE 1978 PV UUID CLbABb-GcLB-l5z3-TCj3-IOK3-SQ2p-RDPW5S
Из вывода pvdisplay видно, что раздел /dev/sda5 (часть диска sda) используется группой томов workstation, а значит, именно там лежит файловая система /tmp.
С учётом всей этой информации можно с уверенностью сказать: большие файлы, показанные в выводе lsof выше, и есть те самые, к которым процесс bonnie++ постоянно обращается для чтения и записи.