MySQL убит из-за памяти: буферный пул больше доступной памяти
Буферный пул InnoDB выделяется при запуске, и его размер задаётся настройкой. Если он больше доступной памяти, сервер либо не стартует, либо его убивает ядро. На небольших виртуальных машинах это самая частая причина внезапных падений после правки настроек.
Вероятные причины
По порядку: сверху то, что встречается чаще.
-
Размер буферного пула больше доступной памяти
Настройку часто копируют с более крупного сервера. Память выделяется при старте, поэтому падение происходит сразу или почти сразу.
-
Много соединений с большими буферами на соединение
Кроме пула есть буферы на каждое соединение: сортировки, объединения, чтения. При большом числе соединений они складываются и добивают память.
-
Ограничение памяти у службы ниже потребности
Если в unit-файле задан предел памяти, сервер убивают при его достижении, даже когда на машине память есть.
Диагностика
Команды идут в том порядке, в котором их стоит выполнять: каждая следующая проверяет то, что осталось после предыдущей.
Подтверждение, что процесс убило ядро из-за памяти.
journalctl -k -b --no-pager | grep -i "killed process"Память машины, предел службы и её пиковое потребление.
free -h && systemctl show mysql -p MemoryMax -p MemoryPeakСообщения сервера: при нехватке памяти он часто пишет о неудачном выделении.
sudo tail -40 /var/log/mysql/error.logРешение
Решение своё для каждой причины. Сначала определите, какая из них ваша, — иначе правки наложатся друг на друга.
- Почему происходит
- Настройку часто копируют с более крупного сервера. Память выделяется при старте, поэтому падение происходит сразу или почти сразу.
- Как проверить
-
Сравните настройку с памятью машины.
sudo grep -iE "innodb_buffer_pool_size|key_buffer" /etc/mysql/mysql.conf.d/*.cnf /etc/mysql/my.cnf 2>/dev/null free -h
- Как исправить
-
Установите размер пула в 50–70% памяти машины, оставив запас на остальные процессы и на соединения.
sudo systemctl restart mysql
- Почему происходит
- Кроме пула есть буферы на каждое соединение: сортировки, объединения, чтения. При большом числе соединений они складываются и добивают память.
- Как проверить
-
Посмотрите предел соединений и буферы.
mysql -e "SHOW VARIABLES LIKE 'max_connections'; SHOW VARIABLES LIKE '%buffer_size';" 2>/dev/null | head -20
- Как исправить
- Снизьте предел соединений или размеры буферов на соединение. Формула проста: память пула плюс предел соединений, умноженный на буферы, должны укладываться в машину с запасом.
- Почему происходит
- Если в unit-файле задан предел памяти, сервер убивают при его достижении, даже когда на машине память есть.
- Как проверить
-
Посмотрите предел и пиковое потребление.
systemctl show mysql -p MemoryMax -p MemoryPeak
- Как исправить
- Приведите предел в соответствие с настройками MySQL или уберите его: у базы уже есть свои механизмы ограничения.
Пример вывода
Буферный пул на 4 ГБ на машине с 2 ГБ памяти. Пример показательный: он собран на тестовой машине специально для этой страницы, а не взят из чужого журнала.
kernel: Out of memory: Killed process 5200 (mysqld) total-vm:4812480kB, anon-rss:1889024kB
systemd[1]: mysql.service: A process of this unit has been killed by the OOM killer.
systemd[1]: mysql.service: Failed with result 'oom-kill'.
Связанные ошибки
- Failed with result 'oom-kill' Состояние oom-kill: процесс службы убит из-за нехватки памяти. Как понять, упёрлись в предел службы или в память машины.
- signal=KILL (status=9/KILL) в systemd Процесс службы убит сигналом KILL. Кто мог его послать: OOM-killer, таймаут остановки systemd, администратор.
- status=204/MEMORY в systemd Код 204/MEMORY: systemd не смог выделить память при подготовке запуска службы. Что проверять на машине и в unit-файле.
- MySQL: Can't connect to local server through socket Клиент не находит unix-сокет MySQL: сервер не запущен, путь к сокету другой, каталог в /run не создан.
- MySQL: Can't open the mysql.plugin table и повреждение системных таблиц MySQL не запускается: недоступны или повреждены системные таблицы. Права на каталог данных, версия схемы, восстановление.
- MySQL: Too many connections База отказывает в новых подключениях: исчерпан max_connections или предел дескрипторов службы.
- A start job is running: загрузка висит на одной службе Загрузка останавливается с обратным отсчётом: служба не укладывается в таймаут. Как найти виновника и не ждать.
- Address already in use при запуске службы Порт или адрес уже занят: bind() failed (98: Address already in use). Как найти владельца порта и что делать с остатками прежнего процесса.
Где встречается чаще всего
Источники
- Документация MySQL: буферный пул InnoDB
-
systemd.resource-control(5)
MemoryMax= и поведение при достижении предела. -
Воспроизведено на тестовой машине, systemd 255 (Ubuntu 24.04)
Воспроизведено на машине с 2 ГБ памяти и пулом 4 ГБ.