Поиск узких мест производительности дисковой подсистемы Linux

HELP-ME-24.COM (Freelance Team), Черноусов Антон

Сегодня мы рассмотрим инструменты для поиска узких мест в работе дисковой подсистемы Linux.

Наверное многие системные администраторы сталкивались с падением отзывчивости системы при низкой нагрузке на процессор и невысоких показателях скорости записи и чтения с жесткого диска. Начинающих системных администраторов такое поведение сервера может поставить в тупик, так как они не владеют инструментами более глубокого анализа.

Полный мониторинг дисковой подсистемы Linux при помощи Zabbix

Дисковая подсистема является наверное самым распространенным  "горлышком" в котором происходит падение производительности системы в целом. Начинающие системные администраторы не совсем понимают механику работы дисковых накопителей и в большинстве случаев оперируют только текущей скоростью обмена данными с жестким диском и хотя это конечно важный параметр, но есть еще несколько не менее важных показателей.

Получение сведений о текущей нагрузке на дисковую подсистему

Утилита которой можно произвести базовую оценку текущей нагрузки на дисковую подсистему называется iostat и входит в пакет sysstat.

Для установки пакета в Cenots/Redhat используется команда:

# yum install sysstat.x86_64

Для установки в Ubuntu Linux и Debian:

# aptitude install sysstat

Запустив утилиту без параметров мы получим сокращенные сведения о текущем состоянии дисковой подсистемы:

