Mysql server has gone away в кластере
Встретил проблему, с которой просто не знаю что делать дальше...
Итак, исходные данные:
Есть сайт (написан на базе osCommerce), который работает без проблем на одном веб сервере и локальной БД. В связи с увеличением количества пользователей и заказов владелец сайта решил сделать распределенную систему (2 веб сервера + mysql кластер на 2 сервера), чтобы поднять производительность системы. Вся эта система была поднята и настроена, но обнаружилась проблема: в админской части система часто выбрасывает 500 Internal server error. Происходит это только в админской части (админская и юзерская часть используют одни и те же параметры коннекта и общую библиотеку для обработки sql запросов) и совершенно произвольно (т.е. на одной и той же странице эта ошибка могла неожиданно появиться, а после рефреша исчезнуть). При этом в error-лог Апача записывалась ошибка типа:
[Wed Oct 10 21:20:10 2007] [error] Query call failed: MySQL server has gone away (2006)
Для исследования проблемы в библиотеке, которая обрабатывает все sql запросы, был включен лог всех запросов к БД, но лог никаких ошибок не зафиксировал. Все запросы обрабатывались этим кодом:
error_log(strftime(STORE_PARSE_DATE_TIME_FORMAT) . ' [' . $_SERVER['REQUEST_URI'] . '] ' . $query . "", 3, STORE_PAGE_PARSE_TIME_LOG);
$result = mysql_query($query, $$link) or tep_db_error($query, mysql_errno($$link), mysql_error($$link));
function tep_db_error($query, $errno, $error) {
error_log(strftime(STORE_PARSE_DATE_TIME_FORMAT) . ' [' . $_SERVER['REQUEST_URI'] . '] Error: #' . $errno . ' - ' . $error . "", 3, STORE_PAGE_PARSE_TIME_LOG);
die('<font color="#000000"><b>' . $errno . ' - ' . $error . '<br><br>' . $query . '<br><br><small><font color="#ff0000">[SCRIPT STOPPED]</font></small><br><br></b></font>');
}
Т.е. в лог записывается как сам запрос, так и ошибка (если она возникает). Однако в логе после нескольких дней работы сайта нет ни одной записи со словом Error, т.е. ошибок при обработке запросов в PHP не возникает. При этом было замечено, что время записей в error-логе Апача и в логе запросов никогда не пересекается — т.е. либо сайт работает без проблем (при этом пишется лог запросов из php), либо выбрасывает 500-ую ошибку (при этом пишется только лог Апача: Query call failed: MySQL server has gone away). Если происходит ошибка, то через некоторое время система снова начинает работать без каких-либо перезапусков Апача или mysql сервера.
Различные попытки поиграться с настройками mysql (увеличить таймаут, размер буфера запроса и т.п.) и php (использовать pconnect вместо connect) никаких результатов не дали — ошибка по-прежнему повторяется в произвольный момент времени и самопроизвольно исчезает. Также совершенно непонятно, откуда в логе Апача возникает ошибка "Query call failed: MySQL server has gone away", если никаких запросов в этот момент не делалось (что видно из лога запросов). Было предположение, что проблема связана с потерей физического коннекта между веб сервером и mysql сервером (т.к. в случае кластера это могут быть разные машины), однако в таком случае непонятно, почему эта проблема возникает только в админке и почему эта ошибка не фиксируется в логе запросов.
Подскажите, плз, в чем может быть проблема? У меня уже просто нет идей, в каком направлении рыть...
При обращении к google по второй ссылке находим
MySQL Server Has Gone Away Typically by the time you see it, something has gone terribly wrong and your output page is either blank or your server-side script completely crashed. Developers need to understand a MySQL connection is an open socket between two machines. It is not guaranteed the socket will stay alive. In fact, you should accept it as a fact that this socket will die unannounced and you must plan ahead by implementing rigorous error checking in your code.
По вашему же тексту понятно, что ошибка происходит не на уровне php скрипта, а реализации mysql_. Думаю, что нужно кластер смотреть. php тут не причём.
Различные попытки поиграться с настройками mysql (увеличить таймаут, размер буфера запроса и т.п.)а покажите какие параметры крутили?
Степаныч[досье] Да, я тоже читал эту статью, но основная ее идея в решении проблемы состоит в том, чтобы циклически посылать запрос из php до тех пор, пока ошибка "MySQL Server Has Gone Away" исчезнет (т.е. запрос либо будет выполнен успешно, либо mysql вернет другую ошибку). Но, как вы видите по логам, в php такая ошибка не возникает, поэтому в данном случае это не может решить проблему. Что было полезного в данной статье, так это то, что там перечислены возможные причины возникновения этой ошибки. Однако я не вижу ни одной, подходящей к моему случаю.
Dennis F. Latypoff aka funky_dennis[досье] Показать, к сожалению, не могу, т.к. это сервер клиента, и крутит параметры там только местный сисадмин. Но я попросил их прислать текущий my.cnf:
[client] port = 3306 socket = /var/run/mysqld/mysqld.sock [mysqld_safe] socket = /var/run/mysqld/mysqld.sock nice = 0 [mysqld] ndbcluster ndb-connectstring=195.64.134.69 skip-external-locking old_passwords = 1 key_buffer = 64M max_allowed_packet = 64M thread_stack = 256K thread_cache_size = 256K max_connections = 10000 query_cache_limit = 1048576 query_cache_size = 16777216 query_cache_type = 1 log-bin = /var/log/mysql/mysql-bin.log expire-logs-days = 20 max_binlog_size = 104857600 [mysqldump] quick quote-names max_allowed_packet = 64M [mysql] [isamchk] key_buffer = 46M [MYSQL_CLUSTER] ndb-connectstring=195.64.134.69
- Вашему местному сисадмину вредно пить пиво:
thread_cache_size = 256K означает, что mysql закеширует 256,000 тредов и не будет их прибивать.
в большинстве случаев достаточно 32.
- нету параметра wait_timeout.
Скорее всего у Вас используется постоянное соединение с mysql. По умолчанию wait_timeout = 28800 секунд (8 часов), Ваше приложение пыталось выполнить запрос спустя 8 часов после последнего запроса. При чем при создании соединения не указывался параметр reconnect. Могло такое произойти?
Возможные решения:
- не использовать постоянные соединения
- использовать постоянные соединения + указывать опцию reconnect при подключении
- использовать постоянные соединения, не указывать опцию reconnect, а добавить в конфиг wait_timeout = 1 год
Я не говорю, что конфигурация там оптимальна. Тем более что возможно, что данная конфигурация есть просто результат попыток сисадмина решить проблему с "MySQL Server Has Gone Away". Наверное, он увеличивал все, что только можно увеличить. Однако, как я понимаю, параметр thread_cache_size не должен влиять на потерю соединения с mysql сервером.
Насчет wait_timeout: проблема возникает не через 8 часов, а прямо в процессе работы с сайтом. Т.е. админ безо всяких проблем ходит по меню и страницам и неожиданно получает 500 Internal server error, а в лог Апача пишется [error] Query call failed: MySQL server has gone away (2006). Кроме того, я писал в моем первом посте, что постоянные соединения были отключены (и отключены сейчас), но проблема по прежнему повторяется. Так что это тоже не может быть причиной.
ну опцию reconnect хотя бы попробуйте как workaround
- еше стоит посмотреть логи mysql.
- случаем mysql по крону не перезапускается?
![[logo]](/site/images/logo.jpg)