vmstat и iostat — что делает CPU и диск под капотом
top показывает snapshot прямо сейчас. Но что было 5 минут назад? Какие диски нагружены? Сколько именно ops/sec идёт? Для этих вопросов есть vmstat и iostat — утилиты из пакета sysstat, выдающие time-series снимки vital metrics. Они — мост между “система медленно работает” и “вот конкретно что тормозит”.
В этом уроке: как читать вывод vmstat 1 (memory, swap, IO, system, CPU), iostat -xz 1 (per-disk метрики: r/s, w/s, await, %util), и sar — архив исторических метрик (“что было в 3:42 ночью когда упал alert”).
vmstat: системные метрики во времени
$ vmstat 2 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 0 0 2945676 124356 9821456 0 0 12 45 187 234 4 1 94 1 0
0 0 0 2945412 124356 9821456 0 0 0 132 423 812 2 1 97 0 0
2 1 0 2944008 124356 9821456 0 0 24 215 511 945 6 2 88 4 0
1 0 0 2944168 124356 9821456 0 0 8 74 234 456 3 1 95 1 0
0 0 0 2944168 124356 9821456 0 0 0 13 198 389 1 0 99 0 0
Команда vmstat 2 5 = снимок каждые 2 секунды, всего 5 раз. Без аргументов — один snapshot (averages с момента boot, не очень полезно для дебага).
Колонки:
procs:
- r — runnable processes (waiting for CPU OR running). Если r > nproc — CPU перегружен.
- b — blocked processes (waiting for IO, D state). Если b > 0 регулярно — IO bottleneck.
memory:
- swpd — сколько в swap (KB).
- free — свободная RAM.
- buff — buffers (metadata IO).
- cache — page cache.
swap:
- si — swap in: страницы прочитаны из swap (kB/s). Любое значение > 0 = плохо.
- so — swap out: страницы записаны в swap. Активный swapping — сигнал нехватки RAM.
io:
- bi — blocks in: прочитано с диска (kB/s).
- bo — blocks out: записано (kB/s).
system:
- in — interrupts per second. Высокое значение — много IRQ от устройств.
- cs — context switches per second. Очень высокое (>10000) — много контекст-свитчинга, возможно много мелких процессов или избыток threads.
cpu — то же что в top: us, sy, id, wa, st.
Что искать в vmstat: типичные паттерны
vmstat -s: cumulative stats since boot
$ vmstat -s | head -20
32985856 K total memory
19234176 K used memory
654321 K active memory
8765432 K inactive memory
3145728 K free memory
124356 K buffer memory
9821456 K swap cache
8388604 K total swap
0 K used swap
8388604 K free swap
345678234 non-nice user cpu ticks
4567891 nice user cpu ticks
78912345 system cpu ticks
2345678901 idle cpu ticks
12345678 IO-wait cpu ticks
0 IRQ cpu ticks
234567 softirq cpu ticks
0 stolen cpu ticks
85648456 pages paged in
234567843 pages paged out
12345 pages swapped in
6789 pages swapped out
1234567890 interrupts
567890123 CPU context switches
1715856234 boot time
234567 forks
Это абсолютные счётчики с момента boot. Полезно для:
- Понимания total work за uptime.
- Расчёта rate: разность за период / время.
- Анализа
pages swapped in/out > 0— система когда-то свопила.
iostat — per-disk метрики
$ iostat -xz 2
Linux 6.5.0-21-generic (server) 05/18/2026 _x86_64_ (4 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
4.32 0.00 1.25 8.45 0.00 85.98
Device r/s w/s rkB/s wkB/s rrqm/s wrqm/s %rrqm %wrqm r_await w_await aqu-sz rareq-sz wareq-sz svctm %util
nvme0n1 12.45 45.67 1234.56 4567.89 0.45 2.34 3.5 4.9 0.45 1.23 0.06 99.13 100.04 0.34 3.21
sda 5.23 23.45 523.45 1234.56 0.12 1.45 2.2 5.8 8.45 25.67 0.65 100.12 52.65 1.23 35.67
Device r/s w/s rkB/s wkB/s ... %util
nvme0n1 15.34 89.12 ... 4.56
sda 8.23 45.67 ... 67.23
iostat -xz 2 — extended stats, skip zero-IO devices, каждые 2 сек.
Колонки:
- r/s, w/s — reads / writes per second (IOPS).
- rkB/s, wkB/s — read / write throughput (KB/s).
- rrqm/s, wrqm/s — merged ops per second (kernel объединяет close ops).
- %rrqm, %wrqm — доля merged.
- r_await, w_await — среднее latency request (миллисекунды). КРИТИЧНАЯ метрика.
- aqu-sz (average queue size) — сколько запросов в очереди.
- rareq-sz, wareq-sz — средний размер request (KB).
- svctm — сервис-время (deprecated, ненадёжно на современных Linux).
- %util — доля времени, когда устройство busy. 100% = диск перегружен.
Что важно в iostat
%util — доля времени, когда диск делает работу. 100% значит диск не успевает.
# Здоровый диск:
Device ... %util
nvme0n1 ... 3.21 <-- 3% utilization, есть запас
# Загруженный:
sda ... 80.45 <-- 80%, под нагрузкой, но справляется
# Перегруженный:
sdb ... 100.00 <-- queue растёт, latency растёт
%util на SSD/NVMe немного лжёт. Эти устройства поддерживают параллельные операции; util считается на основе времени с >=1 active request. Так что NVMe может быть 80% util и ещё иметь capacity. Лучше смотреть await + IOPS.
r_await / w_await — latency. Это среднее время от queue до completion:
- HDD: 5-15 ms норма для последовательных, 100+ для random.
- SSD: 0.1-1 ms норма, 5+ ms — что-то не так.
- NVMe: 0.05-0.5 ms норма, 2+ ms — проблема.
Если await >> typical — IO bottleneck.
aqu-sz (avg queue size) — сколько запросов ждут. Зависит от типа устройства:
- HDD: меньше 2 норма.
- SSD: меньше 8 норма.
- NVMe: меньше 32 норма.
Большая очередь = устройство не справляется или хорошо параллелится workload (для NVMe).
Найти “виновного” процесса: iotop
iostat показывает per-device. Чтобы найти какой ПРОЦЕСС жрёт IO — iotop:
$ sudo iotop -o # -o = только активные
Total DISK READ: 234.56 K/s | Total DISK WRITE: 12.34 M/s
Current DISK READ: 223.45 K/s | Current DISK WRITE: 11.23 M/s
TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND
1234 be/4 postgres 123.45 K/s 10.45 M/s 0.00 % 78.45 % postgres: writer
5678 be/4 root 45.67 K/s 1.23 M/s 0.00 % 12.34 % rsync /backup
9012 be/4 docker 67.89 K/s 543.21 K/s 0.00 % 2.45 % node app.js
В отличие от iostat (показывает диски), iotop показывает процессы. -o — только те, что делают IO. -P — агрегировать по процессу (а не threads).
Колонки:
- DISK READ/WRITE — скорости.
- IO> — процент времени, который процесс провёл в IO wait. Высокий = он часто блокирован.
sar — архивные метрики
sar (System Activity Reporter) — из пакета sysstat. По умолчанию собирает метрики каждые 10 минут, хранит в /var/log/sysstat/. Это бесценно для расследования: “вчера в 3:42 alert был, что происходило?”.
Активация (на Ubuntu):
sudo apt install sysstat
sudo sed -i 's/ENABLED="false"/ENABLED="true"/' /etc/default/sysstat
sudo systemctl restart sysstat
Использование:
# Сегодня CPU breakdown:
sar -u
# Конкретное время сегодня:
sar -u -s 03:30:00 -e 04:00:00
# Вчера:
sar -u -f /var/log/sysstat/sa$(date -d yesterday +%d)
# Память:
sar -r 1
# IO:
sar -b
# Per-device:
sar -d -p
# Network:
sar -n DEV 1
# Load average:
sar -q
Это значит, после инцидента в 3 утра вы утром можете сделать sar -u -s 02:30 -e 03:30 и увидеть точно, что было в момент проблемы.
Real example: расследование “ETL стал медленным после полуночи”
# 1. CPU breakdown в момент инцидента:
$ sar -u -s 00:00 -e 03:00
00:00:01 CPU %user %nice %system %iowait %steal %idle
00:10:01 all 12.34 0.00 3.45 65.78 0.00 18.43 <-- начало!
00:20:01 all 14.56 0.00 4.23 67.45 0.00 13.76
00:30:01 all 13.78 0.00 3.89 70.12 0.00 12.21
00:40:01 all 10.23 0.00 2.34 65.45 0.00 21.98
# 2. Какой диск отвечал:
$ sar -d -p -s 00:00 -e 03:00
00:00:01 DEV tps rkB/s wkB/s areq-sz aqu-sz await %util
00:10:01 nvme0 234 45.67 2345.67 12.34 8.45 35.67 89.23 <-- очередь 8, await 35ms
00:20:01 nvme0 245 23.45 2567.89 13.45 9.23 38.12 92.45
00:30:01 nvme0 256 34.56 2789.12 14.56 10.34 40.23 94.56
# Видим: nvme был под нагрузкой в это время, await 35-40 мс при норме 0.5 мс
# Что-то пишет 2.5 МБ/с уже долго
# 3. Сетевая активность для контекста:
$ sar -n DEV -s 00:00 -e 03:00 | grep eth0
# 4. Память:
$ sar -r -s 00:00 -e 03:00
# Часто после такого: понимание что backup job шёл в полночь, конкурент диска с ETL
free -h vs vmstat -s vs /proc/meminfo
Три способа смотреть память:
# Quick:
$ free -h
total used free shared buff/cache available
Mem: 31Gi 18Gi 2.7Gi 145Mi 10Gi 12Gi
Swap: 8.0Gi 0B 8.0Gi
# Snapshot detail:
$ vmstat -s | head -10
32985856 K total memory
19234176 K used memory
654321 K active memory <-- active LRU pages
8765432 K inactive memory <-- candidate for reclaim
3145728 K free memory
124356 K buffer memory
9821456 K swap cache
# Полные детали:
$ cat /proc/meminfo | head -30
MemTotal: 32985856 kB
MemFree: 3145728 kB
MemAvailable: 12345678 kB
Buffers: 124356 kB
Cached: 9821456 kB
SwapCached: 0 kB
Active: 654321 kB
Inactive: 8765432 kB
Active(anon): 345678 kB <-- private (heap, stack)
Inactive(anon): 98765 kB
Active(file): 308643 kB <-- file-backed (page cache)
Inactive(file): 8666667 kB
Unevictable: 0 kB
Mlocked: 0 kB
SwapTotal: 8388604 kB
SwapFree: 8388604 kB
Dirty: 5678 kB <-- dirty pages (need writeback)
Writeback: 0 kB <-- сейчас flushing на диск
AnonPages: 444443 kB
Mapped: 123456 kB
Shmem: 67890 kB
Slab: 567890 kB <-- kernel data structures
SReclaimable: 345678 kB
SUnreclaim: 222212 kB
KernelStack: 8192 kB
PageTables: 12345 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 24881532 kB
Committed_AS: 1234567 kB
/proc/meminfo — источник для всех остальных утилит.
Попробуй сам
# 1. vmstat 1 -- live observation:
vmstat 1
# Ctrl-C чтобы остановить, читать колонки
# 2. iostat расширенный:
iostat -xz 1
# или (новый формат):
iostat -xz -h 1
# 3. Сразу взглянуть и swap, и memory:
vmstat -s | head -25
# 4. Что в /proc/meminfo:
cat /proc/meminfo | head -20
# 5. Активность диска прямо сейчас:
sudo iotop -o # активные процессы
# 6. Если sysstat не стоит -- поставить:
sudo apt install sysstat
sudo systemctl enable --now sysstat
# Через 10 минут данные начнут собираться
# 7. Sar archive (если уже работает):
sar -u | head -10 # CPU за сегодня
sar -r | head -10 # memory
sar -d -p | head -20 # disks
# 8. Простой тест disk performance:
sudo hdparm -t /dev/sda # sequential read
# Или универсально:
dd if=/dev/zero of=/tmp/test bs=1M count=1024 conv=fdatasync
rm /tmp/test