Сайт работал и внезапно перестал: вместо страниц — ошибка подключения к базе данных,
а в логе строка Too many connections. Через несколько минут всё снова
работает, потом падает опять.
Это классическая картина исчерпания лимита одновременных соединений с MySQL. Разберём, откуда берутся лишние соединения, как понять, кто их занимает, и что делать — не только поднимать лимит, но и убирать причину.
Что означает ошибка
У MySQL есть параметр max_connections — максимальное количество
одновременных подключений. Когда все заняты, новые запросы отклоняются
с ошибкой ERROR 1040: Too many connections.
Важно понимать: одновременных, а не всего. Обычное соединение живёт доли секунды. Проблема возникает, когда соединения либо появляются слишком часто, либо держатся слишком долго.
Первое: посмотрите, что происходит сейчас
Текущее состояние показывает список процессов MySQL:
SHOW FULL PROCESSLIST;
Смотрите на два столбца:
| Столбец | На что обратить внимание |
|---|---|
Time |
Сколько секунд выполняется запрос. Всё, что больше 5–10 секунд, подозрительно |
State |
Sending data, Copying to tmp table, Locked — признаки проблемных запросов |
Полезные команды для оценки ситуации:
-- сколько соединений разрешено
SHOW VARIABLES LIKE 'max_connections';
-- сколько занято прямо сейчас
SHOW STATUS LIKE 'Threads_connected';
-- пиковое значение с момента запуска
SHOW STATUS LIKE 'Max_used_connections';
-- сколько раз лимит уже упирался
SHOW STATUS LIKE 'Connection_errors_max_connections';
Если Max_used_connections вплотную приблизился к max_connections —
лимит действительно исчерпывается.
Нужна помощь с Битрикс?
Причина 1. Медленные запросы
Основной источник проблемы. Пока тяжёлый запрос выполняется десять секунд, его соединение занято. Десяток таких запросов — и лимит съеден.
Типичные виновники на сайте под Битрикс:
- выборка каталога без фильтра по
IBLOCK_ID; - умный фильтр без фасетного индекса;
- запросы по неиндексированным полям;
- выборка всех свойств элементов вместо нужных;
- агенты, обрабатывающие большие объёмы на хитах пользователей.
Найти их помогает лог медленных запросов:
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 2;
После этого в лог попадут все запросы дольше двух секунд — обычно там и обнаруживается пара конструкций, ответственных за всю нагрузку.
Причина 2. Отключённое кеширование
Каждая страница без кеша означает полный набор запросов к базе. При включённом кешировании компонентов та же страница отдаётся вообще без обращений к MySQL.
Что проверить:
- Не отключён ли кеш глобально в настройках главного модуля.
- Стоит ли у компонентов тип кеширования «Авто».
- Не отключено ли кеширование меню и хлебных крошек.
- Работает ли композитный сайт на посещаемых страницах.
Подробный разбор настроек — в статье Настройка кеширования в Битрикс. Это самый дешёвый способ снять нагрузку с базы: он не требует ни доступа к серверу, ни изменения кода.
Причина 3. Нагрузка от ботов
Поисковые роботы и парсеры способны создать нагрузку, сравнимую с наплывом посетителей. Особенно если обходят страницы фильтра каталога, где каждый URL — уникальная комбинация параметров и кеша для них нет.
Посмотрите в логе веб-сервера, кто заходил в момент падения:
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -20
Если один адрес дал тысячи запросов за минуту — это не пользователь.
Агрессивных парсеров ограничивают на уровне веб-сервера, а поисковым роботам
задают частоту обхода в robots.txt и в панелях вебмастера.
Причина 4. Соседи по хостингу
На виртуальном хостинге MySQL часто общий. Лимит может исчерпываться из-за чужого сайта, а страдают все.
Признак: нагрузка на ваш сайт обычная, запросы быстрые, но ошибка появляется регулярно и в разное время. Проверить самостоятельно это невозможно — нужен ответ поддержки хостинга.
Если картина подтверждается, вариантов два: перейти на тариф с выделенными ресурсами или сменить хостинг. Ориентиры по выбору есть в статье Выбор хостинга для Битрикс.
Причина 5. Соединения не закрываются
Самописный код, который открывает своё подключение к базе и не закрывает его, накапливает «висящие» соединения. Особенно опасны скрипты обмена и импорта, запускаемые по расписанию.
Признак — растущее число соединений в состоянии Sleep с большим значением Time.
Частично помогает уменьшение таймаута простоя:
SHOW VARIABLES LIKE 'wait_timeout';
Значение по умолчанию — 28800 секунд, то есть 8 часов. Для сайта это чрезмерно: разумное значение обычно в пределах 60–300 секунд. Но это лечение симптома — правильнее найти скрипт, который не закрывает соединение.
Поднятие лимита
Увеличение max_connections — не решение, а способ выиграть время.
Тем не менее иногда лимит действительно занижен:
[mysqld]
max_connections = 200
Помните, что каждое соединение потребляет память. Бездумное увеличение до тысячи приведёт к тому, что сервер начнёт уходить в своп, и вместо ошибки соединений вы получите общее замедление всего.
Правило простое: сначала уберите медленные запросы и включите кеш, и только потом, если нагрузка действительно выросла, поднимайте лимит.
Порядок действий при падении
- Посмотрите
SHOW FULL PROCESSLIST— какие запросы висят. - Если есть зависший тяжёлый запрос, снимите его через
KILL. - Проверьте лог веб-сервера: не бот ли создал наплыв.
- Убедитесь, что кеширование включено.
- Включите лог медленных запросов и посмотрите на них через сутки.
- Добавьте индексы или перепишите проблемные запросы.
- Только после этого рассматривайте повышение лимита.
Как предотвратить
- Держите кеширование включённым — это снимает большую часть запросов.
- Переведите агенты на cron. Агенты, работающие на хитах, добавляют нагрузку именно в моменты наплыва посетителей.
- Запускайте импорт и обмен ночью и по возможности порциями.
- Включите фасетный индекс, если используется умный фильтр.
- Настройте мониторинг числа соединений, чтобы видеть приближение к лимиту заранее, а не по факту падения.
Итог
Too many connections означает, что соединения с MySQL заканчиваются
быстрее, чем освобождаются. В основе почти всегда лежат медленные запросы,
отключённое кеширование или всплеск нагрузки от ботов.
Начинать диагностику нужно с SHOW FULL PROCESSLIST и лога медленных
запросов, а не с правки конфигурации. Поднятие max_connections
без устранения причины лишь отодвигает следующее падение и добавляет расход памяти.
