Человеческий мозг обычно лучше воспринимает информацию из изображений, чем из текстов. И в инструментах, подобных Flame Graph, этот принцип блестяще реализован. Поэтому в Percona его используют в рамках работы группы поддержки. Чаще всего в тех случаях, когда нужно получить всестороннее представление о том, что и как долго проделывает MySQL. Так можно лучше понять, какие операции стоят за конкретной рабочей нагрузкой и каким образом лучше исправлять возникающие проблемы. И это можно использовать и для оптимизации, и для устранения неполадок.

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

Рассмотрим два инструмента, с помощью которых можно получить данные для Flame Graphs. Они используются для создания графического представления функций, которые вызываются в выбранном нами программном обеспечении. В данном случае был выбран Percona Server для MySQL, но его можно распространить на любой софт для получения трассировки стека.

Прежде чем мы начнем, прислушайтесь — НЕ запускайте его в производственных системах, если вы не разбираетесь в том, что делаете. Это относится к любым элементам профилирования.

perf_events

Начнем с perf (он же perf_events). Это интерфейс доступа к счетчикам в PMU (Performance Monitoring Unit), который является частью CPU.

Установка необходимых пакетов

Для простоты в Percona используют команды для CentOS 7, для дистрибутивов на основе Debian все будет иметь тот же вид. Единственная разница в том, что вместо команды «yum» будет «apt-get install linux-tools-$(uname -r)».

Чтобы установить perf, просто введите:

SHELL> sudo yum install -y perf

Чтобы получить проект Flame Graphs:

SHELL> mkdir -p ~/src
SHELL> cd ~/src
SHELL> git clone https://github.com/brendangregg/FlameGraph

Вот и все! Можно приступать.

Образцы сбора данных

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

№1. Сбор только в течение установленного периода времени (в данном случае десять секунд):

SHELL> sudo perf record -a -F 99 -g -p $(pgrep -x mysqld) -- sleep 10

№2. Сбор до отправки сигнала прерывания (CTRL-C):

SHELL> sudo perf record -a -F 99 -g -p $(pgrep -x mysqld)

В примерах 1,2 использовался флаг «-p», чтобы сбор данных производился только из интересующего нас процесса, но при необходимости можно собирать данные из всех запущенных процессов.

№3. Сбор на протяжении всего жизненного цикла процесса:

SHELL> sudo perf record -a -F 99 -g -- /sbin/mysqld \
--defaults-file=/etc/percona-server.conf.d/mysqld.cnf --user=mysql

Так как невозможно заранее узнать ID процесса (PID), а при выполнении команды фактически запускается сервис MySQL, то данные мы собираем со всех процессов. Этот тип команды удобен, если вы хотите получить данные с самого начала процесса, что невозможно сделать другими способами.

Обратите внимание, что прервав этот вариант, мы также прервем порожденный процесс, поэтому можно использовать еще и такой сбор:

SHELL> sudo perf record -a -F 99 -g -p $(pgrep -x mysqld) -- mysql -e "SELECT * FROM db.table"

В этом варианте выполняется запрос к уже запущенному сервису MySQL, поэтому можно использовать флаг «-p» для сбора данных о серверном процессе. Это удобно, если вы хотите собрать данные о том, что происходит внутри MySQL в определенный момент.

Подготовка образцов

После первоначального сбора данных их еще нужно сделать «читабельными», потому что perf record хранит их в двоичном формате. Для этого можно использовать:

SHELL> sudo perf script > perf.script

Так, perf.data будет читаться по умолчанию. Но это имя файла уже использует perf record, поэтому его нужно переопределить с помощью флагов «-i» и «-o». После этого можно будет прочитать сгенерированный текстовый файл. Если вы его откроете, то увидите, что читать его довольно тяжело, именно поэтому мы агрегируем данные в более понятную визуальную форму.

Генерация Flame Graphs

Для этого нужно перенаправить вывод stackcollapse-perf.pl на ввод flamegraph.pl. Поскольку мы не добавили папку git FlameGraph в наш путь, мы будем использовать полные пути:

SHELL> ~/src/FlameGraph/stackcollapse-perf.pl perf.script | ~/src/FlameGraph/flamegraph.pl > flamegraph.svg

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

SHELL> time sudo perf record -a -F 99 -g \
-p $(pgrep -x mysqld) \
-- mysql test -e "INSERT INTO joinit SELECT NULL, uuid(), time(now()),  (FLOOR( 1 + RAND( ) *60 )) FROM joinit;"
Warning:
PID/TID switch overriding SYSTEM
[ perf record: Woken up 7 times to write data ]
[ perf record: Captured and wrote 1.909 MB perf.data (8214 samples) ]
 
real 1m24.366s
user 0m0.133s
sys 0m0.378s
SHELL> sudo perf script | \
~/src/FlameGraph/stackcollapse-perf.pl perf.script | \
~/src/FlameGraph/flamegraph.pl > mysql_select_into_flamegraph.svg

