English Version

Глава 9. Загадочное исчезновение сервера.

Часто это выглядит так:

$php phpconf2009_3.php
string(26) "MySQL server has gone away"

Код:

$cat phpconf2009_3.php
<?php
mysql_connect('127.0.0.1:3351', 'root', '');
mysql_select_db('test');
mysql_query('set wait_timeout=1');
$query = 'SELECT 1';
sleep(3);
$result = mysql_query($query);
if (0 != mysql_errno())
    var_dump(mysql_error());
else
    while ($row = mysql_fetch_row($result))
        var_dump($row);
mysql_close();
?>

Перед тем как указать на причину возникновения ошибки мне бы хотелось обратить ваше внимание на несколько системных переменных MySQL сервера. Это переменные, отвечающие за timeout:

mysql> show variables like '%timeout%';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| connect_timeout            | 10    |
| interactive_timeout        | 28800 |
| net_read_timeout           | 30    |
| net_write_timeout          | 60    |
| wait_timeout               | 28800 |
+----------------------------+-------+

Ниже приведены их описания:

connect_timeout

Сколько ждать ответа сервера перед тем как выдать ошибку о том, что сервер не отвечает.

interactive_timeout

Сколько ждать активности от интерактивного клиента перед тем как разорвать соединение.

wait_timeout

Сколько ждать активности от любого клиента перед тем как разорвать соединение. Если клиент интерактивный и значение interactive_timeout отличается от wait_timeout, то будет использовано значение interactive_timeout.

net_read_timeout

Сколько времени MySQL сервер будет ждать ответа от клиента осуществляющего чтение. Например, клиент послал запрос SELECT и читает ответ сервера.

net_write_timeout

Сколько времени MySQL сервер будет ждать ответа от клиента осуществляющего запись. Например, клиент поылает запрос для обработки.

В приведённом выше примере проблема была в том, что мы ждали слишком долго для предварительно установенного маленького wait_timeout:

mysql_query('set wait_timeout=1');

установленный wait_timeout.

sleep(3);

время ожидания: 3>1, поэтому не удивительно, что мы получили ошибку.

Естественно sleep(3) был добавлен только для наглядности. В случае реального приложения следует обратить внимания на места, где такая задержка может быть вызвана в том числе кодом без использования sleep и подобных функций.

Также проверяйте другие timeout-ы в случае аналогичных ошибок.

Приём №16: проверяйте значение wait_timeout и других timeout-ов, если вы встречаете ошибку "MySQL server has gone away"

Также я хотела бы обратить ваше внимание на то, что вы не всегда получите сообщение "MySQL server has gone away" в случае слишком маленького timeout. Это также может быть сообщение «Lost connection to MySQL server at 'reading authorization packet'». Чаще всего такое сообщение говорит о проблеме с connect_timeout.

Для примера я не смогла найти сети с достаточными для повторения проблемы перебоями, поэтому применила отладчик.

Запускаем интерпретатор PHP под отладчиком gdb:

$gdb php

Устанавливаем breakpoint в клиентской функции MySQL C API:

(gdb) b wait_for_data
Breakpoint 1 at 0x4337a: file client.c, line 190.

Передаём имя файла с PHP скриптом интерпретатору:

(gdb) set args phpconf2009_3.php

Запускаем программу:

(gdb) run
Starting program: /usr/local/bin/php phpconf2009_3.php
Reading symbols for shared libraries .+.................................................................++.++ done
Breakpoint 1 at 0x204e435: file client.c, line 1861.
Reading symbols for shared libraries . done
Breakpoint 1, wait_for_data (fd=6, timeout=60) at client.c:195
195       ufds.fd= fd; client.c:1861
(gdb)

Когда интерпретатор останавливается ждём 11 секунд, что на 1 секунду больше предустановленного значения connect_timeout, затем вводим команду с (продолжить).

(gdb) c
Continuing.
PHP Warning: mysql_connect(): Lost connection to MySQL server at 'reading authorization packet', system error: 0 in /Users/apple/Documents/www_project/MySQL/Conferences/phpconf2009_3.php on line 2

Warning: mysql_connect(): Lost connection to MySQL server at 'reading authorization packet', system error: 0 in /Users/apple/Documents/www_project/MySQL/Conferences/phpconf2009_3.php on line 2

В результате иы получили ошибку «Lost connection to MySQL server at 'reading authorization packet'», что говорит о слишком маленьком connect_timeout

Что делать?

Проблемы с connect_timeout чаще всего свидетельствуют либо о нестабильной работе сети между клиентом и MySQL сервером, либо о том, что машина, на которой запущен MySQL сервер, перегружена.

Поэтому после того как вы проверили помогает ли увеличение timeout, попытайтесь найти и устранить реальную причину такого поведения, если это возможно.

Не увеличивайте connect_timeout без необходимости: никому не пронравится ждать слишком долго!

Приём №17: проверяйте значение connect_timeout в случае ошибки «Lost connection to MySQL server at 'reading authorization packet'»

Назад Содержание Вперёд



Автор 2009 Света Смирнова
COPYRIGHT © 2009 С.Смирнова и С.Ласунов
sveta_гав_js-client_точка_com