Мониторинг производительности дисковой подсистемы при помощи zabbix и block stat

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

    Сегодня хочу поделиться с сообществом своим текущим опытом на реальном примере zabbix и его связке с block stat.



    Небольшое отступление


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

    Да есть куча утилит, которая позволит протестировать диски, например тот же fio. Но ничто не сравнится с тестированием реальной нагрузкой.

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

    Когда то давным-давно для этих целей использовал iostat, лютый парсер к нему и gnuplot, и даже написал статейку habr.com/post/165855. Скажу я вам – это жутко неудобно.

    Куда как удобнее натравить на систему zabbix и мониторить. А к zabbix можно прикрутить модную Grafana и мониторить красиво. Сразу скажу – выбор zabbix скорее исторический: «потому что он уже был».

    Мониторинг дисков в zabbix


    Справедливости ради скажу, что в zabbix уже есть встроенные ключи vfs.dev.*, но увы очень мало: скорость чтения и записи, объем.

    А что нужно нам?

    Практика показывает что ключевые метрики по которым можно оценивать дисковую подсистему это:

    • Количество операций в секунду (ops)
    • Пропускная способность (throughput)
    • Время обработки запроса (latency или правильней svctime)
    • Утилизация дисковой подсистемы (utilization)

    Так как эти метрики очень зависят друг от друга, то не зная все нельзя сделать правильные выводы.

    Все эти метрики есть в iostat. Но как их положить в zabbix?

    Легкое гугление приводит нас к различным парсерам iostat, в том числе и здесь.

    Но мне по душе другой вариант, а именно парсинг вывода /sys/class/block/*/stat

    Плюсы метода:

    • это первоисточник данных — iostat так же использует эти данные
    • для разбора показателей можно ограничиться только однострочником в UserParameter без дополнительных скриптов.

    Но есть и недостатки:

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

    Итак, кроме самого zabbix и zabbix-agent на наблюдаемой машине нам потребуется awk. Мы используем дистрибутив CentOS 7.4 и zabbix 3.4

    Данные в zabbix мы будем собирать при помощи zabbix-agent, создав пользовательские ключи. Для этого в /etc/zabbix/zabbix_agentd.d нужно создать файлик userparameter_custom.vfs.conf примерно со следующим содержимым:

    UserParameter=custom.vfs.dev.io.ms[*],cat /sys/class/block/$1/stat | awk '{print $$10}'

    Тут все просто — создаем пользовательский ключ custom.vfs.dev.io.ms, в качестве параметра передаем туда имя блочного устройства, значением параметра будет 10 колонка файлика stat.

    В этом файлике статистики всего 11 колонок, посмотреть их описание можно вот тут.

    Колонка №10 это io_tics — количество миллисекунд затраченным устройством на ввод вывод. Как почти все параметры — эта цифра является аккумулятором и постоянно возрастает. Как же получить из них привычные метрики.

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


    Эта метрика аналогична значению поля utils команды iostat -x. Характеризует загрузку дисковой подсистемы. По сути это сколько процентов реального времени система затратила на операции ввода-вывода за интервал между опросами. Как правило при приближении к 100% система начинает все больше простаивать в ожидании когда диски обработают ваши запросы.

    Чтобы получить эту цифру — надо взять значение 10 колонки файла статистики и запомнить его в zabbix как скорость изменения в секунду, не забыв умножить на 0.1 так как значение в статистике в миллисекундах, а нам нужны проценты.





    Аналогичным образом можно посчитать нагрузку записью/чтением (колонки write_ticks / read_ticks).

    Время обработки запроса


    Эта метрика аналогична r_svctime и w_svctime для записи и чтения соответственно. По сути это усредненное время обработки запросов за интервал между опросами.

    Данная метрика чуть посложнее. Рассмотрим на примере запросов на запись.

    Для этого нам понадобится создать три ключа:

    • write utils — количество времени потраченное на запись — колонка №8 write_ticks сохраненная, как скорость изменения в секунду между опросами. По сути значение ключа в zabbix будет утилизация записью.


    • write ops — количество запросов на запись — колонка №5 write I/Os. Так же сохраняем как скорость
    • svctime или latency — искомый параметр. Создаем как вычисляемое значение: последнее значение write utils / последнее значение write ops. Плюс еще поделить на 1000 чтобы в секунды перейти

    Абсолютно также считается время обработки запросов на чтение, только используя колонки №1 read I/Os и №4 read_ticks.

    Пропускная способность


    Метрика показывающая с какой скоростью данные были записаны или прочитаны

    Для этой метрики используются колонки №3 read sectors и №5 write sectors. Значение сколько было прочитано или записано «секторов». Точно так же в zabbix сохраняем как изменение за секунду.

    Единственный ньюанс - значение в файле указанно «в попугаях-секторах», причем размер этого «сектора» фиксирован 512 байт и не зависит от реальных значений ни физического ни логического сектора устройства (проверял на нескольких устройствах с реальным размером физического сектора 4к). Так что чтобы пересчитать в байты — не забудьте умножить на 512.

    Количество операций ввода-вывода в секунду


    Эта метрика — те самые пресловутые IOPS

    Самая простая метрика — мы ее уже записывали для подсчета svc time это значение колонок №5 write I/Os и №1 read I/Os также сохраненные как скорость в секунду.

    Заключение


    Этих метрик мне как правило достаточно для того чтобы я мог делать обоснованные выводы. Конечно это не все цифры которые можно получить из файла статистики. Например там есть и число текущих обрабатываемых запросов, и количество запросов которые были объеденены. Но полагаю при необходимости вам не составит труда добавить их по аналогии с описанным.
    И да не претендую на авторство — сам метод был когда-то давно загуглен, но за давностью лет ссылки конечно затерялись.

    В заключении приведу шаблончик и файлик параметров.

    Увы NDA заставляет кое-что подчистить из них, но надеюсь на работоспособность шаблона это не повлияет.

    А в шапке скриншот из Grafana прикрученной поверх zabbix — демонстрирующий реальные цифры с одной из тестовых инсталляций.
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 31

      +2
      > А к zabbix можно прикрутить модную Graphana и мониторить красиво.
      Статья отменная, но против Графаны у меня лично есть один, но весомый аргумент: Графана использует Zabbix API, который: а) Создаёт весьма неэффективные запросы в таблицы history и склонен ещё и отваливаться в таких ситуациях по таймауту; б) написан местами просто из рук вон плохо на языке PHP — и каждый тяжёлый вызов API тормозит базу данных.
      Для того, чтобы Графана не аффектила сам мониторинг, нужно написать для неё читалку из кеширующего history бэкенда, в свою очередь обновляющего кэш запросами в базу напрямую, либо — нужно пользоваться возможностью записи history в elastic search, но тогда не очень понятно, зачем вообще будет нужна Garafana. Инструмент визуализации мониторнга, который аффектит мониторинг — это плохо, и если Grafana до сих пор использует Zabbix API, то именно так и происходит.
      Относительно же красоты — собственно, сам Zabbix-«фронтенд» в 4.x станет полностью векторным, так что тем более глубокого смысла в графане не вижу.
        +1
        Но справедливости ради, запросы к zabbix-api это не сама grafana, а плагин к ней — по сути сторонний, еще до кучи у которого уведомления прикручены непонятно как. И в целом связка zabbix+grafana выглядит избыточной. В боевой системе мониторинга, особенно когда идет опрос большого числа узлов (ну и когда не нужны красивые картинки для менеджмента) наверное лучше либо использовать штатные графики заббикса (может не такие красивые, но зачем там красота) либо другую систему хранения, например прометей.
          +1
          плагин уже умеет лазить в postgres базу заббикса сам
            +1
            У нас, например, MySQL на весьма масштабной инсталляции и десяток профессиональных DBA'шников, специализирующихся на MySQL. Т.е. как бы для графаны мы точно не стали бы переходить на PostgreSQL. Особенно учитывая тот факт, что красивые векторные графики — это одно из основных целевых направлений развития Zabbix (направление неверное, на мой взгляд, но кто меня спрашивает).
          +1
          Чтобы вас хорошенько похаять дам с начала полезной инфы.
          Обновляемся до заббикс 3.4 или выше(вы уже).
          Потом включаем удалённое выполнение команд, шифрование до агента(если есть прокси, то и до прокси). Можете не включать, тогда вас смело могут вздрючить выполнив rce(найдут способ).
          Для LLD нахождения дисков вызываем lsblk с форматом вывода json через system.run `lsblk какие то ключи`
          Создаём айтем system.run `cut /path/to/[#lld_blk]/stat`
          Потом создаём зависимые айтемы и парсим таблицу.

          При таком подходе вот этого не будет:
          Но есть и недостатки:

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


          Пример как надо делать: github.com/AlexGluck/ZBX_NGINX

          Теперь хай.
          А юзерпараметры в одно место можете засунуть, когда их надо на 2к машин раскидать это лютое УГ. Мониторингом надо рулить на сервере мониторинга, а не по машинам скакать с авоськой тухлых реализаций.
            0
            Вариант конечно, но и я могу ваш вариант «обхаить» зачем system.run `cut /path/to/[#lld_blk]/stat` когда можно просто: vfs.file.contents['/path/to/[#lld_blk]/stat']

            Насчет цитированного — увы будет ибо, делить надо не одновременные значения а дельту… Хотя возможно зависимые элементы и отработают одновременно — в такие моменты заббикса не углублялся.

            В оправдание себя скажу — в статью не попало, но реальная срока в моем скрипте посложнее — ибо суммирует значения сразу с кучки дисков, причем в качестве параметра получает маску названий алиасов (несколько устройств разом). Кроме того мне не нужен мониторинг всей тьмы дисков. Разделы побиты на группы в соответствии с назначением и мониторятся именно группы. Но это лютый кастом и лишнее для статьи.

            И да любые файлики userparams легко раскидываются на 2к машин разными системами деплоймента типа Ansible например. Ну и потом не всегда можно вот так взять и обновить заббикс на 3.4.

              0
              Хотя возможно зависимые элементы и отработают одновременно

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

              vfs.file.contents['/path/to/[#lld_blk]/stat'] так даже лучше

              И да любые файлики userparams легко раскидываются на 2к машин разными системами деплоймента типа Ansible например.
              На практике нефига не раскидываются из-за сложности учёта где какие параметры нужно мониторить, либо превращают список добавленных параметров в непотребно огромный. Ну и расскажите мне с какой скоростью можно обновлять на таком количестве хостов эти параметры? Это занимает прилично времени и кроме мониторинга есть и другие задачи для которых необходимо выделять ресурсы.
                0
                Вот про группировку бы подробнее… У меня вот тоже куча дисков. И шаблоны чтобы группировать приходится скриптами делать…
                А у вас как?
                  0
                  Извиняюсь за паузу…
                  В примере есть скрипт дискавери… По сути его задача прочитать на хосте конфиг в котором написано: блочные устройства с именами в /dev/mapper/XXX* это диски индексатора, /dev/mapper/YYY* это диски BLOB, /dev/mapper/ZZZ* это разное логгирование.

                  Соответственно на такую группу устройств рисуется одна группа метрик которые прибиты к своему application

                  Затем в самом скрипте метрики чуть более сложный однострочник вида:
                  UserParameter=custom.vfs.dev.read.sectors[*],realpath '$1' | xargs -I{} basename {} | uniq | xargs -I {} cat /sys/class/block/{}/stat | awk '{n += $$3}; END{print n}'
                  Который по идее суммирует информацию по блочным устройствам, которые смонтированы куда надо.

                  Ну и плюсом собираются метрики по отдельным дискам дабы разобраться что к чему.

                  Но на самом деле, меня эта схема не очень устраивает потому как учитываются «средние значения», а при этом существует разный профиль например для индексатора крайне важен iops поэтому диски работают параллельно — и там не должно быть перекосов по нагрузке. А для BLOB iops не важны — софт работает на строго последовательный доступ и там диски работают так же последовательно и то что один пашет, а остальные простаивают — это норма. Что то можно учесть кастомными триггерами для приложения, а что то нет.

                +3
                Возможность запускать команды удаленно это немного опасно как минимум.
                  +1
                  Плюсанул, ты мой КО. Не просто же так я написал, что без шифрования не стоит включать выполнение команд.
                  –1
                  Во-первых удалённые команды выполняются всё-таки неким shell'ом, а никак не сервером мониторинга, нет ничего особо выдающегося в том, что агент может забрать STDOUT команды.
                  Во-вторых — во всех нормальных компаниях (из известных мне — просто во всех), конфигурацией управляют итак централизованно, через штуки типа Puppet и Ansible
                  Ну и в-третьих — а вы точно проверяли, что все ваши агенты НЕ принимают удалённые команды без шифрования? Проверьте — будете удивлены. Мы на всех агентах эту «возможность» отключили.
                    0
                    Вы невнимательно читали или неправильно поняли. Перечитайте или можете ошибаться дальше.
                    0
                    На самом деле меня сейчас больше интересует возможность использования для препроцессинга скриптов исполняемых на самом сервере заббикса.

                    Например такая вот проблема:
                    Приложение (например elastic) имеет api диагностики через HTTP json. B заббикс может разбирать json. Но увы парсер путей там тупой до безобразия. А в диагности нашего приложения используются массивы, а элементы определяются не позицией, а наличием ключа с определенным значением (например:
                    "modules" : [
                     {"module" : "first_module" , 
                       "metrics": { "metric" : "value" } 
                    },
                     {"module" : "second_module" , 
                       "metrics": { "metric" : "value" } 
                    } ]
                    

                    На наше счастье названия модулей «удобные» и мы написали несложненький php скриптец, который делает из такой простыни, простыню плоскую:

                     "first_module" :   {
                      "metrics": { "metric" : "value" } },
                     "second_module": {
                       "metrics": { "metric" : "value" } } 
                    

                    и до метрики можно добраться плоским zabbix парсером: first_module.metrics.metric

                    Но вы правы таскать скрипты по серверам неудобно, и хотелось бы иметь такой скрипт например на сервере самого заббикса, ну или на прокси.
                    Есть ли какие то варианты расширения самого заббикс сервера?
                      0

                      Увы пока нет. Руководитель заббикса пару лет назад говорил вроде о идее добавить луа, но мало вероятно, что это будет в релизе 4.0 может потом. Кроме луа тоже мало вероятно что добавят другие языки.

                    0
                    Насколько разумно мониторить всё описанное выше на виртуальных машинах (KVM, ESXi)? На что стоит обратить внимание, какие могут быть нюансы?
                      0
                      Увы не знаком с ньюансами мониторинга дисков на виртуальных машинах. Но на самом гипервизоре наверняка это необходимость.
                      0
                      Простите, может быть глупый вопрос: а насколько подобное тестирование на целевой машине влияет на ее производительность? Если я правильно понимаю, для более-менее адекватного тестирования надо записать а потом прочитать достаточно большой объем данных, а на это требуются какие-то ресурсы.
                        +2
                        Данные тесты не создают какой то дополнительной нагрузки (ну кроме самого получения метрик) и используют реальные данные и реальную среду для оценок.
                        Мой опыт показывает, что только тестирование на реальной машине, в реальной конфигурации, с реальными данными может показать насколько ваш сферический конь в вакууме тест в лаборатории соотноситься с реальной кобылой в сарае нагрузкой.
                        И как раз только в реальных условиях вы сможете протестировать на реальном объеме записываемых данных с реальными ресурсами.

                        А то как бывает обычно: мы берем какое то хранилище у которого: кеш у дисков, кеш у raid контроллера, навороченное ssd кеширование, плюс кеш операционной системы и еще кеш внутри приложения. Еще до кучи супер пупер навороченные алгоритмы префетчинга и прочее. За все эти кеши и алгоритмы мы заплатили денежки прямо или опосредованно.
                        И начинаем тестировать его, так чтобы все эти кеши забились и перестали работать. Т.е. тестируя мы заведомо выходим на режимы в котором наша система работать не будет а все эти навороты ненужны. Ну и какая цена такому тестированию?
                        Но по другому мы действовать не можем ибо, а кто нам скажет с какой вероятностью мы будем попадать в эти кеши. А еще у которых есть 100500 настоек самого кеша, плюс в десять раз больше настроек всего остального на них влияющих начиная от конфигураций файловой системы, опций форматирования и монтирования, различных LVM.
                        И только наблюдая за системой «в реальной среде обитания» вы сможете сказать: «да кеши работают» или «нет не работают» или да — форма графиков в реальной среде совпадают с аналогичными в тестовой, значит скорее всего методика тестирования верна.
                          0
                          Спасибо за развернутый ответ
                        +1
                        Используем SAR, в принципе проще и без наворотов. Шаблон подпил коллега, репа тут github.com/abstractiontensor/sar-zabbix-template
                          +1
                          Так как эти метрики очень зависят друг от друга, то не зная все нельзя сделать правильные выводы.


                          Эх, еще бы и кейсы из практики по параметрам… :)
                          Например. резко выросла утилизация raid массива, при этом упала пропускная способность, что указало выход из строя диска.

                          или изменение параметров ОС/ФС/контроллеров с… на… дало прирост параметра на Х %
                            0
                            Сложно говорить про какие то конкретные вещи, но из последнего:
                            • рост IOPS при тех же скоростях записи — признак фрагментации файловой системы
                            • утилизация дисковой подсистемы строго следует за пропускной способностью, и например составляет 100% для 6,2 гигабита в секунду — уперлись в пропускную способность FC 8gbps линка. Добавляем второй линк и настраиваем мультипас — утилизация падает в 2 раза
                            • утилизация дисковой подсистемы выросла пи этом iops и скорость записи та же — глючил линк на FC на одном из каналов
                            • покрутили queue/max_sectors_kb со штатных 512 до 4096 — утилизация упала, но максимально много не значит лучше, при 8192 — утилизация стала расти

                            и другое. На самом деле на практике вдруг замечаешь, что резко изменилась форма графиков и просто начинаешь разбираться что случилось. Там уж и dmesg в помощь. И не всегда проблема бывает в вашем софте.
                            Был случай когда при обновлении не вытерся старый бинарник — он в принципе не очень мешал, а просто подтекал и кушал память потом его OOM прибивал, он перезапускался и так по кругу. На графиках это выглядело как рост операций ввода вывода от софта в виде пилы. Софт перекопали, проблем не нашли — в итоге оказалось что софтина выкушивала кеш операционной системы, что конечно приводило к изменению количества запросов.
                              0
                              Еще эти графики полезны например при настройках СУБД типа Postgres и оценках работы например индексов. Т.е. же самые shared_buffers у Postgres или извечные терки — выносить ли pg_xlog на отдельные диски, а avtovacuum ли мешает работе базы.
                                0
                                Рейды, mdadm например, тоже можно мониторить без юзерпараметров, забирать значения через vfs.file.contents и потом предобработкой парсить регулярками.
                                А из полезных советов могу накинуть ещё один:

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

                                Дойдут руки, всем напихаю дефолтные шаблоны феншуйные. ^^
                                  0
                                  В современном мире найти решение получения данных не проблема, проблема правильно понять данные.
                                  Если вернуться к дискам, то каждые n-секунд врятли кто то будет мониторить состояние raid и прогон теста на badblock каждый день тоже врятли делают. А вот утилизация диска мониторится постоянно.
                                  Вот и хотелось бы расширить анамнез различных проблем базируясь минимум данных.
                                +1
                                Простите, но без размещения на share.zabbix.com и гитхабе — кпд вашей работы довольно низкий. Люди ищут, сравнивают и выбирают решения именно там.
                                  0
                                  :) прощаю — у меня не было цели предложить кому-то решение. Скорее так — просто поделиться конкретным опытом. Более того я не считаю, что заббикс — правильный или наиболее подходящий инструмент для этой задачи. Просто подвернулся под руку, и возникла задача как сделать именно это и именно с заббиксом. Ну плюсом спровоцировать дискуссию из которой можно было бы почерпнуть что то новое. Вон например в комментариях выше уже были варианты как сделать тоже самое, но проще. То есть считайте профит какой то уже получен.
                                  0
                                  А в чем смысл вычислять производную от iops и util метрику *_svctime, если ядро предоставляет информацию о суммарном затреченном времени на все дисковые операции (в /sys/block/sdX/stat поля read ticks, write ticks или в /proc/diskstat аналоничные по смыслу поля). Делим на количество io в еденицу времени и получаем честный средний latency (await).

                                  В случае с *_svctime цифра может не иметь ничего общего с реальным latency. Наример: за 1 секунду было сделано 5 параллельных r_io опреаций, каждая выполнялась 1 секунду. Реальный средний r_latency (и посчитанный исходя из 5ти секунд read ticks) — 1 секунда, r_svctime же будет 1/5 = 0.2 секунды.
                                    0
                                    Что то или я не до конца уловил вашу мысль или вы не совсем поняли, но вроде вы и говорите про то же самое:

                                    В моем примере делится: количество тиков за интервал измерения (по сути это есть утилизация записью) на количество операций за этот же интервал (количество параллельных записей). Т.е. как и в вашем примере так и будет:
                                    Пусть выполнялось:
                                    5 одновременных операций.
                                    каждая за 100 msec (реальный латенси 1 операции )
                                    интервал опросов заббиксом 1 секунда. тогда…

                                    write_util будет: 100 мсек * 5 операций / 1 секунду = 0.5 = 50 % (100 * 5 = 500 тиков это колонка w_ticks (ms))
                                    а w_svctime: 500 / 1 секунду / (5 операций / 1 секунду )…
                                    собственно технический делитель от забикса «1 секунда» сократится и получим:

                                    100 * 5 / 5 == 100ms или искомыя средняя latency.

                                      0
                                      Да, я поспешил. У вас в статье с этим все правильно. Просто бросилось в глаза «write utils», это и смутило. Не заметил дальше, что берется именно «write ticks», т.е. суммарное время всех w_io операций.

                                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                  Самое читаемое