Задать вопрос

OS не освобождает память. Что может быть?

Здравствуйте.

Есть около 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, результата также нет.

Что это может быть, куда копать? Почему одно и тоже программное обеспечение ведет себя по разному?
  • Вопрос задан
  • 849 просмотров
Подписаться 4 Средний 3 комментария
Пригласить эксперта
Ответы на вопрос 1
Изначально заметил, что серверы MySQL.... потребляют больше памяти, чем им выделено.
Во время аллокации памяти операционке до задницы, что там написано в конфигурационных файлов приложений, которые она обслуживает.

А сервер базы данных может при этом съесть 2 гигабайта (именно RES, не VIRT памяти)
Во-первых это не так много, если у тебя всего на сервере Physical Memory: 7.7G. Во-вторых, куда должна деваться оставшаяся память, для каких-то иных приложений? В-третьих, что там с разделом подкачки?

При запуске он потребляет 1.4 гигабайта (RES) памяти, если выполнить мягкую перезагрузку (graceful), то после "перерождения" процессов новые начинают потреблять 3 гигабайта (RES) памяти.
Тут возможен тот случай, что операционка не сразу сбрасывает страницы с данными, а думает, что они могут ещё пригодиться - вариант часы с двумя стрелками. Чтобы потом не лезть на диск за данными в случае возникновения ошибки отсутствия страницы в памяти, операционка не сразу сбрасывает недавние данные на диск.

Почему одно и тоже программное обеспечение ведет себя по разному?
Сам над этим вопросом голову ломаю: два одинаковых сервера брата близнеца, одинаковый дистрибутив, но, сука, становятся по разному. Или случай - ставишь драйвер для видеокарты на машину, где два диска с идентичными операционками (один про запас). На один становится как по маслу, на другой раком влезает, потом в итоге гробит всю систему.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы