← Все статьи

SiteGuard12 мин чтения

MySQL server has gone away: как найти причину разрыва соединения

Приложение уже работало с базой, но очередное обращение завершилось ошибкой MySQL server has gone away или Lost connection to MySQL server during query. После обновления страницы всё может восстановиться, а через несколько часов проблема повторяется. В другом случае обрыв возникает только при большой выгрузке или сохранении объёмного документа. Одинаковое сообщение не означает одинаковую причину.

Здесь рассматривается потеря уже установленного соединения. Цель диагностики — установить момент разрыва, сопоставить события клиента и сервера и безопасно определить судьбу прерванной операции. Увеличивать все таймауты и повторять запись до успеха нельзя: первое может скрыть неисправность, второе — создать дубли.

Сначала определите, на каком этапе исчезло соединение

Руководство MySQL 8.4 различает клиентские ошибки CR_SERVER_GONE_ERROR и CR_SERVER_LOST. В первом случае клиент не смог отправить команду, во втором не получил полный ответ после передачи без обнаруженной ошибки записи. Это описание наблюдения со стороны клиента, а не готовый диагноз состояния базы.

Момент обнаруженияЧто проверить первымЧего это ещё не доказывает
Первый запрос после долгой паузыПростой сессии, срок хранения соединения в пуле, промежуточный проксиЧто сервер сейчас недоступен всем клиентам
Передача большой командыРазмер пакета, клиентские ограничения, сетевой сбойЧто достаточно увеличить только серверный предел
Ожидание результата или чтение строкТаймаут драйвера, состояние запроса, объём ответаЧто запрос ничего не выполнил
Ожидание подтверждения записи или COMMITИдентификатор операции и её подтверждённый результатЧто транзакция обязательно откатилась

Сохраните исходный код ошибки, SQLSTATE и сообщение драйвера. Переведённая фраза «база недоступна» теряет полезные различия. При этом одинаковые ошибки на разных операционных системах и библиотеках могут проявляться на разных этапах обнаружения разрыва, поэтому одного текста недостаточно.

Какие сведения собрать до изменения настроек

Для одной воспроизводимой попытки зафиксируйте время с часовым поясом, узел приложения, адрес выбранного сервера базы, версию драйвера, идентификатор соединения и этап операции. Запишите время последнего успешного обращения через эту сессию и время начала проблемного запроса. Это помогает отличить возраст соединения от длительности его простоя.

Добавьте безопасное описание запроса: тип операции, размер передаваемых данных, ожидаемый объём результата и наличие транзакции. Полный SQL с персональными данными или секретами для первого разбора обычно не нужен. Идентификатор бизнес-операции полезнее, чем неограниченная запись всех значений в журнал.

Выясните масштаб: один воркер, один сервер приложения или все клиенты одновременно. Если пострадал только старый фоновый процесс, проверьте его пул и длительные паузы. Если в одну секунду разорвались соединения разных приложений, приоритет получают события сервера базы и общей сети.

Сопоставляйте часы систем. Расхождение времени может создать ложную картину, будто перезапуск произошёл после ошибки, хотя именно он прервал соединения. Отмечайте неизвестные интервалы явно, не заполняя их предположениями.

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

Чем wait_timeout отличается от interactive_timeout

Wait_timeout связан с ожиданием активности на соединении. При создании сессии его значение берётся из глобального wait_timeout либо interactive_timeout — в зависимости от типа клиента. Интерактивным считается клиент, который использует флаг CLIENT_INTERACTIVE при подключении. Наличие пользователя перед экраном или слова «интерактивный» в названии приложения этого не определяет.

Для диагностики узнайте, с какими параметрами подключается фактический драйвер. Не рассчитывайте, что изменение interactive_timeout автоматически исправит веб-приложение. Проверяйте эффективный session wait_timeout именно у его соединения, а не у отдельно открытой административной консоли.

Длительный выполняющийся запрос и простаивающая сессия — разные состояния. Если SQL работает несколько минут, это само по себе не означает превышения idle-таймаута. Если же воркер открыл соединение, затем долго вычислял данные вне базы и только после этого обратился к ней, сервер действительно мог видеть паузу.

