Skip to content

Latest commit

 

History

History
106 lines (75 loc) · 8.74 KB

File metadata and controls

106 lines (75 loc) · 8.74 KB

Отладка блочного ввода-вывода Linux

Источник: Linux Block I/O debugging

14 октября 2023

Случайно я наткнулся на блог и видео Танеля Педера (Tanel Poder). Материалы превосходные, если вы хотите заняться низкоуровневой отладкой ввода-вывода в Linux — особенно рекомендую следующий пост в блоге с соответствующим видео:

Вдохновлённый детальностью его анализа, я сам на какое-то время окунулся в изучение блочного ввода-вывода Linux. В этом посте я собираю полезные сведения и инструменты для отладки хранилищ в Linux — в основном как записную книжку для себя. Возможно, это будет полезно и вам.

Инструменты

bcc

В BPF Compiler Collection входит огромный набор инструментов для перехвата и наблюдения за различными точками взаимодействия userspace и ядра. Неважно, хотите ли вы отлаживать TCP-соединения, управление памятью или блочный ввода-вывод — здесь вы что-нибудь найдёте. Коллекция доступна в большинстве дистрибутивов как bcc-tools, однако скрипты часто не находятся в $PATH, и их нужно вызывать вручную из /usr/share/bcc/tools/. Все инструменты используют небольшие BPF-программы, которые загружаются в ядро, чтобы отслеживать (probe) функцию или событие и собирать о них информацию. Если вам интересно, как это делается, посмотрите классный учебник bcc для Python-разработчиков.

mlc от Intel: Memory Latency Checker

Memory Latency Checker полезен для проверки пропускной способности и задержек на пути от CPU к RAM. Особенно в NUMA-системах это может представлять большой интерес для поиска узких мест, поскольку пропускная способность CPU может быть ограничена, если задержка доступа к памяти слишком высока. См. также numactl и lstopo.

lstopo

Что касается физического расположения компонентов машины, есть инструменты вроде lshw или lspci, которые дают хорошую информацию. Кроме того, команда lstopo --of ascii из пакета hwloc может нарисовать в терминале картину топологии оборудования.

0x.tools

Инструменты на 0x.tools интересны для отладки приложений в Linux. Пока я нечасто ими пользовался, но там есть хорошие примеры того, как с помощью perf получить визуализацию в виде дерева, показывающую, в каких местах кода ядра CPU проводит больше всего времени.

perf record -g -F 2 -a -o perf_log
perf report -i perf_log

dstat

dstat — преемник известных инструментов вроде vmstat, iostat и ifstat. Он стремится унифицировать интерфейс, упростить использование и добавить больше информации. Полное руководство см. на https://linux.die.net/man/1/dstat. Для отладки хранилища я часто использую dstat -pcmrd, чтобы видеть IOPS и пропускную способность, вот так:

[root@test /tmp]# dstat -pcmrd
---procs--- ----total-usage---- ------memory-usage----- --io/total- -dsk/total-
run blk new|usr sys idl wai stl| used  free  buf   cach| read  writ| read  writ
1.0   0    |                   | 594M  257M 2172k 2670M|           |
1.0   0   0|  1  55  42   0   0| 594M  185M 2172k 2742M|   0   184 |   0   120M
1.0   0   0|  1  57  41   0   0| 590M  131M 2172k 2801M|   0   175 |   0   164M
1.0   0   0|  1  57  41   0   0| 587M  121M 2172k 2812M|1.00   195 |4096B  164M
1.0   0 3.0|  1  57  40   0   0| 584M  111M 2172k 2826M|1.00   234 |4095B  160M
1.0   0   0|  3  57  41   0   0| 582M  104M 2172k 2836M|   0   222 |   0   148M
1.0   0   0|  0  62  30   6   0| 578M  109M 2172k 2835M|   0   460 |   0   365M

Здесь видно, что один процесс выполняет довольно большой объём операций записи (IOPS), который занимает более половины CPU в коде ядра.

Типичные проблемы

Ядро разбивает операции ввода-вывода

Хотя приложение отправляет ядру операции ввода-вывода с определённым размером блока, эти операции могут быть разбиты блочным слоем (block layer) ещё до того, как попадут на сами диски. Я до сих пор не знаю точно, когда именно это происходит, но предполагаю, что это делается для выравнивания операций с физическими размерами блоков. В любом случае это может изменить результаты вашего теста, особенно если вы измеряете пропускную способность или IOPS при разных размерах блоков.

Хороший способ проанализировать это — инструмент bitesize из BCC.

[root@test]# ./bitesize
Tracing block I/O... Hit Ctrl-C to end. ^C
Process Name = dd
     Kbytes              : count     distribution
         0 -> 1          : 0        |                                        |
         2 -> 3          : 0        |                                        |
         4 -> 7          : 1000     |*****                                   |
         8 -> 15         : 0        |                                        |
        16 -> 31         : 0        |                                        |
        32 -> 63         : 0        |                                        |
        64 -> 127        : 1000     |*****                                   |
       128 -> 255        : 0        |                                        |
       256 -> 511        : 3000     |*****************                       |
       512 -> 1023       : 3000     |*****************                       |
      1024 -> 2047       : 7000     |****************************************|

Другой метод — протестировать с заданным размером блока и проверить количество выполненных IOPS. Это, конечно, сложнее на загруженных системах. Следующий скрипт перебирает разные размеры блоков и отображает IOPS с помощью dstat:

#/bin/bash

trap "echo exiting...; exit" SIGINT

IOSIZES=${1:-512 1024 2048 4k i8k 16k 32k 64k 512k 1M 4M}

for i in ${IOSIZES}; do
        echo "testing with blocksize of $i"
        echo "-----------------------------"
        dd oflag=direct if=/dev/urandom of=/test.img bs=$i &
        timeout 5 dstat -pcmrd
        killall -9 dd
        echo
done

linux kernel ebpf