В пример вошли полные команды и их выходные данные. Чтобы избежать записи и чтения из выходного файла perf.script, пришлось объединить шаги №2 и №3 с помощью канала (|). Мы получили выходные данные по времени, поэтому можем увидеть оценку объема данных, которые генерирует инструмент: более 2 Мб за 1 минуту и 25 секунд. Данные, конечно, будут варьироваться в зависимости от многих факторов, поэтому их лучше протестировать в имеющейся среде.

Еще давайте запустим запрос INSERT INTO … SELECT к базе данных, чтобы проанализировать его выполнение. Вот так выглядит скриншот Flame Graph, сгенерированный процессом по методу сбора данных №2:

Его можно оптимизировать, покопавшись во write_record. Если сделать эту функцию быстрее, то мы получим большой потенциал для сокращения общего времени выполнения. В синей рамке в левом нижнем углу видно, что для построения графика взято в общей сложности более 60% выборок этого пути выполнения кода. Эта информация динамически меняется при наведении курсора на имена функций:

Вы также можете улучшить визуализацию с помощью выделенной синей рамкой области.
Вы также можете улучшить визуализацию с помощью выделенной синей рамкой области.

В рамках интерпретации данных perf — это всё. Давайте теперь посмотрим еще один инструмент, который подходит для создания наглядных графиков.

pt-pmp

Flame Graphs изначально не задумывался для обработки выходных данных pt-pmp. Поскольку они аналогичны результату использования stackcollapse-perf.pl, то их тоже можно использовать, но с оговорками.

Основные отличия выходных данных pt-pmp:

  • В первом столбце указано количество потоков с обратной трассировкой.

  • Имена функций разделяются запятой вместо точки с запятой.

  • Pt-pmp печатает дату в первой строке, поэтому ее нужно будет обрезать.

В этой части тоже есть свое «НО», на которое нужно обратить внимание. Pt-pmp будет использовать GDB в фоновом режиме, а значит, MySQL при сборе образцов остановится. Обязательно прочитайте документацию, прежде чем запускать всё это в производственной среде.

Установка пакетов

Для получения Flame Graphs мы клонируем проект GitHub:

shell> cd ~/src
shell> git clone https://github.com/brendangregg/FlameGraph

Запуск инструментов

Предположим, мы использовали простую команду pt-pmp:

shell> pt-pmp --pid=$(pgrep -x mysqld) > pt-pmp.out

Чтобы компенсировать различия, описанные выше, мы можем использовать однострочник BASH, например:

shell>  tail -n+2 pt-pmp.out | awk '{print $2, $1}' | sed -e 's/,/;/g' > pt-pmp.fgr.out

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

  • tail -n+2 pt-pmp.out  -> игнорирует первую строку, то есть дату;

  • awk ‘{print $2, $1}’  -> перемещает количество потоков в конец строки так что backtrace оказывается вначале;

  • sed -e ‘s/,/;/g’  -> меняет запятую на точку с запятой.

После этого можно использовать perl-скрипт как обычно:

shell> ~/src/FlameGraph/flamegraph.pl --countname="threads" pt-pmp.fgr.out > pt-pmp.fgr.out.svg

Аргумент –countname предназначен только для изменения текста «образцов» по умолчанию, чтобы он лучше читался относительно количества потоков. Именно это означают числа в данном контексте.

И тогда мы получаем требуемый svg-файл с Flame Graph, показывающий разные обратные трассировки и потоки:

Дополнение Percona Toolkit

Кроме того, pt-stalk можно использовать не только для сбора типичной информации о метриках, связанных с ОС и MySQL, но и для сбора трассировки стека. Так у нас будет подробная информация о том, что происходит на сервере, и позволяющая провести улучшенный анализ.

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

Вывод

Flame Graph был создан, чтобы быстро и подробно понять использование ЦП при работе с MySQL. Но со временем область его применения расширилась, и он стал применяться для анализа и оптимизации различных операций под нагрузкой.

По сравнению с длинными полотнами текстовых отчетов, а также трассировщиками, которые требуют большого опыта при интерпретации полученного результат, у Flame Graph есть явные преимущества. Его можно просматривать в любом браузере без каких-либо дополнительных инструментов, области будут кликабельными. Он интуитивно понятен и не требует длительного обучения.

Источники:

  1. Profiling Software Using perf and Flame Graphs

  2. Using Flame Graphs to Process Outputs From pt-pm

27-28 июня в Москве впервые пройдет TestDriven Conf 2022 — профессиональная конференция для senior тестировщиков и QA-инженеров. Она будет посвящена всем вопросам автоматизации в тестировании и рядом.

Расписание и тезисы докладов уже на сайте. И можно купить или забронировать билеты по выгодной цене — чем ближе к конференции, тем будет дороже.

Комментарии (0)