Кто грузит диск: iotop и атрибуция io процессам

Рейтинг: 72.2% · 10 голосов
Подробный курс по диагностике и производительности Linux для админов и DevOps: с чего начать, методология USE, логи (journalctl, dmesg), процессы, CPU, память и OOM, диск и IO (iostat), сеть (ss, tcpdump), системные вызовы и strace, ltrace, perf, флеймграфы, ftrace, eBPF и bpftrace, lsof, мониторинг. Разбор каждого инструмента с чтением вывода.
Ответить
Аватара пользователя
Dmitry_SRE
Сообщения: 47
Зарегистрирован: 11 май 2026, 05:31

Кто грузит диск: iotop и атрибуция io процессам

Сообщение Dmitry_SRE »

Оглавление курса (47)
  1. С чего начать диагностику Linux: методология вместо паники
  2. Первые 60 секунд: экспресс-диагностика нагруженного сервера
  3. Методологии диагностики: USE, RED и здравый смысл
  4. Логи systemd через journalctl: где искать причину
  5. Где лежат логи Linux: /var/log, dmesg и rsyslog
  6. Источники правды: load average, /proc и /sys
  7. Процессы Linux: ps, pstree и состояния процессов
  8. Интерактивный мониторинг: top и htop
  9. Метрики процессов во времени: pidstat
  10. Приоритеты и ограничения: nice, ionice, cgroups
  11. Сигналы и зависшие процессы: kill, и что делать с D-state
  12. Загрузка CPU: user, system, iowait, steal и контекст-свитчи
  13. Диагностика CPU по ядрам: vmstat и mpstat
  14. Профилирование CPU: perf top и поиск пожирателя
  15. Частоты, троттлинг и NUMA: turbostat и numastat
  16. Память Linux: RSS, VSZ, page cache и миф о нехватке памяти
  17. Сколько памяти занято: free, /proc/meminfo и vmstat
  18. Поиск утечек и пожирателей памяти: smem, pmap, smaps
  19. Swap и подкачка: swapon, swappiness, когда своп - это боль
  20. OOM killer: кто и за что убил процесс
  21. Память ядра и slab: slabtop и куда уходит RAM
  22. Подсистема ввода-вывода: путь запроса от приложения до диска
  23. Диагностика диска: iostat и чтение await, %util
  24. Кто грузит диск: iotop и атрибуция io процессам (вы здесь)
  25. Файловые системы: df, du, иноды и куда делось место
  26. Глубокая диагностика блочного слоя: blktrace и biolatency
  27. Кеш страниц и грязные данные: dirty pages, fsync, drop_caches
  28. Сетевой стек Linux: путь пакета и где возникают задержки
  29. Сокеты и соединения: ss и netstat
  30. Захват трафика: tcpdump для диагностики сети
  31. Задержки и потери в сети: ping, mtr, диагностика латентности
  32. Сеть как источник проблем: nftables, conntrack, дропы
  33. Что такое системный вызов и зачем его трассировать
  34. strace: трассировка системных вызовов на практике
  35. strace в бою: почему программа висит, падает или тормозит
  36. ltrace: трассировка вызовов библиотек
  37. Накладные расходы трассировки и безопасные альтернативы
  38. perf: универсальный профайлер Linux
  39. Флеймграфы: визуализация профиля производительности
  40. Трассировка ядра: ftrace и trace-cmd
  41. eBPF: революция в наблюдаемости Linux
  42. Инструменты eBPF на практике: BCC и bpftrace
  43. lsof: открытые файлы, дескрипторы, кто держит файл и порт
  44. Разбор кейса: приложение тормозит - пошаговая диагностика
  45. Непрерывный мониторинг: sar, node_exporter, Grafana, Zabbix
  46. Диагностика в контейнерах: cgroups, лимиты, Docker и Kubernetes
  47. Карта инструментов и сквозной разбор инцидента производительности
Представь: ты запустил iostat, и он честно показал, что диск стоит на ушах - %util под сотню, очередь aqu-sz забита, await растёт. Хорошо, проблема найдена. Но iostat говорит про устройство (sda, nvme0n1), а не про процессы. Он как датчик на въезде в город: видно, что пробка есть, а кто именно в неё встал - не видно. И вот тут начинается самый частый вопрос новичка: ну ладно, диск загружен, а КТО его грузит? Какой именно процесс молотит по диску прямо сейчас?

