Здравствуйте.
Есть около 10 серверов, на части установлена CloudLinux 6 (это OS на базе CentOS 6), на части CentOS 6. Столкнулся с проблемой выделения и освобождения памяти.
Изначально заметил, что серверы MySQL (стоят версии MariaDB 10.2.17 и Percona 5.6.39 в зависимости от сервера) потребляют больше памяти, чем им выделено. Например, mysqltuner.pl может иметь следующий вывод (это тестовый сервер, буферы установлены на минимум):
-------- Storage Engine Statistics --------------------------------------- --------------------------
[-] Data in MyISAM tables: 284.6M (Tables: 8400)
[-] Data in InnoDB tables: 2.1G (Tables: 9416)
[-] Data in MEMORY tables: 0B (Tables: 62)
-------- Performance Metrics ---------------------------------------- -------------------------------
[-] Up for: 2m 34s (7K q [47.175 qps], 696 conn, TX: 23M, RX: 18M)
[-] Physical Memory: 7.7G
[-] Max MySQL memory: <b>562.8M</b>
[-] Other process memory: 2.2G
[-] Total buffers: 184.0M global + 2.9M per thread (100 max threads)
А
сервер базы данных может при этом съесть 2 гигабайта (именно RES, не VIRT памяти) спустя пару дней работы (либо можно просто запустить mysqltuner.pl несколько раз и обычно потребление уже выше заданного лимита). flush tables, caches не освобождают память.
Есть два решения данной проблемы - это установка
MALLOC_ARENA_MAX в значение от 1 до 4 (изначально данное значение для сервера с 8 ядрами имеет значение 64), в данной ситуации MySQL начинает потреблять память корректно. Также можно ставить
malloc_check_=3 (тоже помогает, данная переменная переводит glibc в старый режим работы с потоками). В системах стоит glibc 2.12 версии, зачем-то RHEL собирают его с параметром --enable-experimental-malloc, который и создает данные проблемы (изменение malloc_check_ как раз отключает данный режим). Второе решение, использование jemalloc (прописывается malloc-lib файла my.cnf).
В сети находил подобные проблемы, но часто там описывается неконтролируемый рост VIRT памяти на glibc 2.12, но никак не RES. Единственная похожая запись проблемы есть здесь
https://jira.mariadb.org/browse/MDEV-15344, а также находил на сайте bugs.mysql.com, но ссылку не сохранил. Если смотреть pmap -x, то видно много выделенных anon блоков по 10 и 64 мб. Интересный момент еще в том, что при запуске сервера через утилиту valgrind --leak-check=full --leak-resolution=med потребление памяти нормальное.
Данная
проблема не только с сервером базы данных, интересный момент есть и с веб сервером nginx. При запуске он потребляет 1.4 гигабайта (RES) памяти, если выполнить мягкую перезагрузку (graceful), то после "перерождения" процессов новые начинают потреблять 3 гигабайта (RES) памяти. Перевод на jemalloc также устраняет данное поведение.
Для диагностики я установил два новых сервера с идентичным объемом ресурсов и операционными системами, скопировал серверы базы данных и веб сервера, проблему воспроизвести не удалось. Я стал сравнивать все параметры sysctl, ядра, различий не было. Сделал проверку файлов всех пакетов через rpm-Va, а после и вовсе сделал yum reinstall * (что переустановило все пакеты), но проблема не исчезла на тестовом сервере и не появилась на двух специально установленных серверах. Пробовал отказывать и обновлять glibc, результата также нет.
Что это может быть, куда копать? Почему одно и тоже программное обеспечение ведет себя по разному?