Список участников MySql, заполненный записями "Сон", приводящих к "Слишком много подключений"?
Я хотел бы попросить вашей помощи по давней проблеме с соединениями php/mysql.
Каждый раз, когда я выполняю команду "SHOW PROCESSLIST", она показывает мне около 400 незанятых (Status: Sleep) подключений к серверу базы данных, возникающих на наших 5 веб-серверах.
Это никогда не было большой проблемой (и я не нашел быстрого решения), пока в последнее время количество трафика не увеличилось, и с тех пор MySQL неоднократно сообщает о проблемах "ко многим соединениям", даже если 350+ этих соединений находятся в "спящем режиме" государство. Кроме того, сервер не может получить соединение MySQL, даже если к этому же серверу есть спящие соединения.
Все эти соединения исчезают при переустановке сервера Apache.
Код PHP, используемый для создания соединений с БД, использует обычный модуль "mysql", модуль "mysqli", PEAR :: DB и Zend Framework Db Adapter. (Разные проекты). Ни один из проектов не использует постоянные соединения.
Повышение лимита соединения возможно, но не кажется хорошим решением, поскольку сейчас оно составляет 450, и в любом случае в каждый момент времени существует только 20-100 "реальных" соединений.
Мой вопрос:
Почему в состоянии сна столько подключений и как я могу это предотвратить?
- Обновление:
Число запросов Apache, выполняемых за один раз, никогда не превышает 50 одновременных запросов, поэтому я думаю, что есть проблема с закрытием соединения, или apache держит порт открытым без присоединенного phpscript или чего-то еще (?)
my.cnf, если это полезно:
innodb_buffer_pool_size = 1024M
max_allowed_packet = 5M
net_buffer_length = 8K
read_buffer_size = 2M
read_rnd_buffer_size = 8M
query_cache_size = 512M
myisam_sort_buffer_size = 128M
max_connections = 450
thread_cache = 50
key_buffer_size = 1280M
join_buffer_size = 16M
table_cache = 2048
sort_buffer_size = 64M
tmp_table_size = 512M
max_heap_table_size = 512M
thread_concurrency = 8
log-slow-queries = /daten/mysql-log/slow-log
long_query_time = 1
log_queries_not_using_indexes
innodb_additional_mem_pool_size = 64M
innodb_log_file_size = 64M
innodb_log_buffer_size = 8M
innodb_flush_log_at_trx_commit = 2
innodb_file_per_table
Ответы
Ответ 1
В принципе, вы получаете соединения в состоянии "Сон", когда:
- PHP script подключается к MySQL
- Выполняются некоторые запросы
- тогда PHP скрипт делает некоторые вещи, которые требуют времени
- и, наконец, заканчивается PHP скрипт
- что означает, что он отключается от сервера MySQL
Таким образом, вы, как правило, получаете много процессов в состоянии "Сон", когда у вас много процессов PHP, которые остаются на связи, и фактически ничего не делают на стороне базы данных.
Основная идея, поэтому: убедитесь, что у вас нет процессов PHP, которые работают слишком долго, или принудительно отключите их, как только они больше не нуждаются в доступе к базе данных.
Другое дело, что я часто вижу, когда на сервере есть некоторая загрузка:
- В Apache все больше запросов
- что означает, что многие страницы генерируют
- Каждый PHP script, чтобы сгенерировать страницу, подключается к БД и выполняет некоторые запросы
- Эти запросы занимают все больше времени, так как загрузка на сервере БД увеличивается.
- Это означает, что все процессы продолжают стекировать.
Решение, которое может помочь, - сократить время, в течение которого выполняются ваши запросы, - оптимизация самых длинных.
Ответ 2
Увеличение количества max-соединений не решит проблему.
Мы столкнулись с такой же ситуацией на наших серверах. Это то, что происходит
Пользователь открывает страницу/представление, которые подключаются к базе данных, запрашивают базу данных, все еще запрос (запросы) не были завершены, и пользователь покидает страницу или переходит на другую страницу.
Таким образом, соединение, которое было открыто, останется открытым и будет продолжать увеличивать количество соединений, если будет больше пользователей, подключающихся к БД и выполняющих что-то подобное.
Вы можете установить для MySQL interactive_timeout, по умолчанию это 28800 (8 часов) до 1 часа
SET interactive_timeout=3600
Ответ 3
Прежде чем увеличивать переменную max_connections, вы должны проверить, сколько у вас неинтерактивных соединений, запустив команду show processlist.
Если у вас много спящих соединений, вам нужно уменьшить значение переменной "wait_timeout", чтобы закрыть неинтерактивное соединение после нескольких раз ожидания.
- Чтобы показать значение wait_timeout:
ПОКАЗАТЬ СЕССИИ ПЕРЕМЕННЫЕ, КАК 'wait_timeout';
+ --------------- + ------- +
| Переменное_имя | Значение |
+ --------------- + ------- +
| wait_timeout | 28800 |
+ --------------- + ------- +
значение в секундах, это означает, что неинтерактивное соединение еще до 8 часов.
- Чтобы изменить значение переменной "wait_timeout":
SET session wait_timeout = 600;
Запрос в порядке, затронуто 0 строк (0,00 с)
Через 10 минут, если спящее соединение все еще спит, mysql или MariaDB прерывают это соединение.
Ответ 4
Итак, я запускал 300 PHP-процессов симулятивно и получал скорость от 60 до 90 в секунду (мой процесс включает в себя 3х запросов). Я поднял его до 400, и это упало примерно до 40-50 в секунду. Я бросил его до 200 и вернулся к 60 и 90 годам!
Поэтому мой совет любому, у кого есть эта проблема, - эксперимент с запуском меньше, чем больше, и посмотрите, улучшится ли он. Там будет меньше памяти и процессора, поэтому процессы, которые выполняются, будут иметь большую способность и скорость может улучшиться.
Ответ 5
Вышеуказанные решения, например, выполнить запрос
SET session wait_timeout=600;
Работает только до перезапуска mysql. Для постоянного решения отредактируйте mysql.conf и добавьте после [mysqld]:
wait_timeout=300
interactive_timeout = 300
Где 300 - это количество секунд, которое вы хотите.
Ответ 6
Хорошо, поэтому, пробовав каждое решение для решения этих точных проблем в блоге Wordpress, я мог бы сделать что-то действительно глупое или гениальное... Не зная, почему существует увеличение соединений Mysql, я использовал php script ниже в моем заголовке, чтобы убить все спальные процессы.
Поэтому каждый посетитель моего сайта помогает убивать спальные процессы.
<?php
$result = mysql_query("SHOW processlist");
while ($myrow = mysql_fetch_assoc($result)) {
if ($myrow['Command'] == "Sleep") {
mysql_query("KILL {$myrow['Id']}");}
}
?>