Человеческий мозг обычно лучше воспринимает информацию из изображений, чем из текстов. И в инструментах, подобных 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, но и для сбора трассировки стека. Так у нас будет подробная информация о том, что происходит на сервере, и позволяющая провести улучшенный анализ.
Подробнее о том, как собирать эти образцы, можно прочитать в онлайн-документации.
Brendan Gregg – вдохновитель проекта Flame Graph) расскажет вам по теме еще больше
Flame Graphs 201, отличный вебинар, чтобы лучше во всем разобраться
Вывод
Flame Graph был создан, чтобы быстро и подробно понять использование ЦП при работе с MySQL. Но со временем область его применения расширилась, и он стал применяться для анализа и оптимизации различных операций под нагрузкой.
По сравнению с длинными полотнами текстовых отчетов, а также трассировщиками, которые требуют большого опыта при интерпретации полученного результат, у Flame Graph есть явные преимущества. Его можно просматривать в любом браузере без каких-либо дополнительных инструментов, области будут кликабельными. Он интуитивно понятен и не требует длительного обучения.
Источники:
27-28 июня в Москве впервые пройдет TestDriven Conf 2022 — профессиональная конференция для senior тестировщиков и QA-инженеров. Она будет посвящена всем вопросам автоматизации в тестировании и рядом.
Расписание и тезисы докладов уже на сайте. И можно купить или забронировать билеты по выгодной цене — чем ближе к конференции, тем будет дороже.