Не держите незавершённую транзакцию во время длительного внешнего вызова без необходимости. Помимо риска разрыва, такой сценарий усложняет восстановление: приложение связывает судьбу одной сессии с чужим сетевым ответом, время которого не контролирует.

Почему изменение GLOBAL не исправляет старый пул

MySQL разделяет глобальные и сессионные значения. Для соответствующих параметров начальное состояние сессии формируется при подключении. Поэтому изменение глобального wait_timeout не переписывает автоматически wait_timeout уже существующих соединений. Пул способен продолжать выдавать старые сессии с прежним поведением.

Ниже приведены запросы только для чтения, иллюстрирующие проверку. Их следует выполнять в разрешённой диагностике нужной сессии; подключение из другого клиента покажет состояние другого соединения.

SELECT
  CONNECTION_ID() AS connection_id,
  @@GLOBAL.wait_timeout AS global_idle_seconds,
  @@SESSION.wait_timeout AS session_idle_seconds,
  @@GLOBAL.interactive_timeout AS global_interactive_seconds;

SELECT
  @@GLOBAL.max_allowed_packet AS global_packet_bytes,
  @@SESSION.max_allowed_packet AS session_packet_bytes;

Если значения различаются, установите причину: сессия создана раньше изменения, приложение назначает свои параметры при подключении или запрос попал на другой узел. Не заменяйте проверку массовым перезапуском приложения без понимания последствий для выполняющихся задач.

План обновления пула должен учитывать активные транзакции. Выводите соединения из обращения предусмотренным библиотекой способом, затем подтверждайте настройки новых сессий. Отдельно проверяйте сохранение конфигурации после штатного перезапуска базы.

Учебный пример: сервер закрыл сессию раньше пула

Допустим, session wait_timeout равен 300 секундам, а приложение хранит простаивающее соединение в пуле до 600 секунд без проверки при выдаче. Других ограничений в учебном сценарии нет. Последняя работа с базой завершилась в 12:00:00.

ВремяСостояниеЧто видит приложение
12:00:00Соединение возвращено в пулУспешная последняя операция
Около 12:05:00Достигнут серверный предел простоя 300 секундПул может ещё хранить прежний объект
12:07:00Новый запрос получает старое соединениеПростой составил 420 секунд, ошибка обнаруживается сейчас

420 секунд больше серверных 300, но меньше настроенных в пуле 600. Это объясняет, почему ошибка появляется после паузы, хотя база уже принимает новые соединения. Проверка свежего подключения не опровергает неисправность повторного использования старого.

Исправление может включать своевременное удаление простаивающих соединений и проверку при выдаче, если это поддерживает библиотека. Пределы согласуют со всей цепочкой, включая прокси, и оставляют запас на задержки обслуживания пула. Проверка жизнеспособности уменьшает риск, но не гарантирует, что соединение не оборвётся сразу после неё.

Как проверить max_allowed_packet на обеих сторонах

По документации MySQL, слишком большой пакет может вызвать ошибку и закрытие соединения. Собственные ограничения есть у сервера и клиента. Пакетом в этом контексте может быть SQL-команда или отдельная строка результата; общий размер многорядной выгрузки не равен размеру одного такого пакета.

Проверяйте реальные данные после формирования запроса, экранирования и кодирования. Большой INSERT с множеством строк может оказаться существенно крупнее исходного файла. При чтении причиной иногда становится одна строка с объёмным BLOB, хотя запрос SELECT выглядит коротким.

В условном примере размер передаваемой команды составляет 26 МиБ, сервер допускает 64 МиБ, а клиент ограничен 24 МиБ. Увеличение только серверного значения ничего не изменит: 26 больше клиентских 24. Конкретное название и способ задания клиентского ограничения зависят от драйвера; настройка консольной программы mysql не настраивает автоматически библиотеку приложения.

Выберите обоснованный предел по измеренным законным запросам и доступным ресурсам. Иногда лучше уменьшить пакет обработки или изменить способ хранения крупных данных. Если разбиваете запись на части, заранее определите атомарность и восстановление после частичного успеха. Универсальное увеличение до максимального значения проблему не диагностирует.

Как отличить простой от перезапуска, crash или OOM

Если соединения исчезли одновременно у многих клиентов, проверьте журнал ошибок MySQL. Он содержит события запуска и завершения работы, а также диагностические сообщения. Сопоставьте их с журналами службы, контейнера, хостинга и операционной системы за тот же интервал.

