Утилита fio
Об утилите
Утилита fio позволяет выполнять нагрузочное тестирование дисковой подсистемы. Для этого она создаёт потоки или процессы, которые в свою очередь нагружают дисковую подсистему операциями ввода/вывода.
Так как эта утилита не предустановлена в систему, её нужно вначале установить. В Ubuntu 22.04 и в Debian 11 вы можете установить эту утилиту из стандартных репозиториев:
$ sudo apt install fio
Типичное использование fio выглядит следующем образом:
$ sudo fio <файл задания>
Файл задания — это описание теста, который утилита должна выполнить.
Получается, для того чтобы изучить работу fio, нужно научиться писать файлы заданий и читать отчеты о проделанных тестах.
Если хотите погрузиться в изучение этой утилиты, то можете почитать документацию здесь . Я же опишу несколько простых тестов и покажу как читать некоторую информацию из полученных отчетов.
Терминология
Прежде чем мы начнём работать с этой утилитой, нужно познакомиться с некоторыми терминами, которые связаны с дисковой подсистемой:
- Когда приложение работает с данными, то оно читает или записывает эти данные блоками, в итоге операция ввода/вывода — это чтение или запись одного такого блока.
- Однако, приложение может читать или писать блоки разного размера, поэтому размер блока — это тоже важный параметр.
- Пропускная способность дисковой подсистемы измеряется в двух величинах:
- B/s — количество байт в секунду, или производные (KB/s, MB/s);
- IOPS — количество операций ввода/вывода в секунду.
- Латентность — это время выполнения одной операции ввода/вывода. Причем, утилита fio определяет 3 разных показателя латентности:
- slat — время необходимое на отправку запроса;
- clat — временной промежуток после отправки запроса и до полной его обработки;
- lat — время между тем как запрос был создан и до завершения его обработки.
- Так как операции ввода/ввода вывода обрабатываются очень быстро, то расчет латентности ведется в usec (микросекундах), или в msec (миллисекундах).
- Глубина очереди (iodepth). Когда система работает с диском, то одни запросы обрабатываются, а другие ждут в очереди. Грубо говоря, если iodepth=10, значит запрос находился в очереди в 10 раз дольше чем обрабатывался. А если быть точным то iodepth равняется сумме нахождения в очереди и обработке, делённой на время обработки. Если iodepth = 32, значит запрос находился в очереди 31 условную единицу времени а обрабатывался 1 условную единицу времени.
Примеры различных файлов заданий
Случайное чтение с диска:
$ nano randread.cfg
[readtest] # называние теста (таких тестов в одном файле может быть несколько)
blocksize=4k # чтение блоками по 4KB
filename=/dev/sda2 # будем читать раздел sda2
rw=randread # метод теста - случайное чтение
direct=1 # без буфера
buffered=0 # без кэша
ioengine=libaio # движок libaio (собственный асинхронный ввод/вывод Linux)
iodepth=32 # тест должен добиться этой глубины очереди
Здесь, по желанию, вы можете изменить: размер блока (blocksize) и читаемый файл (filename). В качестве filename можно указать блочное устройство или обычный файл, но предварительно нужно этот файл создать.
Случайная запись в файл:
$ nano randwrite.cfg
[writetest]
size=1G
blocksize=4k
filename=/tmp/test1
rw=randwrite # метод теста - случайная запись
direct=1
buffered=0
ioengine=libaio
iodepth=32
В этом примере, по желанию, вы также можете изменить: размер блока (blocksize) и записываемый файл (filename).
Внимание! Когда выполняется тестирование на запись, то в указанный файл (filename) пишутся данные перезатирая его. Поэтому не указывается в качестве filename блочное устройство с нужными данными.
Выполняем тест случайного чтения
Запуск теса:
$ sudo fio randread.cfg
Результат тестирования:
readtest: (g=0): rw=randread, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=libaio, iodepth=32
fio-3.28
Starting 1 process
Jobs: 1 (f=1): [r(1)][100.0%][r=162MiB/s][r=41.5k IOPS][eta 00m:00s]
readtest: (groupid=0, jobs=1): err= 0: pid=39490: Thu Oct 20 13:26:00 2022
read: IOPS=42.5k, BW=166MiB/s (174MB/s)(16.0GiB/98740msec)
slat (usec): min=4, max=7475, avg=16.52, stdev=13.18
clat (usec): min=32, max=30637, avg=733.38, stdev=262.41
lat (usec): min=48, max=30674, avg=750.70, stdev=264.66
clat percentiles (usec):
| 1.00th=[ 363], 5.00th=[ 461], 10.00th=[ 506], 20.00th=[ 562],
| 30.00th=[ 611], 40.00th=[ 660], 50.00th=[ 709], 60.00th=[ 758],
| 70.00th=[ 816], 80.00th=[ 889], 90.00th=[ 988], 95.00th=[ 1057],
| 99.00th=[ 1270], 99.50th=[ 1401], 99.90th=[ 3064], 99.95th=[ 4228],
| 99.99th=[ 6063]
bw ( KiB/s): min=113736, max=203504, per=100.00%, avg=170097.57, stdev=16561.25, samples=197
iops : min=28434, max=50876, avg=42524.39, stdev=4140.29, samples=197
lat (usec) : 50=0.01%, 100=0.03%, 250=0.16%, 500=9.04%, 750=49.04%
lat (usec) : 1000=32.94%
lat (msec) : 2=8.56%, 4=0.17%, 10=0.05%, 20=0.01%, 50=0.01%
cpu : usr=29.34%, sys=69.67%, ctx=7672, majf=0, minf=45
IO depths : 1=0.1%, 2=0.1%, 4=0.1%, 8=0.1%, 16=0.1%, 32=100.0%, >=64=0.0%
submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.1%, 64=0.0%, >=64=0.0%
issued rwts: total=4193536,0,0,0 short=0,0,0,0 dropped=0,0,0,0
latency : target=0, window=0, percentile=100.00%, depth=32
Run status group 0 (all jobs):
READ: bw=166MiB/s (174MB/s), 166MiB/s-166MiB/s (174MB/s-174MB/s), io=16.0GiB (17.2GB), run=98740-98740msec
Disk stats (read/write):
sda: ios=4190107/168, merge=211/117, ticks=771178/93, in_queue=771317, util=100.00%
Разбор отчета по случайному чтению
Первые 4 строки показывают информацию о самом тесте:
readtest: (g=0): rw=randread, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=libaio, iodepth=32
fio-3.28
Starting 1 process
Jobs: 1 (f=1): [r(1)][100.0%][r=162MiB/s][r=41.5k IOPS][eta 00m:00s]
Здесь же видим полученную пропускную способность — [r=162MiB/s][r=41.5k IOPS].
Дальше видим более подробную информацию о пройденном тесте:
readtest: (groupid=0, jobs=1): err= 0: pid=39490: Thu Oct 20 13:26:00 2022
read: IOPS=42.5k, BW=166MiB/s (174MB/s)(16.0GiB/98740msec)
slat (usec): min=4, max=7475, avg=16.52, stdev=13.18
clat (usec): min=32, max=30637, avg=733.38, stdev=262.41
lat (usec): min=48, max=30674, avg=750.70, stdev=264.66
clat percentiles (usec):
| 1.00th=[ 363], 5.00th=[ 461], 10.00th=[ 506], 20.00th=[ 562],
| 30.00th=[ 611], 40.00th=[ 660], 50.00th=[ 709], 60.00th=[ 758],
| 70.00th=[ 816], 80.00th=[ 889], 90.00th=[ 988], 95.00th=[ 1057],
| 99.00th=[ 1270], 99.50th=[ 1401], 99.90th=[ 3064], 99.95th=[ 4228],
| 99.99th=[ 6063]
bw ( KiB/s): min=113736, max=203504, per=100.00%, avg=170097.57, stdev=16561.25, samples=197
iops : min=28434, max=50876, avg=42524.39, stdev=4140.29, samples=197
lat (usec) : 50=0.01%, 100=0.03%, 250=0.16%, 500=9.04%, 750=49.04%
lat (usec) : 1000=32.94%
lat (msec) : 2=8.56%, 4=0.17%, 10=0.05%, 20=0.01%, 50=0.01%
cpu : usr=29.34%, sys=69.67%, ctx=7672, majf=0, minf=45
IO depths : 1=0.1%, 2=0.1%, 4=0.1%, 8=0.1%, 16=0.1%, 32=100.0%, >=64=0.0%
submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.1%, 64=0.0%, >=64=0.0%
issued rwts: total=4193536,0,0,0 short=0,0,0,0 dropped=0,0,0,0
latency : target=0, window=0, percentile=100.00%, depth=32
Описывать всё не буду, но некоторые вещи объясню. Здесь показана достигнутая пропускная способность — IOPS=42.5k, BW=166MiB/s, сколько всего было считано с диска и сколько времени на это ушло — (16.0GiB/98740msec).
Также видим минимальную и максимальную латентность: lat (usec): min=48, max=30674.
И есть информация, как изменялся clat по
процентилям
(clat percentiles (usec)):
- если взять 1% самых быстрых запросов, то самый медленный из них выполнялся 363 usec —
1.00th=[ 363]; - если взять 20% самых быстрых запросов, то самый медленный из них выполнялся 562 usec —
20.00th=[ 562]и так далее.
Дальше идёт статистика пропускной способности. Здесь видна минимальная, максимальная и средняя пропускная способность в KiB/s и iops. (bw ( KiB/s): min=113736, max=203504) и (iops : min=28434, max=50876).
А ниже представлена статистика по латентности (lat):
- число запросов, которые выполнялись 50 usec, было 0,01 % (
50=0.01%); - число запросов, которые выполнялись 750 usec, было 49,04% (
750=49.04%) и так далее.
А ещё ниже показана статистика по использованию ЦПУ:
- usr — пользовательские процессы;
- sys — системные процессы;
- ctx — количество переключения контекста через которые прошел этот поток;
- majf — количество major page faults. Такие ошибки могут быть устранены только путем доступа к диску;
- minf — количество minor page fault. Такие ошибки могут быть устранены с помощью страниц, которые уже находятся в памяти.
Выполняем тест случайной записи
Чтобы не затереть свой диск, писать будем в файл. А чтобы было интереснее, в одном файле задания, я опишу сразу два теста: случайную запись блоками 4K и 4M:
$ nano randwrite.cfg
[writetest-4K]
size=1G
blocksize=4k
filename=/tmp/test1
rw=randwrite
direct=1
buffered=0
ioengine=libaio
iodepth=32
[writetest-4M]
size=1G
blocksize=4M
filename=/tmp/test2
rw=randwrite
direct=1
buffered=0
ioengine=libaio
iodepth=32
Запускаем тестирование:
$ sudo fio randwrite.cfg
Разбор отчета по случайной записи блоками 4К
writetest-4K: (groupid=0, jobs=1): err= 0: pid=42936: Sat Oct 22 14:17:41 2022
write: IOPS=13.3k, BW=52.0MiB/s (54.5MB/s)(1024MiB/19696msec); 0 zone resets
slat (usec): min=12, max=27704, avg=47.01, stdev=100.91
clat (usec): min=2, max=115525, avg=2352.97, stdev=3452.47
lat (usec): min=70, max=115567, avg=2400.94, stdev=3455.61
clat percentiles (usec):
| 1.00th=[ 97], 5.00th=[ 322], 10.00th=[ 1074], 20.00th=[ 1418],
| 30.00th=[ 1500], 40.00th=[ 1582], 50.00th=[ 1663], 60.00th=[ 1762],
| 70.00th=[ 1909], 80.00th=[ 2409], 90.00th=[ 4752], 95.00th=[ 6521],
| 99.00th=[ 9372], 99.50th=[ 11076], 99.90th=[ 65799], 99.95th=[ 81265],
| 99.99th=[104334]
bw ( KiB/s): min= 1548, max=81288, per=50.25%, avg=53508.18, stdev=22017.15, samples=39
iops : min= 387, max=20322, avg=13376.90, stdev=5504.33, samples=39
lat (usec) : 4=0.01%, 50=0.01%, 100=1.07%, 250=2.89%, 500=2.50%
lat (usec) : 750=1.39%, 1000=1.45%
lat (msec) : 2=63.60%, 4=14.35%, 10=12.01%, 20=0.44%, 50=0.17%
lat (msec) : 100=0.10%, 250=0.02%
cpu : usr=7.34%, sys=48.00%, ctx=197078, majf=0, minf=14
IO depths : 1=0.1%, 2=0.1%, 4=0.1%, 8=0.1%, 16=0.1%, 32=100.0%, >=64=0.0%
submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.1%, 64=0.0%, >=64=0.0%
issued rwts: total=0,262144,0,0 short=0,0,0,0 dropped=0,0,0,0
latency : target=0, window=0, percentile=100.00%, depth=32
Здесь мы достигли скорость = IOPS=13.3k, BW=52.0MiB/s.
Латентность min=70 usec, max=115567 usec. И больше всего времени (63.60%) латентность была — 2 msec.
Разбор отчета по случайной записи блоками 4M
writetest-4M: (groupid=0, jobs=1): err= 0: pid=42937: Sat Oct 22 14:17:41 2022
write: IOPS=339, BW=1358MiB/s (1424MB/s)(1024MiB/754msec); 0 zone resets
slat (usec): min=172, max=10518, avg=544.27, stdev=871.18
clat (msec): min=14, max=181, avg=92.03, stdev=33.74
lat (msec): min=22, max=181, avg=92.58, stdev=33.58
clat percentiles (msec):
| 1.00th=[ 25], 5.00th=[ 28], 10.00th=[ 32], 20.00th=[ 67],
| 30.00th=[ 84], 40.00th=[ 91], 50.00th=[ 97], 60.00th=[ 103],
| 70.00th=[ 110], 80.00th=[ 115], 90.00th=[ 126], 95.00th=[ 142],
| 99.00th=[ 182], 99.50th=[ 182], 99.90th=[ 182], 99.95th=[ 182],
| 99.99th=[ 182]
bw ( MiB/s): min= 1333, max= 1333, per=100.00%, avg=1333.33, stdev= 0.00, samples=1
iops : min= 333, max= 333, avg=333.00, stdev= 0.00, samples=1
lat (msec) : 20=0.39%, 50=14.45%, 100=40.62%, 250=44.53%
cpu : usr=5.31%, sys=13.28%, ctx=229, majf=0, minf=10
IO depths : 1=0.4%, 2=0.8%, 4=1.6%, 8=3.1%, 16=6.2%, 32=87.9%, >=64=0.0%
submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
complete : 0=0.0%, 4=99.6%, 8=0.0%, 16=0.0%, 32=0.4%, 64=0.0%, >=64=0.0%
issued rwts: total=0,256,0,0 short=0,0,0,0 dropped=0,0,0,0
latency : target=0, window=0, percentile=100.00%, depth=32
Здесь мы достигли скорость = IOPS=339, BW=1358MiB/s.
Латентность min=22 msec, max=181 msec. И больше всего времени латентность была: 44.53 % — 250 msec, и 40.62% — 100 msec.
Если понравилась статья, подпишись на мой канал в VK или Telegram .