Статьи

Профилирование использования памяти MySQL с массивом Valgrind

 Этот пост принадлежит Роэлю Ван де Паару   из блога MySQL Performance.

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

Например; Вы, возможно, заметили резкое увеличение памяти после выполнения определенного запроса. Или, возможно, mysqld использует слишком много памяти. Или, может быть, вы заметили, что профиль памяти mysqld постепенно увеличивается, что указывает на возможную ошибку памяти

Безотносительно причины, есть простой, но мощный способ профилировать использование памяти MySQL; инструмент Massif от Valgrind. Выдержка из справочной страницы по массиву (память кучи — это просто выделенный пул памяти для использования программами);

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

Во-первых, нам нужно получить программу Valgrind. Хотя вы можете использовать последнюю версию, поставляемую с вашей ОС (например, yum или apt-get install Valgrind), я предпочитаю получить и скомпилировать последнюю версию (3.8.1 на данный момент):

sudo yum remove valgrind*      # or apt-get etc.
sudo yum install wget make gcc gcc-c++ libtool libaio-devel bzip2 glibc*
wget http://valgrind.org/downloads/valgrind-3.8.1.tar.bz2      # Or newer
tar -xf valgrind-3.8.1.tar.bz2
cd valgrind-3.8.1
./configure
make
sudo make install
valgrind --version             # check version to be same as what was downloaded (3.8.1 here)

Есть несколько преимуществ для самостоятельной компиляции:

  1. При использовании последней версии Valgrind, даже скомпилированной «из коробки» (т.е. без изменений), вы, скорее всего, увидите меньше проблем, чем с более ранними версиями. Например, в более ранних версиях может быть слишком мало выделенных ресурсов отслеживания внутренней памяти Valgrind. Другими словами; вы не сможете запустить ваш огромный буферный пул под Valgrind, если он не будет быстро жаловаться.
  2. Если вы самостоятельно компилируете и эти внутренние ограничения Valgrind все еще слишком малы, вы можете легко изменить их перед компиляцией. Часто встречающийся параметр — VG_N_SEGMENTS в coregrind / m_aspacemgr / aspacemgr-linux.c (когда вы видите «Valgrind: FATAL: VG_N_SEGMENTS слишком низок»)
  3. Новые версии [лучше] поддерживают более новое оборудование и программное обеспечение.

Как только ‘valgrind –version’ вернет правильную установленную версию, вы готовы к работе. В этом примере мы запишем вывод в /tmp/massif.out. Если вы предпочитаете использовать другое местоположение (и, следовательно, обязаны установить правильные права на файл и т. Д.), Используйте:

$ touch /your_location/massif.out
$ chown user:group /your_location/massif.out    # Use the user mysqld will now run under (check 'user' setting in my.cnf also) (see here if this is not clear)

Теперь, прежде чем запускать mysqld под Valgrind, убедитесь, что присутствуют символы отладки. Символы отладки присутствуют, когда двоичный файл не удален из них (загруженные пакеты ‘GA’ [общедоступные] могут содержать оптимизированные или очищенные двоичные файлы, которые оптимизированы для скорости, а не для отладки). Если ваши двоичные файлы удалены, у вас есть несколько вариантов получить отладочную сборку mysqld для использования в целях профилирования памяти:

  • Загрузите соответствующие пакеты debuginfo (они могут быть доступны не для всех выпусков).
  • Загрузите отладочные файлы той же версии сервера, которую вы используете в настоящее время, и просто используйте отладочный mysqld в качестве замены для вашего текущего mysqld (т. Е. Завершение работы, mv mysqld mysqld.old, cp / debug_bin_path / mysqld ./mysqld, запуск ).
  • Если у вас есть (через загрузку или из прошлого хранилища) доступный исходный код (той же версии сервера, которую вы используете в данный момент), просто отладьте-скомпилируйте исходный код и используйте двоичный файл mysqld в качестве замены для замены, как показано в последнем точка. (Например, исходный код Percona Server 5.5 можно откомпилировать с помощью «./build/build-binary –debug ..»).

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

Как только вы все настроите с помощью символов отладки, завершите работу сервера mysqld с помощью стандартной процедуры завершения работы, а затем перезапустите его вручную в Valgrind с помощью инструмента Massif:

$ valgrind --tool=massif --massif-out-file=/tmp/massif.out /path/to/mysqld {mysqld options...}