В этом уроке мы закрываем этот разрыв. Берём перегруженное устройство и находим конкретного виновника - тот PID, который реально пишет и читает. Инструменты простые и есть почти везде: iotop, pidstat -d и счётчики в /proc. А в конце разберём, чем эту классику в 2026 году дополняет eBPF (biotop/biosnoop), который уже стал стандартом для глубокой атрибуции. Если ты хоть раз гуглил "iotop" или "кто грузит диск linux" - это ровно про то.

Откуда вообще берутся цифры по io процесса

Сначала немного механики, без неё цифры будут магией. Ядро Linux считает дисковый ввод-вывод на двух уровнях, и их важно не путать.

Первый уровень - системные вызовы. Когда программа делает read() или write(), ядро складывает байты в счётчики rchar и wchar. Это "сколько приложение попросило". Но запрос на запись почти никогда не идёт сразу на диск: он оседает в page cache - оперативной памяти, которую ядро использует как буфер. Программа уже думает, что записала, а физически данные ещё лежат в RAM и полетят на блин/флеш позже, при сбросе (writeback).

Второй уровень - реальный блочный io. Тут живут счётчики read_bytes и write_bytes: это сколько байт по-настоящему ушло в storage. Вот эти цифры и совпадают с тем, что показывает iostat на устройстве.

Почему это критично для новичка: процесс может "писать" гигабайты в секунду через write(), а диск при этом почти спит - всё ушло в кеш. И наоборот: процесс давно ничего не пишет, а write_bytes растут - это ядро лениво сбрасывает накопленный кеш на диск. Поэтому фактический io процесса и то, что просило приложение, - две разные величины. Запомни связку: rchar/wchar - просьба приложения, read_bytes/write_bytes - реальная работа диска.

Посмотреть эти счётчики можно руками, без всяких утилит, прямо из /proc:

Код: Выделить всё

sudo cat /proc/$(pgrep -n mysqld)/io

Код: Выделить всё

rchar: 10543219712
wchar: 8732190455
syscr: 2841902
syscw: 1992011
read_bytes: 4096000000
write_bytes: 3221225472
cancelled_write_bytes: 16777216
Как читать. rchar/wchar - байты, прочитанные/записанные через системные вызовы (с учётом кеша). syscr/syscw - сколько было самих вызовов read/write; если syscw огромный, а wchar маленький, приложение пишет крошечными порциями (плохой паттерн, мелочь забивает диск). read_bytes/write_bytes - байты, реально ушедшие на устройство хранения. Если wchar большой, а write_bytes маленький - запись отлично кешируется в RAM, до диска доходит немного. cancelled_write_bytes - "отменённая" запись: процесс набросал данные в кеш, а потом удалил/обрезал файл до сброса, и ядру не пришлось ничего писать. Это нормально и даже хорошо. Один минус /proc/PID/io - это накопительные счётчики с момента старта процесса, не скорость. Чтобы получить скорость, нужны два замера с интервалом и вычитание. К счастью, за нас это уже делают готовые утилиты.

Изображение

iotop - top по диску: кто грузит диск прямо сейчас

iotop - это интерактивный монитор, по духу как top, только не про CPU, а про диск. Требует root (читает аккаунтинг по всем процессам через интерфейс taskstats ядра), поэтому запускаем через sudo:

Код: Выделить всё

sudo iotop
Если команды нет, ставится одним пакетом: в Debian/Ubuntu и Astra Linux - apt install iotop, в RHEL/Fedora/RED OS - dnf install iotop. Важная деталь на 2026: старый iotop был на Python, последний релиз которого вышел ещё в 2013 году. Современные дистрибутивы поставляют переписанную на C версию iotop-c (её ведёт Boian Bonev) - она быстрее, не тянет Python и часто ставится просто как пакет iotop. Поведение и флаги совместимы, так что всё ниже работает для обеих.

Сразу полезный режим, чтобы не отвлекаться на спящие процессы:

Код: Выделить всё

sudo iotop -oPa
Здесь -o (only) показывает только те процессы, что реально делают io прямо сейчас; -P - агрегировать по процессам, а не по потокам (иначе один postgres размножится на десятки тредов); -a - накопительный режим (сколько процесс налил io за время наблюдения). Вывод выглядит так:

Код: Выделить всё

Total DISK READ:   45.20 M/s | Total DISK WRITE:   12.10 M/s
Current DISK READ: 45.10 M/s | Current DISK WRITE:  11.80 M/s
    PID  PRIO  USER   DISK READ  DISK WRITE  SWAPIN     IO>    COMMAND
   3412  be/4  mysql   42.00 M/s    8.50 M/s  0.00 %  92.30 %  mysqld
   1180  be/4  root     2.10 M/s    0.00 B/s  0.00 %   5.10 %  rsync ...
   2207  be/4  www      0.00 B/s    3.60 M/s  0.00 %   1.20 %  php-fpm
