Используем менеджер памяти jemalloc и tcmalloc с Oracle MySQL на Debian 9

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

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


6 комментариев

  • Ответить qweqwe |

    Доброго.

    Спасибо за статью. Дополню, что в репах Дебиана версия jemalloc старая.
    Приходится качать и компилировать из сурсов.

  • Ответить Михаил |

    Всегда пожалуйста.

    Да, согласен с Вами, версия jemalloc старая в репо, но использовать ее в продакшене или собирать из исходников нужно после тестов производительности. В том же блоге перконы были тесты на разных версиях jemalloc и они различались по производительности. Так что не факт, что новая 5-я версия jemalloc лучше 3-ей применительно к MySQL.

  • Ответить Norm |

    Спасибо за инфу.
    Для mariadb — надо добавлять в /etc/systemd/system/mysql.service.d/
    Для Ubuntu — строку «AmbientCapabilities=CAP_SYS_NICE» нужно убрать.
    А можно подключить jemalloc к php и nginx?
    Если да — то как?

  • Ответить Михаил |

    А можно подключить jemalloc к php и nginx?
    Если да — то как?

    Можно, только для nginx не вижу профита в jemalloc.

    Но если хочется, то для Debian 9 в
    /lib/systemd/system/nginx.service.d/limit.conf (проверьте какие файлы у вас есть в /lib/systemd/system/nginx.service.d или если каталога нет, то создайте его) пишем:

    [Service]
    Environment='LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.1'
    

    потом

    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 добавляете строки:

    [Service]
    Environment=LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.1
    

    потом

    systemctl daemon-reload
    systemctl restart php7.0-fpm
    

    проверяем

    lsof -n | grep [j]emalloc | grep php
    

Хотите оставить комментарий?