Принудительное завершение из-за нехватки памяти может потребовать подтверждения в системных событиях или статусе контейнера: одного текста клиентской ошибки недостаточно для вывода об OOM. Отсутствие аккуратной записи о завершении тоже не доказывает конкретную причину. Разделяйте подтверждённый перезапуск и пока неизвестный механизм остановки.

Для проверки времени работы существует показатель Uptime, измеряемый в секундах. Иллюстративный запрос чтения:

SHOW GLOBAL STATUS LIKE 'Uptime';

Небольшое значение после массового обрыва согласуется с недавним запуском, но сначала убедитесь, что смотрите тот же сервер. Переключение на другой узел также меняет наблюдаемую историю. Сохраните свидетельства и найдите основание перезапуска: обслуживание, сбой процесса, ограничение ресурсов или действие автоматизации. Повторно запускать подозрительный тяжёлый запрос в рабочей базе ради доказательства не следует.

Сеть, прокси и клиентские таймауты: где заканчивается ожидание

Aborted_clients относится к уже установленным соединениям, которые завершились ненормально. Рост этого счётчика помогает увидеть проблему, но не определяет её источник: причиной может быть поведение клиента, простой или сбой обмена. Сравнивайте прирост за интервал, а не только накопленное число.

Проверьте маршрут от процесса приложения до базы: сетевой прокси, балансировщик, туннель, NAT и ограничения управляемого сервиса. Сопоставьте время закрытия соединения и журналы сторон. Успешное соединение с ноутбука или другого сервера не подтверждает исправность маршрута проблемного воркера.

У клиента есть собственные ограничения ожидания. Например, MySQL C API предусматривает MYSQL_OPT_READ_TIMEOUT и MYSQL_OPT_WRITE_TIMEOUT. Их семантика относится к попыткам чтения и записи, поэтому нельзя автоматически считать любое значение точным общим пределом длительности SQL. Для используемого драйвера проверьте документированные повторы и таймауты.

На сервере net_read_timeout и net_write_timeout относятся соответственно к ожиданию данных от клиента и передаче клиенту. Эти настройки не заменяют idle wait_timeout. Долгая обработка запроса, медленное чтение большого результата и пауза между запросами требуют разных проверок.

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

Не путайте таймаут установления подключения с ожиданием ответа по уже открытой сессии. Проверьте также общий срок выполнения задачи в приложении: её отмена или завершение рабочего процесса может оборвать обмен независимо от настроек MySQL. Ищите первый сработавший предел, а не самую большую цифру в конфигурации.

Что делать, если разрыв произошёл во время записи

После отправки изменения возможны разные исходы: сервер не выполнил его, выполнил и не зафиксировал либо зафиксировал, но подтверждение потерялось. При обрыве во время COMMIT клиент может не знать, какой вариант произошёл. Поэтому ошибка соединения не должна автоматически превращаться в повторное создание заказа, списание или повтор всей транзакции.

Для InnoDB документация описывает откат последней незавершённой транзакции, когда сессия с отключённым autocommit заканчивается без явной фиксации. Но это не доказательство исхода конкретного потерянного COMMIT: сначала нужно установить, успел ли он выполниться. Уже подтверждённые ранее изменения не становятся отменёнными от последующего обрыва.

До отправки бизнес-операции назначайте устойчивый идентификатор, по которому можно проверить результат. После разрыва используйте новое исправное соединение и предусмотренный приложением способ сверки. Для проверки важен авторитетный источник актуального состояния: отсутствие записи на отстающей реплике не доказывает, что она не была сохранена на основном узле.

Не ищите операцию только по сумме и приблизительному времени. Такие признаки не отличают два законных одинаковых заказа. Проверка должна связывать конкретный идентификатор с ожидаемыми параметрами и подтверждённым состоянием выполнения.

Идемпотентность требует проектной реализации: уникального ключа в нужной области, согласованного сохранения результата и правил обработки конкурентного повтора. Она не возникает от одного повторного подключения. Внешние действия, например запрос платёжному провайдеру, проверяют отдельно по его идентификатору и договору API.