Разберём по колонкам, это и есть главное. DISK READ и DISK WRITE - фактическая скорость чтения и записи на диск этим процессом (тот самый реальный блочный io, не кеш). PRIO - класс и приоритет io-планировщика (be/4 это best-effort, средний; бывают rt - realtime и idle - только когда диск свободен; их выставляют через ionice). SWAPIN - процент времени, что процесс ждал подкачку страниц из swap; если тут не ноль - у тебя ещё и память в дефиците, диск дёргают свопом. Колонка IO> - процент времени, который процесс провёл в ожидании io. Вот она часто важнее самих мегабайт: процесс может лить всего пару M/s, но если IO> под 100%, значит он почти всё время висит на диске и сам же тормозит. В примере виновник очевиден - mysqld с 42 M/s чтения и IO> 92%. Это и есть наш клиент.

Важный нюанс 2026 года, на котором спотыкаются все. Начиная с ядра 5.14 механизм delay accounting (он и питает колонки SWAPIN и IO>) по умолчанию ВЫКЛЮЧЕН - его отключили из-за накладных расходов. Поэтому на свежей Ubuntu, Debian, Astra или RED OS свежий iotop при старте ругнётся, что CONFIG_TASK_DELAY_ACCT не активен, а колонки SWAPIN и IO> будут пустыми. Лечится одной строкой:

Код: Выделить всё

sudo sysctl kernel.task_delayacct=1
В интерактивном iotop то же самое включается на лету сочетанием Ctrl-T. Выключить обратно (чтобы не платить за аккаунтинг постоянно) - sudo sysctl kernel.task_delayacct=0. Сами колонки DISK READ/WRITE при этом работают всегда, delay accounting нужен только ради SWAPIN и IO>.

Управление: стрелками влево/вправо меняешь колонку сортировки, r переворачивает порядок, o переключает режим "только активные", p - агрегацию по процессам/потокам. Выход - q.

pidstat -d - та же атрибуция io, но в скрипты и логи

iotop хорош, когда ты сидишь у терминала и смотришь живьём. Но он интерактивный, его не положишь в cron и не отдашь в лог. Для неинтерактивной атрибуции дисковой нагрузки на процессы есть pidstat из пакета sysstat (тот же, откуда iostat). Связка pidstat диск - рабочая лошадка для автоматики, и, в отличие от iotop, root тут не обязателен для своих процессов.

Код: Выделить всё

pidstat -d 1
Цифра 1 - интервал в секундах, замер раз в секунду. Можно добавить число итераций (pidstat -d 1 5 - пять замеров и выход). Вывод:

Код: Выделить всё

15:42:07      UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s iodelay  Command
15:42:08     1001      3412  43008.00   8704.00      0.00     145  mysqld
15:42:08        0      1180   2150.00      0.00      0.00       3  rsync
15:42:08       33      2207      0.00   3686.40      0.00       0  php-fpm
По колонкам. kB_rd/s - килобайт в секунду, которые процесс заставил прочитать с диска. kB_wr/s - килобайт в секунду на запись на диск. kB_ccwr/s - "отменённая" запись (то же, что cancelled_write_bytes из /proc): процесс натворил грязных страниц в кеше, а потом обрезал/удалил файл, и до диска они не дошли. iodelay - задержка блочного io этого процесса в тактах ядра (clock ticks): сколько процесс простоял, ожидая завершения синхронных дисковых операций и swapin. Высокий iodelay - явный признак, что процесс упирается именно в диск, а не считает на CPU. В примере снова виден mysqld: 43 MB/s чтения и заметный iodelay 145. Замечание на 2026: колонка iodelay тоже опирается на delay accounting, так что если ты не включил kernel.task_delayacct=1, она будет нулевой - это та же история, что с IO> в iotop.

Чтобы не разгребать всех подряд, фильтруй по команде:

Код: Выделить всё

pidstat -d 1 -C mysqld
А для записи в лог с временными метками удобно так:

Код: Выделить всё

pidstat -dl 1 60 >> /var/log/io_who.log
Флаг -l показывает командную строку целиком (с аргументами - полезно отличить два php-fpm друг от друга), 1 60 - минута замеров по секунде. Заметь: pidstat показывает реальный блочный io (kB_rd/s и kB_wr/s), как и iotop, поэтому числа в обоих инструментах обычно сходятся. Если процесс активно "пишет", но kB_wr/s около нуля - запись поглощается page cache, и физического давления на диск пока нет.