# iostat
Linux 4.10.0-30-generic (DEV-101)       08.08.2017      _x86_64_        (4 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           5,66    0,02    1,85   21,28    0,00   71,20

Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
sda             123,44     19986,44     31263,41  200868469  314204812
sdb              32,72       458,13      6241,62    4604321   62729768
sdc               0,02         0,42         0,00       4232          0

Упрощенная запись нам мало интересна и мы будем работать с полным выводом статистики. Для получения всех сведений о текущем состоянии дисковой подсистемы добавьте к команде параметр -x:

# iostat -x
Linux 4.10.0-30-generic (DEV-101)       08.08.2017      _x86_64_        (4 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           5,64    0,02    1,85   21,46    0,00   71,03

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               3,05    27,92   76,91   48,83 20453,22 31606,18   828,09    52,58  418,07    5,01 1068,66   3,06  38,42
sdb               0,93    16,30   17,68   14,77   453,44  6176,51   408,66    19,61  604,43   24,36 1298,66   6,94  22,51
sdc               0,00     0,00    0,01    0,00     0,42     0,00    55,68     0,00    1,21    1,21    0,00   0,76   0,00

На моем сервере установлено три жестких диска sda/sdb/sdc. Утилита iostat предоставляет сведения о общей загрузке системы аналогичные выводу команды top или htop и статистику по текущей активности каждого из жестких дисков.

Схема работы жесткого диска

Показатели avg-cpu вам скорее всего знакомы, но на всякий случай пробежимся и по ним:

  • %user - Процент рабочего времени которое тратится на работу с приложениями пользователя (level application).
  • %nice - Процент времени которые потребляют приложения с искусственно измененным приоритетом.
  • %system - Аналогично вышеописанным параметрам, но отображает показатели системных процессов уровня ядра (ОС level kernel).
  • %iowait - Процент процессорного времени который тратится на ожидание дискового ввода-вывода (этот параметр крайне важен).
  • %steal - Параметр актуальный только в виртуализованных средах и описывает процент времени затраченный на ожидание гипервизора.
  • %idle - Время покоя когда система не загружена и не проводит операции ввода-вывода.

Эти параметры я уже неоднократно разбирал в предыдущих статьях и на них мы останавливаться сегодня не будем, а перейдем к более интересным параметрам напрямую относящимся к дисковой подсистеме.

Рассмотрим каждый параметр вывода статистики iostat -x подробно:

  • rrqm/s - число запросов на чтение за последнюю секунду (дисковая очередь чтения) после объединения в блоки (где avgrq-sz средний размер блока)
  • wrqm/s - число запросов на запись за последнюю секунду (дисковая очередь записи) после объединения в блоки (где avgrq-sz средний размер блока)
  • r/s - это собственно и есть пресловутый iops, а именно число запросов на запись которые запросили приложения в секунду. Эти запросы в дальнейшем объединяются в дисковую очередь rrqm/s.
  • w/s - аналогично r/s, но очередь на запись. Если значения  w/s и wrqm/s становятся примерно одинаковыми, то это означает, что система не может собрать запросы в очередь и идет интенсивная запись в разные сектора диска, что довольно характерно для виртуальных машин. Аналогичная ситуация для предыдущего пункта, в этом случае будет случайное-чтение.
  • rkB/s - текущая скорость чтения с устройства в kB/s
  • wkB/s - текущая скорость записи на устройство в kB/s
  • avgrq-sz - средний размер запросов в секторах, которые были отправлены на устройство.
  • avgqu-sz - средняя длина очереди к устройству (средняя по чтению и записи)
  • await - среднее время ожидания данных от устройства (в миллисекундах)
  • r_await - среднее время (в миллисекундах) для запросов на чтение, отправленных накопителю (общее время потраченное на обслуживание запросов).
  • w_await - аналогично предыдущему пункту, но в случае записи данных.
  • svctm - этот пункт будет удален в следующих версиях iostat и сейчас показывает погоду на Марсе (Warning! Do not trust this field any more. This field will be removed in a future sysstat version).
  • %util - Процент использования полосы пропускания для устройства, относительно корректные данные выдает на обычных HDD, для SSD не применим и для raid-накопителей так-же выдает не совсем корректные данные.

Могу поспорить, что с первого раза пробежавшись по параметрам стало не намного понятнее, но не беспокойтесь и в конце заметки я приведу реальные примеры и все встанет на свои места.

Постоянный мониторинг показателей нагрузки на дисковую подсистему при помощи Zabbix

Постоянно запускать утилиту iostat -x и интерпретировать результаты в числовом виде можно только в крайних случаях, когда разобраться с тормозами на сервере надо прямо здесь и сейчас. В повседневной работе разумнее настроить мониторинг при помощи zabbix и не допускать нештатных ситуаций оперативно реагируя на повышение нагрузки на дисковую подсистему.

Можно было бы самому написать скрипт интерпретирующий показатели iostat, но полноценные скрипты уже написаны и они были мной многократно апробированы. Можно пользоваться, результаты достоверные.

Как устанавливать zabbix-агент я уже рассказывал, но в случае использования Centos с включенным SeLinux у меня возникли некоторые проблемы в работе скриптов сбора данных и я немного повторюсь и пройдемся по установке Zabbix-агент в Centos 7.

Устанавливаем zabbix-агент:

# wget http://repo.zabbix.com/zabbix/3.2/rhel/7/x86_64/zabbix-agent-3.2.7-1.el7.x86_64.rpm
# chkconfig zabbix-agent on

Настраиваем работу zabbix в SeLinux:

# yum install policycoreutils-python
# cat /var/log/audit/audit.log | grep zabbix_agentd | \
grep denied | audit2allow -M zabbix_agent_setrlimit
# semodule -i zabbix_agent_setrlimit.pp
# systemctl start zabbix-agent

В дополнение к представленным выше правилам вам потребуется для работы сборщика статистики iostat дополнительно выполнить и эти команды:

# cat /var/log/audit/audit.log | grep "/tmp/iostat.out" | \
  grep denied | audit2allow -M zabbix_agent_file_setrlimit
# semodule -i zabbix_agent_file_setrlimit.pp

Завершив настройку агента, перейдем к настройке скриптов сбора данных iostat. Набор скриптов и шаблонов находится на GitHub по адресу: https://github.com/lesovsky/zabbix-extensions/tree/master/files/iostat. Особой сложности установка скриптов не составляет и вам потребуется разместить скрипты сбора статистики в соответствующих папках и подправить пути к скриптам в конфигурационном файле сборщика данных Zabbix.

На сервер потребуется загрузить шаблон iostat-disk-utilization-template.xml и добавить его к списку шаблонов сервера на котором развернуты соответствующие скрипты.

Обратите внимание, что сбор данных происходит в пассивном и активном режиме и параметр ServerActive агента должен быть сконфигурирован корректно. Вторая не менее важная деталь которая не оговаривается в документации, это то, что необходимо установить параметр Timeout на сервере и клиенте в 30 секунд.

Для проверки работы io-сборщиков, мы можем выполнить на сервере запрос при помощи  zabbix_get:

# zabbix_get -s 172.16.0.107 -k iostat.discovery

Если он выдает что то наподобие:

{
        "data":[
                {
                        "{#HARDDISK}":"vda"},
                {
                        "{#HARDDISK}":"scd0"}]}

Значит данные скоро начнут поступать, но я еще дополнительно рекомендую проверить еще один параметр:

# zabbix_get -s 172.16.0.107 -k "iostat.collect"

И если он выдает ошибку:

/etc/zabbix/scripts/iostat-collect.sh: line 13: /tmp/iostat.out: Permission denied

Это означает, что вы не корректно сконфигурировали SeLinux (описано в начале статьи).

Так как в процессе обсуждения статьи все же возникли некоторые вопросы, я подробно рассмотрю установку zabbix-агента и настройку мониторинга нагрузки на дисковую подсистему в Ubuntu Linux.

Настройка Zabbix-агента для сбора статистики нагрузки на дисковую подсистему в Ubuntu Linux

Начнем как обычно с установки необходимых для работы пакетов:

# aptitude install sysstat zabbix-agent git

В типовой конфигурационный файл необходимо внести следующие изменения:

Server=127.0.0.1,172.16.3.58
ServerActive=172.16.3.58
Hostname=dev105
Timeout=30

Параметр server мы настраиваем на два ip-адреса и таким образом разрешаем запрос данных zabbix-сервером и запрос с локального адреса для тестирования настроек. ServerActive должен быть обязательно настроен на адрес zabbix-сервера который будет принимать данные от агента в активном режиме.

Zabbix-сервер в свою очередь принимает данные в активном режиме только в случае совпадения имени хоста Hostname с указанным в разделе Host name настройки web-интерфейса Zabbix.

Добавление Zabbix-агента в web-интерфейс Zabbix-server

В разделе Visible name можно указывать любое имя и это имя будет фигурировать в отчетах и оповещениях и я рекомендую делать его максимально информативным.

Параметр TimeOut должен быть установлен в 30 секунд на агенте и сервере. Это связано со спецификой работы скрипта сбора статистики по операциям ввода-вывода.

Следующим этапом переходим к настройке сборщиков текущих показателей нагрузки на дисковую подсистему для чего нам понадобятся скрипты из репозитория о котором мы говорили выше. В этом репозитории довольно много скриптов для мониторинга нестандартных параметров, но на сейчас интересует только iostat:

# git clone https://github.com/help-me-project/zabbix-extensions.git

Из репозитория копируем конфигурационный файл и скрипты:

# cp ./zabbix-extensions/files/iostat/iostat.conf /etc/zabbix/zabbix_agentd.conf.d/
# mkdir -p /usr/libexec/zabbix-extensions/scripts/
# rsync -vr ./zabbix-extensions/files/iostat/scripts/ /usr/libexec/zabbix-extensions/scripts/
# chown zabbix -R /usr/libexec/zabbix-extensions/scripts/
# chmod +x /usr/libexec/zabbix-extensions/scripts/*.s

По завершении настройки перезапускаем zabbix-агент при помощи команды:

# service zabbix-agent restart

Теперь сборщик должен работать корректно и вам необходимо лишь импортировать шаблон сборщика данных на zabbix-сервер и добавить шаблон к нашему хосту.

Добавляем шаблон мониторинга в Zabbix

Через некоторое время данные начнут поступать, но если со сбором данных возникли проблемы, то вы можете проверить работу скриптов при помощи команды zabbix_get в ручном режиме.

Примеры мониторинга нагрузки на дисковую подсистему

Как я и обещал сейчас мы рассмотрим несколько графиков нагрузки на дисковую подсистему, чтобы стали понятны описания параметров из начала статьи.

Шаблон iostat-disk-utilization-template.xml содержит несколько пред настроенных графиков и эти графики будут доступны для каждого накопителя в системе:

  • Disk await
  • Disk merges
  • Disk queue
  • Disk read and write
  • Disk utilization

Рассмотрим типовые примеры нагрузки на дисковую подсистему и начнем с линейной записи реализуемой простой командой:

# dd bs=1024 count=102400000 if=/dev/zero of=/opt/images/test-image.img

При линейной записи получается файл размером 100 гб заполненный нулями (100 гб мы выбрали чтобы минимизировать влияние кэша операционной системы). Для тестирования я использовал дисковый накопитель WDC WD2000FYYZ-01UL1B1 подключенный в SATA 3.0, 6.0 Gb/s (current: 3.0 Gb/s).

Средняя скорость записи составила 144 MB/s:

# dd bs=1024 count=102400000 if=/dev/zero of=/opt/images/test-image.img
102400000+0 записей получено
102400000+0 записей отправлено
104857600000 байт (105 GB, 98 GiB) скопирован, 730,132 s, 144 MB/s

Пройдемся по графикам которые мы получили за время линейной записи:

Disk await

Ожидание дискофой подсистемы при линейной записи

Disk merges

Слияние дисковой очереди

Disk queue

Дисковая очередь при линейной записи

Disk read and write

Грфик скорости диска WD Black при записи данных

Disk utilization

Процент загруженности дисковой подсистемы при интенсивной записи на диск

Логично, что следующим этапом мы произведем линейное чтение созданного файла при помощи команды:

# dd bs=1024 count=102400000 if=/opt/images/test-image.img of=/dev/null

Средняя скорость чтения этого же файла составила 146 MB/s:

# dd bs=1024 count=102400000 if=/opt/images/test-image.img of=/dev/null
102400000+0 записей получено
102400000+0 записей отправлено
104857600000 байт (105 GB, 98 GiB) скопирован, 718,247 s, 146 MB/s

Disk await

Время ожидания при линейном чтении с диска

Disk merges

Объединения дисковой очереди при посекторном чтении

Disk queue

Дисковая очередь при линейном чтении

Disk read and write

Средняя скорость линейного чтения с HDD WD Black

Disk utilization

Утилизация дисковой подсистемы при линейном чтении

Представленные выше примеры линейных чтения и записи из вымышленного мира где пони и бабочки и предназначены для понимания основных показателей (на граффиках статистики zabbix), а в реальном мире все намнного сложнее и сейчас мы перейдем к рассмотрению ситуаций более приближенных к боевым.

Предпоследним этапом, мы протестируем одновременные линейные чтение и запись, что уже ближе к реальной ситуации. Для реализации такого сценария мы запустим две команды из первого и второго примера одновременно в двух потоках.

# dd bs=1024 count=102400000 if=/opt/images/test-image.img of=/dev/null &
# dd bs=1024 count=102400000 if=/dev/zero of=/opt/images/test-image-1.img &

Операция записи:

# dd bs=1024 count=102400000 if=/dev/zero of=/opt/images/test-image-1.img
102400000+0 записей получено
102400000+0 записей отправлено
104857600000 байт (105 GB, 98 GiB) скопирован, 1479,16 s, 70,9 MB/s

Операция чтения:

# dd bs=1024 count=102400000 if=/opt/images/test-image.img of=/dev/null
102400000+0 записей получено
102400000+0 записей отправлено
104857600000 байт (105 GB, 98 GiB) скопирован, 848,007 s, 124 MB/s

Чтение завершилось за 14 минут, а запись продолжалась еще 12 минут, что явно видно на графиках, но общая длительность операции суммарно равна длительности двух предыдущих экспериментов.

Disk await

Тест производительности дисковой подсистемы на операциях одновременной чтения-записи

Disk merges

Поведение дисковой очереди на операциях одновременной чтения-записи

Disk queue

Длина дисковой очереди при одновременной чтеии-записи

Disk read and write

Конкурентные чтение-запись

Disk utilization

Загрузка диска в процентах на одновременной чтении записи

Но на практике чаще всего встречается случайный доступ на чтение и запись в несколько потоков и мы будем эмулировать его при помощи утилиты fio и этой утилитой мы уже работали в статье "Тестирование производительности жестких дисков и програмных raid-массивов в linux".

Мы будем использовать следующий конфигурационный файл для случайного чтения-записи:

[readtest-01]
blocksize=48k
filename=/opt/images/tmp/1.dat
rw=randread
direct=1
buffered=0
ioengine=libaio
iodepth=3
size=4096m

[writetest-01]
blocksize=48k
filename=/opt/images/tmp/2.dat
rw=randwrite
direct=1
buffered=0
ioengine=libaio
iodepth=3
size=4096m
[readtest-02]
blocksize=48k
filename=/opt/images/tmp/3.dat
rw=randread
direct=1
buffered=0
ioengine=libaio
iodepth=3
size=4096m

[writetest-02]
blocksize=48k
filename=/opt/images/tmp/4.dat
rw=randwrite
direct=1
buffered=0
ioengine=libaio
iodepth=3
size=4096m

Утилита fio по завершении своей работы предоставляет отличный отчет:

Run status group 0 (all jobs):
READ: io=8191.1MB, aggrb=9332KB/s, minb=4666KB/s, maxb=4674KB/s, mint=897332msec, maxt=898840msec
WRITE: io=8191.1MB, aggrb=7565KB/s, minb=3782KB/s, maxb=3786KB/s, mint=1107641msec, maxt=1108760msec
Disk stats (read/write):
sda: ios=174761/176529, merge=5/29665, ticks=5380108/31362408, in_queue=40289408, util=100.00%

Но нас интересует именно динамика нагрузки на дисковую подсистему собранная zabbix и мы вновь возвращаемся к графикам которые нам подготовила система мониторинга.

Disk await

Время ожидания писковой подсистемы при случайных операциях чтения-записи

Disk merges

Объединение дисковой очереди на рандомном чтении записи

Disk queue

Длина дисковой очереди при случайных операциях чтения-записи

Disk read and write

Скорости чтения - записи при рандомном доступе

Disk utilization

Общая утилизация дисковой подсистемы при random-access

Продолжение следует...

Оставьте комментарий

Вы должны быть вошедший в чтобы отправить комментарий