Обратите внимание, что «{mysqld options}» может, например, включать –default-file = / etc / my.cnf (если именно здесь находится ваш файл my.cnf), чтобы указать mysqld на файл настроек и т. Д. После mysqld при правильном запуске (проверьте, можете ли вы войти в систему с помощью клиента mysql), вы должны выполнить любые шаги, которые, по вашему мнению, необходимы для увеличения использования памяти / вызвать проблему с памятью. Вы также можете просто оставить сервер включенным на некоторое время (например, если у вас со временем увеличивается объем памяти).

После того, как вы сделали это, выключение туздО (снова используя обычную процедуру выключения), а затем использовать  ms_print инструмент на файл masif.out для вывода текстового графика использования памяти:

ms_print /tmp/massif.out

Частичный пример вывода из недавней проблемы с клиентом, над которой мы работали:

96.51% (68,180,839B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
 ->50.57% (35,728,995B) 0x7A3CB0: my_malloc (in /usr/local/percona/mysql-5.5.28/usr/sbin/mysqld)
 | ->10.10% (7,135,744B) 0x7255BB: Log_event::read_log_event(char const*, unsigned int, char const**, Format_description_log_event const*) (in /usr/local/percona/mysql-5.5.28/usr/sbin/mysqld)
 | | ->10.10% (7,135,744B) 0x728DAA: Log_event::read_log_event(st_io_cache*, st_mysql_mutex*, Format_description_log_event const*) (in /usr/local/percona/mysql-5.5.28/usr/sbin/mysqld)
 | |   ->10.10% (7,135,744B) 0x5300A8: ??? (in /usr/local/percona/mysql-5.5.28/usr/sbin/mysqld)
 | |   | ->10.10% (7,135,744B) 0x5316EC: handle_slave_sql (in /usr/local/percona/mysql-5.5.28/usr/sbin/mysqld)
 | |   |   ->10.10% (7,135,744B) 0x3ECF60677B: start_thread (in /lib64/libpthread-2.5.so)
 | |   |     ->10.10% (7,135,744B) 0x3ECEAD325B: clone (in /lib64/libc-2.5.so)
 [...]

И несколько снимков позже:

92.81% (381,901,760B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->84.91% (349,404,796B) 0x7A3CB0: my_malloc (in /usr/local/percona/mysql-5.5.28/usr/sbin/mysqld)
| ->27.73% (114,084,096B) 0x7255BB: Log_event::read_log_event(char const*, unsigned int, char const**, Format_description_log_event const*) (in /usr/local/percona/mysql-5.5.28/usr/sbin/mysqld)
| | ->27.73% (114,084,096B) 0x728DAA: Log_event::read_log_event(st_io_cache*, st_mysql_mutex*, Format_description_log_event const*) (in /usr/local/percona/mysql-5.5.28/usr/sbin/mysqld)
| | ->27.73% (114,084,096B) 0x5300A8: ??? (in /usr/local/percona/mysql-5.5.28/usr/sbin/mysqld)
| | | ->27.73% (114,084,096B) 0x5316EC: handle_slave_sql (in /usr/local/percona/mysql-5.5.28/usr/sbin/mysqld)
| | | ->27.73% (114,084,096B) 0x3ECF60677B: start_thread (in /lib64/libpthread-2.5.so)
| | | ->27.73% (114,084,096B) 0x3ECEAD325B: clone (in /lib64/libc-2.5.so)

Как вы можете видеть, для функции Log_event :: read_log_event выделяется достаточное количество (и в данном случае «слишком много») памяти. Вы также можете видеть, что объем памяти, выделенной для функции, значительно увеличивается по снимкам. Этот пример помог выявить ошибку утечки памяти на отфильтрованном ведомом устройстве (подробнее см. В настоящем  отчете об ошибке ).

Помимо запуска Valgrind Massif описанным выше способом, вы также можете изменить параметры снимка Massif  и другие параметры строки cmd для соответствия частоте снимка и т. Д. В соответствии с вашими конкретными требованиями. Однако вы, вероятно, обнаружите, что параметры по умолчанию будут работать хорошо в большинстве сценариев.

Для технически продвинутых вы можете сделать еще один шаг: использовать gdbserver от Valgrind для получения снимков массива по требованию (т.е. вы можете запускать снимки массива из командной строки непосредственно перед, во время и после выполнения любых команд, которые могут существенно изменить использование памяти).

Вывод: использование массива Valgrind и, возможно, gdbserver Valgrind (который не использовался в решении обсуждаемого примера ошибки), поможет вам проанализировать входы и выходы использования памяти mysqld (или любых других программ).

Кредиты: Персонал @ клиент Percona, Оваис, Лауринас, Сергей, Джордж, Владислав, Рагхавендра, Игнасио, я и другие в Percona — все объединенные усилия, приводящие к информации, которую вы можете прочитать выше.