eBPF в 2026: biotop и biosnoop для глубокой атрибуции

iotop и pidstat отвечают на вопрос "кто и сколько". Но они работают через периодический опрос счётчиков и теряют короткоживущие процессы (бэкап на 0.5 секунды просто не попадёт в кадр) и не показывают задержку каждой отдельной операции. В 2026 году стандартный ответ на это - eBPF-инструменты из наборов bcc и bpftrace, которые трассируют сам блочный слой ядра. Ставятся пакетом bpfcc-tools (Debian/Ubuntu/Astra) или bcc-tools (RHEL/RED OS); нужно ядро не древнее 4.x, на современных дистрибутивах всё уже есть.

biotop - это буквально top по блочному io, но построенный на трассировке, а не на опросе. Он точно ловит даже мелкие и короткие операции:

Код: Выделить всё

sudo biotop-bpfcc

Код: Выделить всё

PID    COMM       D MAJ MIN DISK       I/O  Kbytes  AVGms
3412   mysqld     R 259   0 nvme0n1    842  421000   0.38
1180   rsync      R 259   0 nvme0n1     21    2150   0.51
2207   php-fpm    W 259   0 nvme0n1     45    3686   1.92
Колонки: D - направление (R чтение, W запись), I/O - число операций за интервал, Kbytes - объём, AVGms - средняя задержка одной операции в миллисекундах. AVGms - то, чего нет в iotop: видно не только объём, но и насколько больно каждая операция даётся. Второй инструмент, biosnoop, печатает КАЖДУЮ операцию построчно с PID, размером и латентностью - незаменим, когда нужно поймать редкие медленные io:

Код: Выделить всё

sudo biosnoop-bpfcc

Код: Выделить всё

TIME(s)     COMM         PID    DISK    T SECTOR    BYTES  LAT(ms)
0.000000    mysqld       3412   nvme0n1 R 1048576   16384    0.42
0.004210    jbd2/nvme0   289    nvme0n1 W 88210432  4096     8.71
Тут LAT(ms) - задержка конкретной операции; всплеск в десятки мс на отдельных строках сразу выдаёт проблемный io. Это не замена iotop для повседневки, а тяжёлая артиллерия, когда обычные утилиты не дают картинки. Главная мысль на 2026: для глубокой атрибуции дисковой нагрузки eBPF уже вытеснил старые подходы, и знать biotop/biosnoop в SRE-работе обязательно.

Типичные грабли и заблуждения
  • Пустые колонки IO> и SWAPIN в iotop (и нулевой iodelay в pidstat). Самая частая засада на свежих ядрах: с 5.14 delay accounting выключен по умолчанию. Не баг - включи sudo sysctl kernel.task_delayacct=1 (или Ctrl-T в iotop). Колонки DISK READ/WRITE работают и без этого.
  • "iotop не запускается". Чаще всего забыли sudo - без root утилита не получит аккаунтинг по чужим процессам через taskstats.
  • Путают page cache и реальную запись. Видят в приложении "записал 5 ГБ", а диск спокоен. Это норма: write() ушёл в кеш. Реальная нагрузка проявится при сбросе (можно увидеть всплеск write_bytes и работу ядерных потоков kworker и jbd2 при flush). Не ищи виновника там, где работает кеш.
  • Смотрят только на мегабайты и игнорируют IO>/iodelay/AVGms. Процесс с маленьким потоком, но огромным временем ожидания io грузит диск мелкими случайными запросами хуже, чем тот, кто льёт крупным последовательным потоком. На HDD это критично, да и на дешёвом SSD тоже.
  • Берут /proc/PID/io как скорость. Там накопительные счётчики с момента старта, а не B/s. Для скорости нужны два замера во времени - или просто бери pidstat/iotop/biotop, они это считают сами.
  • Винят kworker или jbd2. Это не "вирус", а ядерные потоки, которые сбрасывают чужой кеш и ведут журнал ФС. Настоящий виновник - тот, кто наполнил этот кеш; ищи его по wchar и по логике приложения, а не по имени ядерного треда.
Мини-лаба: найди нагрузку диска по процессу руками