Даже отсутствие записи при первом повторном чтении может быть недостаточным основанием для немедленного повтора, если исходная операция ещё выполняется. Состояние «результат неизвестен» должно иметь отдельную процедуру разрешения.

В учебном сценарии операция demo-order-73 отправлена, затем ответ потерян. Повтор сохраняет тот же идентификатор логической операции; новый идентификатор означал бы уже другое намерение и мог бы обойти защиту от дублей. Сверка должна завершиться подтверждённым результатом либо контролируемым разбором, а не созданием ещё одного заказа «для надёжности».

Почему reconnect не продолжает прежнюю транзакцию

Описание reconnect в MySQL C API предупреждает о сбросе состояния: теряются временные таблицы, пользовательские переменные и подготовленные выражения, заново устанавливаются параметры сессии. Прежняя активная транзакция не переносится в новое соединение. Автоматическое переподключение в этой библиотеке по умолчанию выключено и помечено устаревающим; поведение конкретного клиента следует проверять отдельно.

Успешный запрос через новое соединение доказывает доступность новой сессии, но не завершённость старой операции. Если сервер ещё не обнаружил сетевой разрыв, прежняя сессия может некоторое время продолжать работу. Нельзя на основании reconnect считать все старые блокировки уже освобождёнными, а неподтверждённый COMMIT — обязательно отменённым.

Приложение должно явно инициализировать требуемые свойства новой сессии: кодировку, необходимые параметры и режим работы. Не продолжайте цепочку SQL с середины, если она опиралась на временную таблицу или ранее установленную переменную. Такую операцию возобновляют только по предусмотренному алгоритму после выяснения её результата.

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

Как выбрать исправление по собранным доказательствам

Сформулируйте вывод как проверяемую связь: конкретная сессия простаивала дольше своего предела; пакет превысил клиентское ограничение; процесс базы перезапустился в момент ошибок; промежуточный узел закрыл соединение по своему правилу. Такая формулировка задаёт ограниченное изменение и способ его проверки.

При старых соединениях согласуйте срок хранения и проверку пула. При слишком большом пакете измерьте требуемый размер и проверьте обе стороны. При restart или OOM работайте с подтверждённым источником остановки и ресурсами. При задержке ответа разберите запрос и путь передачи, прежде чем увеличивать ожидание.

Меняйте по одному существенному условию, если ситуация позволяет. Сохраните исходные значения и объяснение нового предела. Иначе исчезновение ошибки после одновременного изменения пяти параметров не покажет, что именно помогло и не вернётся ли проблема при другой нагрузке.

Короткий проверочный SELECT через свежую сессию полезен для проверки доступности, но не воспроизводит большой пакет, чтение объёмного результата или повторное использование соединения после паузы. Приёмочный сценарий должен сохранять существенные условия исходной ошибки. Иначе успешная проверка будет отвечать на более простой вопрос, чем поставленная задача.

Восстановление бизнес-процесса проверяйте отдельно от устранения технического обрыва. После исправления соединения могут остаться задачи с неопределённым результатом, незавершённые импорты и повторные попытки в очереди. Их нельзя автоматически считать безопасными для массового перезапуска.

Как проверить результат и обнаруживать повторение

В тестовой среде воспроизведите подтверждённый сценарий: паузу, большой допустимый пакет или контролируемую потерю соединения. Используйте синтетические записи. Проверка должна подтверждать не только отсутствие прежнего исключения, но и корректную обработку отказа, когда соединение всё же теряется.

  • Новая и ранее созданная сессии имеют ожидаемые параметры.
  • Пул не выдаёт заведомо просроченные соединения без предусмотренной проверки.
  • Предельные законные размеры запроса и строки результата проходят обе стороны.
  • Клиентская ошибка сопоставляется с сервером, соединением и бизнес-операцией.
  • Разрыв при записи не запускает бесконтрольный повтор заказа или транзакции.
  • После reconnect заново создаётся необходимое состояние сессии.
  • Неопределённые результаты сверяются по устойчивым идентификаторам.

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

Дополните внутреннюю диагностику внешним наблюдением за HTTP-доступностью сайта через SiteGuard. Состояние MySQL и результат операций проверяет команда приложения, а внешний сигнал помогает заметить, когда проблема отражается на доступности веб-узла.