База отказывает под нагрузкой - слишком много соединений
Сайт то открывается, то отдаёт ошибку базы, а в журнале лежит строка «(1040) Too many connections». База жива и в спокойные часы отвечает мгновенно, но на пике отказывает части посетителей. Разбираем причины по убыванию частоты, начиная с соотношения пределов базы и веб-сервера.
С чего начать
Смотрим предел соединений и пик занятых:
SHOW VARIABLES LIKE 'max_connections'; -- сколько соединений база принимает разомSHOW STATUS LIKE 'Threads_connected'; -- занято прямо сейчасSHOW STATUS LIKE 'Max_used_connections'; -- пик с момента последнего запуска базы-- пик, равный пределу, означает отказы, даже если сейчас соединений немногоПик, дошедший до предела, подтверждает диагноз без гадания по журналам. Дальше важен другой вопрос: заняты соединения работой или простаивают, и он делит все причины ровно пополам.
Смотрим, чем заняты соединения:
SHOW FULL PROCESSLIST;-- Query и десятки секунд в поле Time: запросы висят и держат за собой очередь-- Sleep у большинства строк: слоты заняты процессами, которые ничего не спрашиваютДолгие строки Query называют виновника сами, и дорога дальше идёт в план выполнения запроса. Толпа строк Sleep говорит о другом: соединений открыто больше, чем базе есть чем занять.
Сверяем число процессов PHP с пределом базы:
grep -E 'pm.max_children|pm.max_requests' /etc/php-fpm.d/*.conf # сколько процессов поднимет PHPmysql -e "SHOW VARIABLES LIKE 'max_connections'" # сколько соединений примет база# каждый рабочий процесс держит своё соединение, поэтому предел базы обязан быть вышеВеб-сервер, поднимающий больше процессов, чем принимает база, отказывает сам себе. Запас считают с учётом cron, обмена с учётной системой и консольных скриптов, а не впритык к числу посетителей.
Правим предел так, чтобы правка пережила перезагрузку:
grep max_connections /etc/mysql/conf.d/bvat.cnf # BitrixVM пишет сюда сам, по объёму памятиprintf '[mysqld]\nmax_connections = 200\n' > /etc/mysql/conf.d/z_bx_custom.cnfsystemctl restart mysqld # свои значения кладут только в z_bx_custom.cnfФайл окружения перезаписывается по шаблону памяти, и правка в нём пропадает после ближайшей перезагрузки. Каждое соединение стоит оперативной памяти, поэтому предел поднимают вместе с замером её свободного остатка.
Проверяем режим соединения в настройках сайта:
// /bitrix/.settings.php, секция connections'options' => 2, // 2 - отложенное соединение, оно устанавливается при первом запросе// 1 - PERSISTENT: соединение не закрывается после запроса и держит слот базы занятым$db = \Bitrix\Main\Application::getConnection('external'); // второе соединение того же хитаОтложенный режим - значение по умолчанию для базы, и менять его без причины не стоит. Второе подключение внутри одного хита удваивает расход слотов, поэтому запас по пределу считают сразу на все соединения проекта.
Причины
-
Предел базы ниже, чем число рабочих процессов веб-сервера примерно 30% случаев
ПризнакОтказы приходят ровно на пике, а в остальные часы сайт работает ровно.
ПроверкаСравниваем число рабочих процессов PHP с пределом соединений в настройках самой базы.
Что делатьПоднимаем предел выше числа процессов и оставляем запас на cron и обмен.
-
Долгие запросы держат соединения, и очередь растёт лавиной примерно 25% случаев
ПризнакОтказы начинаются не сразу, а через минуту после всплеска посещений.
ПроверкаСмотрим список соединений: у висящих строк состояние Query и десятки секунд.
Что делатьЧиним сам запрос индексом или переписыванием, а не поднятием предела соединений.
-
Фоновые задания и обмен идут одновременно с пиком посещаемости примерно 20% случаев
ПризнакОтказы повторяются по расписанию: каждый час или в ночь полной выгрузки.
ПроверкаСверяем время отказов с расписанием cron и журналом обмена с учётной системой.
Что делатьРазводим тяжёлые задания по времени и уносим их в часы спада нагрузки.
-
Свой код открывает второе соединение и не закрывает его примерно 15% случаев
ПризнакЗанятых соединений вдвое больше, чем рабочих процессов у веб-сервера.
ПроверкаИщем в проекте свои подключения мимо секции connections и включённый режим PERSISTENT.
Что делатьБерём подключение только через точку входа ядра и оставляем отложенный режим.
-
Кэш выключен или сброшен целиком, и нагрузка ушла в базу примерно 10% случаев
ПризнакОтказы начались сразу после чистки кэша или правки настроек кэширования.
ПроверкаСмотрим, включено ли автокеширование компонентов и где лежит управляемый кэш.
Что делатьВозвращаем кэш и переносим его в память, чтобы снять с базы повторные чтения.
Частые вопросы
Почему после перезагрузки max_connections снова стал маленьким?
Веб-окружение подставляет значение по шаблону, исходя из объёма памяти сервера, и перезаписывает свой файл настроек. Свои значения кладут в отдельный файл z_bx_custom.cnf.
Поможет ли просто выставить max_connections побольше?
Ненадолго. Каждое соединение занимает память, а очередь из долгих запросов при большем пределе просто станет длиннее и добьёт сервер по памяти.
Нужно ли включать постоянные соединения?
Только осознанно. Значение по умолчанию для базы - отложенное соединение: оно устанавливается при первом запросе, а постоянное держит слот занятым всё время жизни процесса.
Почему сайт открывается через раз, а не падает совсем?
Соединения освобождаются и занимаются заново. Кто успел попасть в свободный слот, увидит страницу, остальные получат ошибку подключения.
Как понять, что виноват обмен с 1С?
По времени: отказы совпадают с началом выгрузки. Обмен идёт длинными транзакциями и держит соединения дольше обычных страниц сайта.
Смежное
- Запросы к базе - оглавление подтемы
- База данных: PostgreSQL, Redis, memcached, шардинг - секция connections и режимы соединения
- Медленный запрос к базе: поиск, план, индекс - что чинить, когда соединения держат долгие запросы
- Трекер SQL-запросов: счётчик запросов участка кода - сколько запросов делает своя страница
- Сайт не подключается к базе: причины по убыванию частоты - когда база не отвечает вообще
- MySQL server has gone away: причины по убыванию частоты - соединение было и оборвалось посреди работы
- Сайт тормозит: разбор причин по убыванию частоты - общий разбор, когда отказов ещё нет
- Вынос базы и кэша на отдельные машины - когда предела одной машины уже мало
- Агенты и cron: фоновые задачи сайта - как убрать фон с хитов посетителей
- Кеширование: автокеш, D7 Cache, тегированный кеш - чем снять с базы повторные чтения
- Настройка базы под нагрузку: буферы, движок, соединения - как поднять предел и буферы осознанно