Делается за пять минут на любой тестовой машине (не на проде).
  • Включи аккаунтинг, иначе не увидишь IO>: sudo sysctl kernel.task_delayacct=1.
  • Открой два терминала. В первом запусти sudo iotop -oPa.
  • Во втором создай управляемую нагрузку записи: dd if=/dev/zero of=/tmp/testio bs=1M count=2000 oflag=direct. Флаг oflag=direct заставляет писать мимо page cache, прямо на диск - так ты увидишь реальный io. Найди dd в iotop, посмотри его DISK WRITE и IO>.
  • Теперь убери oflag=direct и повтори: dd if=/dev/zero of=/tmp/testio bs=1M count=2000. Заметь, что DISK WRITE в iotop теперь скачет неравномерно (кеш копит и сбрасывает порциями), а не ровным потоком.
  • Параллельно во втором терминале запусти pidstat -d 1 -C dd и сравни kB_wr/s с тем, что в iotop. Должны совпадать по порядку.
  • Посмотри сырые счётчики: sudo cat /proc/$(pgrep -n dd)/io. Сравни wchar (что попросило dd) и write_bytes (что реально ушло на диск).
  • Если есть eBPF-тулзы: в третьем терминале запусти sudo biotop-bpfcc и посмотри на колонку AVGms во время dd - сравни задержку при oflag=direct и без него.
  • Прибери за собой: rm /tmp/testio.
Контрольные вопросы
  • Чем отличаются wchar и write_bytes в /proc/PID/io и почему первое может быть сильно больше второго?
  • В iotop процесс показывает скромные DISK READ, но IO> около 100%. О чём это говорит и почему такой процесс опасен для диска?
  • Ты запустил iotop на свежем сервере, а колонки SWAPIN и IO> пустые. В чём причина на ядрах 5.14 и новее и как это исправить?
  • Зачем нужен pidstat -d, если есть iotop, и что дополнительно дают eBPF-инструменты biotop/biosnoop?
Что запомнить

iostat говорит, что устройство перегружено; iotop и pidstat -d говорят, КТО его грузит - это и есть рабочая связка диагностики дисковой нагрузки. iotop - интерактивный top по диску (нужен root, смотри колонки DISK READ/WRITE, SWAPIN и особенно IO>; на современных дистрибутивах это iotop-c). pidstat -d 1 - то же по процессам, но без интерактива, для скриптов и логов (kB_rd/s, kB_wr/s, iodelay). На 2026 помни про delay accounting: с ядра 5.14 он выключен по умолчанию, и без kernel.task_delayacct=1 колонки IO>/SWAPIN/iodelay будут пустыми. Для глубокой атрибуции и латентности отдельных операций бери eBPF: biotop и biosnoop. Под капотом всё опирается на счётчики /proc/PID/io, где rchar/wchar это просьба приложения, а read_bytes/write_bytes - реальный диск. Всегда держи в голове page cache: записал в кеш не значит записал на диск. Нашёл PID - дальше смотри strace/lsof по этому процессу и думай, что он там делает.
👍2 ❤️3 🔥 😄 🤔
Аватара пользователя
elasticninja
Сообщения: 1
Зарегистрирован: 25 май 2026, 14:30

Re: Кто грузит диск: iotop и атрибуция io процессам

Сообщение elasticninja »

Спасибо, наконец дошло про page cache. У меня приложение по логам пишет тонну, а iostat на диске спокоен - думал глюк, оказывается все в кеш улетает. А iotop сразу показал что реально грузит диск совсем другой процесс, бэкап по крону.
👍2 ❤️1 🔥 😄 🤔1
Аватара пользователя
pg23
Сообщения: 1
Зарегистрирован: 13 май 2026, 02:14

Re: Кто грузит диск: iotop и атрибуция io процессам

Сообщение pg23 »

Подтверждаю про task_delayacct. На свежей Astra колонки IO> и SWAPIN были пустые, iotop ругался на CONFIG_TASK_DELAY_ACCT. sysctl kernel.task_delayacct=1 и сразу все появилось, ядро пересобирать не надо. Хорошо что в уроке прямо предупредили.
👍1 ❤️1 🔥 😄 🤔1
Ответить
← Предыдущая глава
Диагностика диска: iostat и чтение await, %util
Следующая глава →
Файловые системы: df, du, иноды и куда делось место

Все главы курса «Диагностика и производительность Linux: логи, strace, perf и eBPF»

Поделиться темой: ✈ Telegram VK
Похожие запросы: perf top как найти что грузит процессорчто такое системный вызов и зачем трассироватькак посмотреть процессы в linux и убить зависшийhtop и top как читать и в чем разницачто такое load average в linux и какое значение нормальноеiostat как читать await и util диска linux

Вернуться в «Диагностика и производительность Linux: логи, strace, perf и eBPF»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость