Человеческий мозг обычно лучше воспринимает информацию из изображений, чем из текстов. И в инструментах, подобных 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.378sSHELL> 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, но и для сбора трассировки стека. Так у нас будет подробная информация о том, что происходит на сервере, и позволяющая провести улучшенный анализ.
Подробнее о том, как собирать эти образцы, можно прочитать в онлайн-документации.
Brendan Gregg – вдохновитель проекта Flame Graph) расскажет вам по теме еще больше
GDB: Программа-отладчик для GNU Project
Interpreting Flame Graphs
Flame Graphs 201, отличный вебинар, чтобы лучше во всем разобраться
Английская статья группы поддержки Percona по Flame Graph
Вывод
Flame Graph был создан, чтобы быстро и подробно понять использование ЦП при работе с MySQL. Но со временем область его применения расширилась, и он стал применяться для анализа и оптимизации различных операций под нагрузкой.
По сравнению с длинными полотнами текстовых отчетов, а также трассировщиками, которые требуют большого опыта при интерпретации полученного результат, у Flame Graph есть явные преимущества. Его можно просматривать в любом браузере без каких-либо дополнительных инструментов, области будут кликабельными. Он интуитивно понятен и не требует длительного обучения.
Источники:
Profiling Software Using perf and Flame Graphs
Using Flame Graphs to Process Outputs From pt-pm
27-28 июня в Москве впервые пройдет TestDriven Conf 2022 — профессиональная конференция для senior тестировщиков и QA-инженеров. Она будет посвящена всем вопросам автоматизации в тестировании и рядом.
Расписание и тезисы докладов уже на сайте. И можно купить или забронировать билеты по выгодной цене — чем ближе к конференции, тем будет дороже.
