Jemalloc является высокопроизводительным менеджером распределения оперативной памяти, который для платформы Linux реализован в виде самостоятельной библиотеки. Jemalloc является оптимизированным вариантом реализации функций malloc, который призван решать проблемы с фрагментацией при выделения памяти в несколько потоков возникающие на однопроцессорных и многопроцессорных системах и оптимальной утилизации ресурсов CPU. Применение jemalloc даёт возможность повысить производительность всей системы, уменьшив фрагментацию и как результат понизить потребление оперативной памяти (RAM). Jemalloc изначально был написан Джейсоном Эвансом (Jason Evans) для FreeBSD, а потом портирован на платформу Linux.
TCMalloc (Thread-Caching Malloc) является аналогом Jemalloc от компании Google.
В интернете очень много статей на тему использования jemalloc и tcmalloc с разными клонами MySQL, но к великому сожалению если настраивать MySQL по этим статьям, то ничего не получиться. Статьи банально устарели. Так давайте же актуализируем их для Oracle MySQL на Debian 9.
Как я говорил выше, в интернете очень много статей на тему использования jemalloc и tcmalloc с разными клонами MySQL, вот наиболее авторитетные стати:
Percona blog: Impact of memory allocators on MySQL performance
Percona blog: Memory allocators: MySQL performance improvements in Percona Server 5.5.30-30.2
Percona blog: MySQL performance: Impact of memory allocators (Part 2)
Percona blog: Enabling and Disabling Jemalloc on Percona Server
Revisiting memory allocators and MySQL performance
Concurrent large allocations: glibc malloc, jemalloc and tcmalloc
Исходные данные: Debian 9, Oracle MySQL 5.7.24, не путайте с MariaDB или Percona Server for MySQL, я буду использовать именно Oracle MySQL.
Задача: Настроить работу MySQL с jemalloc и tcmalloc
В 99% статей для настройки jemalloc с MySQL будет дана такая инструкция:
Добавьте в файл /etc/mysql/my.cnf в секцию [mysqld_safe] строку
malloc-lib = /usr/lib/i386-linux-gnu/libjemalloc.so.1
Потом перезапустите MySQL и все работает, но увы, Вас будет ждать разочарование — это метод не работает на последних версиях Oracle MySQL 5.7.x и MariaDB 10.3.x и дело не в том, что mysqld_safe не читает файл конфигурации или не видит в нем эту директиву, дело совершенно в другом.
В данной статье я не буде сравнивать производительность и другие показатели работы MySQL с разными менеджерами распределения оперативной памяти, все это есть в статьях, указанных мной выше. Намекну лишь, что я проводил разные тесты и остановился на Jemalloc ;)
Итак приступим.
Установим библиотеки libjemalloc1 и libtcmalloc-minimal4
apt-get -y install libjemalloc1 apt-get -y install libtcmalloc-minimal4
Создадим файл настроек для MySQL с библиотекой libjemalloc1:
echo "LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.1" > /etc/default/mysql
Обратите внимание, что если Вы устанавливаете Oracle MySQL из репозитария Oracle, то файла /etc/default/mysql у Вас не будет. В других клонах MySQL, в частности MariaDB файл /etc/default/mysql будет содержать настройки и поэтому в него не нужно писать LD_PRELOAD.
Создадим дополнительный файл с настройками для systemd.
ВНИМАНИЕ! Файл /etc/systemd/system/mysql.service.d/override.conf будет перезаписан, поэтому у Вас его не должно быть.
mkdir /etc/systemd/system/mysql.service.d (cat <<-EOF [Service] AmbientCapabilities=CAP_SYS_NICE EnvironmentFile=-/etc/default/mysql EOF ) > /etc/systemd/system/mysql.service.d/override.conf
Опция AmbientCapabilities=CAP_SYS_NICE добавлена на случай пожара, т.к. на Red Hat Enterprise Linux без нее люди столкнулись с проблемой установки переменной окружения LD_PRELOAD через systemd.
Перечитаем настройки systemd:
systemctl daemon-reload
Проверим статус mysql:
systemctl status mysql ● mysql.service - MySQL Community Server Loaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset: enabled) Drop-In: /etc/systemd/system/mysql.service.d └─override.conf Active: active (running) since Thu 2019-01-03 10:22:51 +05; 38min ago Main PID: 701 (mysqld) CGroup: /system.slice/mysql.service └─701 /usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid
Перезапустим MySQL:
systemctl restart mysql
Проверим процессы использующие libjemalloc.so.1:
lsof /usr/lib/x86_64-linux-gnu/libjemalloc.so.1 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME mysqld 32428 mysql mem REG 254,0 219912 2983 /usr/lib/x86_64-linux-gnu/libjemalloc.so.1
lsof -n | grep [j]emalloc COMMAND PID TID USER FD TYPE DEVICE SIZE/OFF NODE NAME mysqld 32198 mysql mem REG 254,0 219912 4214 /usr/lib/x86_64-linux-gnu/libjemalloc.so.1 mysqld 32198 32199 mysql mem REG 254,0 219912 4214 /usr/lib/x86_64-linux-gnu/libjemalloc.so.1 mysqld 32198 32200 mysql mem REG 254,0 219912 4214 /usr/lib/x86_64-linux-gnu/libjemalloc.so.1 mysqld 32198 32201 mysql mem REG 254,0 219912 4214 /usr/lib/x86_64-linux-gnu/libjemalloc.so.1 ..... mysqld 32198 32232 mysql mem REG 254,0 219912 4214 /usr/lib/x86_64-linux-gnu/libjemalloc.so.1 mysqld 32198 32233 mysql mem REG 254,0 219912 4214 /usr/lib/x86_64-linux-gnu/libjemalloc.so.1 mysqld 32198 32748 mysql mem REG 254,0 219912 4214 /usr/lib/x86_64-linux-gnu/libjemalloc.so.1
Посмотрим мапинг памяти:
pmap -x $(pidof mysqld) | grep [m]alloc Address Kbytes RSS Dirty Mode Mapping 00007fd768ddf000 208 196 0 r-x-- libjemalloc.so.1 00007fd768ddf000 0 0 0 r-x-- libjemalloc.so.1 00007fd768e13000 2044 0 0 ----- libjemalloc.so.1 00007fd768e13000 0 0 0 ----- libjemalloc.so.1 00007fd769012000 8 8 8 r---- libjemalloc.so.1 00007fd769012000 0 0 0 r---- libjemalloc.so.1 00007fd769014000 4 4 4 rw--- libjemalloc.so.1 00007fd769014000 0 0 0 rw--- libjemalloc.so.1
Таким образом сейчас наш экземпляр Oracle MySQL использует менеджер распределения оперативной памяти Jemalloc.
Для того, чтобы использовать TCMalloc в качестве менеджера нужно в файле /etc/default/mysql заменить библиотеку:
echo "LD_PRELOAD=/usr/lib/libtcmalloc_minimal.so.4" > /etc/default/mysql
и перезапустить MySQL.
После этого проверим процессы использующие libtcmalloc_minimal.so.4
lsof /usr/lib/libtcmalloc_minimal.so.4 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME mysqld 5196 mysql mem REG 254,0 160336 4543 /usr/lib/libtcmalloc_minimal.so.4.3.0
Посмотрим мапинг памяти:
pmap -x $(pidof mysqld) | grep [m]alloc Address Kbytes RSS Dirty Mode Mapping 00007fb77ab2f000 152 132 0 r-x-- libtcmalloc_minimal.so.4.3.0 00007fb77ab2f000 0 0 0 r-x-- libtcmalloc_minimal.so.4.3.0 00007fb77ab55000 2044 0 0 ----- libtcmalloc_minimal.so.4.3.0 00007fb77ab55000 0 0 0 ----- libtcmalloc_minimal.so.4.3.0 00007fb77ad54000 4 4 4 r---- libtcmalloc_minimal.so.4.3.0 00007fb77ad54000 0 0 0 r---- libtcmalloc_minimal.so.4.3.0 00007fb77ad55000 4 4 4 rw--- libtcmalloc_minimal.so.4.3.0 00007fb77ad55000 0 0 0 rw--- libtcmalloc_minimal.so.4.3.0
На этом все, до скорых встреч. Если у Вас возникли вопросы или Вы хотите, чтобы я помог Вам, то Вы всегда можете связаться со мной разными доступными способами.
Профессионально занимаюсь системным администрированием Linux -серверов и баз данных (MySQL, PostgreSQL) на протяжении последних 24 лет.
Доброго.
Спасибо за статью. Дополню, что в репах Дебиана версия jemalloc старая.
Приходится качать и компилировать из сурсов.
Всегда пожалуйста.
Да, согласен с Вами, версия jemalloc старая в репо, но использовать ее в продакшене или собирать из исходников нужно после тестов производительности. В том же блоге перконы были тесты на разных версиях jemalloc и они различались по производительности. Так что не факт, что новая 5-я версия jemalloc лучше 3-ей применительно к MySQL.
Спасибо за инфу.
Для mariadb — надо добавлять в /etc/systemd/system/mysql.service.d/
Для Ubuntu — строку «AmbientCapabilities=CAP_SYS_NICE» нужно убрать.
А можно подключить jemalloc к php и nginx?
Если да — то как?
Можно, только для nginx не вижу профита в jemalloc.
Но если хочется, то для Debian 9 в
/lib/systemd/system/nginx.service.d/limit.conf (проверьте какие файлы у вас есть в /lib/systemd/system/nginx.service.d или если каталога нет, то создайте его) пишем:
потом
systemctl daemon-reload
/etc/init.d/nginx restart
и смотрим
pmap -x $(pidof nginx) | grep [m]alloc
Спс.
А для php-fpm что-то схожее?
Или для php-fpm тоже не смысла?
Пожалуйста.
Для php7.0-fpm который идет с Debian 9 аналогично, в файл /lib/systemd/system/php7.0-fpm.service.d/limit.conf добавляете строки:
потом
проверяем
Для php7 это не требуется, т.к. там используется свой memory manager (запиленный на базе jemalloc)
Я его дkя всеq системы зарядил в файл /etc/ld.so.preload для Убунту 20.04(после установки «sudo apt install libjemalloc2»):
/usr/lib/x86_64-linux-gnu/libjemalloc.so.2
Тесты не проводил. Просто по привычке )