MySQL.RU .:. Одобрено лучшими российскими программистами

Справочное руководство по MySQL

A.4.1 Что делать, если работа MySQL сопровождается постоянными сбоями

A.4.1 Что делать, если работа MySQL сопровождается постоянными сбоями

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

Сначала надо попробовать локализовать проблему. Определите, что происходит: то ли демон mysqld прекращает работу, то ли проблема связана с клиентом. Узнать, сколько времени сервер mysqld уже работает, можно, выполнив mysqladmin version. Если mysqld прекратил выполнение, то для выяснения причин можно изучить файл `mysql-data-directory/`hostname`.err' (see section 4.9.1 Журнал ошибок).

Причиной многих аварий MySQL являются поврежденные индексные файлы или файлы данных. MySQL обновляет данные на диске, используя системный вызов write(), после каждой команды SQL и до того, как клиент будет уведомлен о результате (однако при выполнении с delay_key_write это не так: записываются только данные). Отсюда следует, что данные не пострадают даже в случае аварийного завершения mysqld, поскольку ОС позаботится о том, чтобы те данные, которые не сброшены, были записаны на диск. Можно заставить MySQL сбрасывать все на диск после каждой SQL-команды, запустив mysqld с --flush.

Все это означает, что обычно таблицы не должны повреждаться; исключение составляют следующие случаи:

  • Кто-нибудь/что-нибудь убьет процесс mysqld или выключит машину посреди операции обновления.
  • Проявила себя ошибка в mysqld, вызывающая прекращение его выполнения посреди операции обновления.
  • Кто-нибудь работает с файлами данных или индексными файлами вне mysqld и при этом не делает блокировку таблиц как следует.
  • Если работает несколько серверов mysqld с одними данными на системе без пристойной поддержки блокировок файловой системы (обычно реализуется демоном lockd) или если выполняется несколько серверов со --skip-locking
  • Существует поврежденный индексный файл или файл данных, содержащий очень неправильные данные, которые вводят в заблуждение mysqld.
  • Проявила себя в коде записи данных. Это маловероятно, но в общем случае возможно. В этом случае можно попробовать изменить формат файла на соответствующий другому обработчику баз данных, используя ALTER TABLE на исправленной копии таблицы!

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

  • Избавьтесь от NULL в качестве значений по умолчанию (это можно увидеть в DESCRIBE table_name)
  • Используйте truncate() для округления всех отрицательных значений к ближайшему целому.
  • Остановите демон mysqld с помощью mysqladmin shutdown, выполните myisamchk --silent --force */*.MYI на всех таблицах и перезапустите демон mysqld. Этим гарантируется безошибочность исходного состояния (see section 4 Администрирование баз данных).
  • Используйте mysqld --log и попытайтесь определить по информации в журналах, не вызвано ли прекращение работы сервера каким-либо специфическим запросом. Около 95% всех ошибок обусловлены конкретными запросами! Обычно это один из последних запросов в журнальном файле непосредственно до перезапуска MySQL (see section 4.9.2 Общий журнал запросов). Если вы сумеете повторно вызвать отказ MySQL при помощи одного из запросов, даже когда таблицы были проверены непосредственно перед выполнением запроса, то возможна локализация ошибки и подготовка отчета об ошибке! see section 1.8.1.3 Как отправлять отчеты об ошибках или проблемах.
  • Попробуйте сделать контрольный тест, который мы могли бы использовать, чтобы воспроизвести проблему (see section E.1.6 Создание контрольного примера при повреждении таблиц).
  • Попробуйте выполнить входящий в поставку тест mysql-test и тесты производительности MySQL (see section 9.1.2 Пакет тестирования MySQL). Эти тесты должны довольно хорошо протестировать MySQL. Вы можете также добавить в тесты производительности код для имитации своего приложения! Тесты производительности можно найти в каталоге bench в поставке с исходными кодами или, в случае бинарной поставки, в подкаталоге sql-bench своего каталога инсталляции MySQL.
  • Попробуйте fork_test.pl и fork2_test.pl.
  • Если что-то пойдет не так, то собирать информацию о возможных ошибках будет значительно проще, если MySQL сконфигурирован для отладки. Переконфигурируйте MySQL, применяя configure с опцией --with-debug или --with-debug=full, и затем перекомпилируйте (see section E.1 Отладка сервера MySQL).
  • Конфигурирование MySQL в отладочном режиме приводит к включению безопасного распределителя памяти, который может находить некоторые ошибки. Помимо этого, отладочная версия выдает большое количество информации о том, что происходит.
  • Выясните, применены ли последние патчи для используемой операционной системы.
  • Используйте опцию --skip-locking к mysqld. На некоторых системах менеджер блокировок lockd не работает как следует; опция --skip-locking указывает mysqld не применять внешнюю блокировку (это означает, что нельзя выполнять два сервера mysqld на одних данных и что необходимо быть осторожным при использовании myisamchk, однако применение этой опции может принести большую пользу для целей тестирования).
  • Если возникнет ситуация, когда кажется, что mysqld запущен, но не отвечает, стоит попробовать выполнить mysqladmin -u root processlist. Иногда mysqld не является зависшим, даже если кажется, что это так. Проблема может быть в том, что все соединения используются, или, возможно, имеется некая внутренняя проблема с блокировками. mysqladmin processlist обычно способна установить соединение даже в таких случаях и выдать полезную информацию о текущем количестве соединений и их состоянии.
  • Выполните команду в отдельном окне mysqladmin -i 5 status или mysqladmin -i 5 -r для вывода статистики, пока будут выполняться другие запросы.
  • Попробуйте выполнить следующие действия:
    1. Запустите mysqld в gdb (или в другом отладчике). See section E.1.3 Отладка mysqld при помощи gdb.
    2. Запустите тестовые скрипты.
    3. Отобразите стек (backtrace) и локальные переменные на трех нижних уровнях. В gdb это можно сделать следующими командами после аварийного завершения mysqld внутри gdb:
      backtrace
      info local
      up
      info local
      up
      info local
      
      С помощью gdb можно также выяснить, какие имеются потоки (посредством info threads), и переключиться на определенный поток посредством thread #, где # - номер потока.
  • Попробуйте имитировать работу своего приложения с помощью Perl-скрипта, который бы вызвал аварийное завершение или неправильное функционирование MySQL.
  • Отправьте нам обычный отчет об ошибке (see section 1.8.1.3 Как отправлять отчеты об ошибках или проблемах). Любые подробности будут нелишними. Поскольку MySQL нормально эксплуатируется в очень многих местах, то, возможно, авария вызвана причиной, которая свойственна только вашему компьютеру (например, ошибка, связанная с вашими особенными системными библиотеками).
  • Если возникла проблема с таблицами, имеющими динамическую длину строк, и не используются столбцы типа BLOB/TEXT (а только столбцы типа VARCHAR), то можно попробовать изменить все VARCHAR на CHAR с помощью ALTER TABLE. Это заставит MySQL использовать строки фиксированного размера. Для строк фиксированного размера понадобится немного дополнительной памяти, однако они гораздо менее чувствительны к повреждениям! Сегодняшний код динамических строк без каких бы то ни было проблем эксплуатируется в MySQL AB по крайней мере 3 года, но в принципе строки динамической длины более подвержены ошибкам, поэтому данный рецепт, возможно, сможет вам чем-то помочь!