B.3.3.3 如果 MySQL 持续崩溃该怎么办
每个 MySQL 版本在发布前都经过了多种平台的测试。这并不意味着 MySQL 没有 bug,但如果有 bug,应该很少且难以找到。如果你遇到问题,总是帮助你快速解决问题,如果你能找到确切的问题原因。
首先,你应该尝试找出问题是否是 mysqld 服务器崩溃还是你的客户端问题。你可以通过执行 mysqladmin version 来检查 mysqld 服务器已经运行了多长时间。如果 mysqld 已经崩溃并重新启动,你可能可以在服务器错误日志中找到原因。见 第 7.4.2 节,“错误日志”。
在某些系统上,你可以在错误日志中找到 mysqld 崩溃的栈追踪。注意,错误日志中写入的变量值可能不总是正确的。
如果您发现mysqld在启动时在 InnoDB 恢复过程中失败,请参阅第17.20.2节,“恢复故障排除”。
许多意外的服务器退出是由损坏的数据文件或索引文件所致。MySQL 在每个 SQL 语句执行后使用 write()
系统调用将文件写入磁盘(除非您启用了delay_key_write
系统变量,在这种情况下数据文件被写入,但索引文件不被写入)。这意味着,即使mysqld崩溃,操作系统也会确保未刷新的数据被写入磁盘。您可以强制 MySQL 在每个 SQL 语句执行后将所有内容写入磁盘,通过使用mysqld 命令行选项 --flush
。
前面的意思是,通常情况下,您不应该出现损坏的表除非以下情况之一发生:
-
MySQL 服务器或服务器主机在更新过程中被杀死。
-
您发现了mysqld 的bug,导致它在更新过程中崩溃。
-
某外部程序正在同时操作数据文件或索引文件,而没有正确锁定表。mysqld
-
您正在使用同一个数据目录的多个mysqld 服务,或者您在不支持文件系统锁定的系统上运行了多个服务,并且外部锁定已被禁用。
-
您遇到了崩溃的数据文件或索引文件,该文件包含非常损坏的数据,混淆了mysqld。
-
您发现了存储引擎代码中的bug。这不太可能,但至少是可能的。在这种情况下,您可以使用
ALTER TABLE
在修复后的表副本上更换存储引擎。
因为很难知道什么原因会导致崩溃,首先尝试检查是否其他人也遇到了相同的问题。请尝试以下几件事:
-
使用mysqld命令停止服务器,运行mysqladmin shutdown,从数据目录中运行myisamchk --silent --force */*.MYI来检查所有
MyISAM
表,然后重新启动mysqld。这样可以确保你从一个干净的状态运行。见第7章,MySQL 服务器管理. -
使用mysqld命令启动常规查询日志(见第7.4.3节,“常规查询日志”),然后尝试从日志中确定是否某个特定的查询杀死了服务器。通常,这是服务器重启前日志文件中的最后一个查询。见第7.4.3节,“常规查询日志”。如果你可以重复使用特定的查询杀死 MySQL,即使你在执行它前已经检查了所有表,那么你就找到了bug,应该提交一个bug报告。见第1.6节,“如何报告bug或问题”.
-
尝试创建一个可以重复问题的测试用例。见第7.9节,“调试 MySQL”。
-
尝试使用
fork_big.pl
脚本。它位于源代码分发的tests
目录中。 -
为调试 MySQL 配置使得如果出现错误时更容易收集信息。使用
-DWITH_DEBUG=1
选项重新编译 CMake,然后重新编译。见第7.9节,“调试 MySQL”。 -
确保已经应用了最新的操作系统补丁。
-
使用
--skip-external-locking
选项来mysqld. 在某些系统上,lockd
锁管理器不工作正常;--skip-external-locking
选项告诉mysqld不要使用外部锁定。 (这意味着您不能在同一个数据目录上运行两个mysqld服务器,并且如果使用myisamchk,需要小心。然而,这也许是一个测试的好机会。) -
如果mysqld似乎在运行但未响应,尝试mysqladmin -u root processlist。有时mysqld即使未响应也可能不是挂起的状态。问题可能是所有连接都在使用,或者存在一些内部锁定问题。mysqladmin -u root processlist通常即使在这些情况下也能建立连接,并提供当前连接数和状态的有用信息。
-
在另一个窗口中运行命令mysqladmin -i 5 status或mysqladmin -i 5 -r status,以在运行其他查询时生产统计信息。
-
尝试以下操作:
-
从gdb(或另一个调试器)启动mysqld。见第7.9节,“调试 MySQL”。
-
运行您的测试脚本。
-
打印回溯和局部变量的三个最低层次。在gdb中,您可以使用以下命令在mysqld崩溃时执行:
backtrace info local up info local up info local
使用gdb,您也可以使用
info threads
命令来检查存在的线程,然后使用thread
将线程切换到特定的线程,其中N
N
是线程ID。
-
-
尝试使用Perl脚本模拟您的应用程序,强制MySQL退出或不正常工作。
-
发送一个正常的错误报告。见第1.6节,“报告错误或问题”。因为MySQL对很多人有效,崩溃可能是您的计算机上唯一存在的问题(例如,相关于您的特定系统库)。
-
如果您遇到包含动态长度行的表问题,并且只使用
VARCHAR
列(不包括BLOB
或TEXT
列),可以尝试将所有VARCHAR
更改为CHAR
使用ALTER TABLE
。这样强制MySQL使用固定大小行。固定大小行需要一些额外空间,但对数据损坏更加容忍。当前动态行代码已经使用了几年,很少出现问题,但是动态长度行本质上更容易出错,所以尝试这个策略来看是否有帮助。
-
在诊断问题时,考虑硬件故障的可能性。硬件故障可能是数据损坏的原因。在排查硬件故障时,特别注意内存和磁盘子系统。