1.7 当服务器无响应的时候
有时候,MySQL客户端会收到严重的错误消息“在请求中丢失与服务器的连接”或者“服务器已停止”。尽管我希望你永远不会遇到这个错误,但是有所准备总是有好处的。由MySQL安装本身引起的这个问题主要有两个原因:服务器问题(最有可能是崩溃)或者滥用连接选项(通常是超时选项或者max_allowed_packet)。
第3章将讨论连接相关的配置。第4章会讨论硬件问题和第三方软件相关的问题。这里简短地介绍一下如果遇到服务器崩溃该做些什么。
首先,确定你的服务器是否真的崩溃。你可以借助进程状态监控器进行确认。如果你在服务器崩溃后运行了mysqld_safe或者其他守护进程重启服务器,错误日志将会包含表明服务器已经重启的消息。当mysqld启动时,它始终会在错误日志文件中输出类似如下的信息:
因此,如果你找到了类似消息,那么服务器已经重启了。如果没有任何消息,并且服务器已经启动并在运行,那么丢失连接的问题最有可能是因为滥用连接选项导致的,这将在第3章进行讨论。
提示 提示
如果你记得MySQL服务器原来是何时启动的,你可以使用状态变量uptime,该变量的值代表服务器已启动的时间,单位是秒:
该信息也可以帮你检查mysqld是否是因为操作系统的重启而失败的。仅需要比较该变量的值和操作系统的启动时间即可。
依赖于错误日志文件是因为我工作经历的原因,比如当客户在服务器崩溃数小时后发现问题,甚至有时候是在mysqld计划重启后才发现问题。
如果你确认服务器已经重启了,你应该再次检查错误日志去搜索崩溃本身的信息。通常,你会从错误日志中获取足够的崩溃信息,从而避免发生同样的情况。第6章将讨论如何调查你可能会遇到的少数困难情况。现在,我们再次回到错误日志文件,来看一下在服务器崩溃情况下的典型内容示例。这里我将摘录出大量信息:
表明崩溃原因的关键行是:
这意味着MySQL服务器在向操作系统申请资源(例如,访问文件或者内存)后终止了,得到了错误代码11。在大多数操作系统里,这个信号代表分段错误(segmentation fault)。你可以在你的操作系统的用户手册中获取更详细的信息。对于UNIX和Linux系统可以执行man命令。在Windows操作系统里,相似的情况通常会产生类似“mysqld got exception 0xc0000005”的日志消息。查找Windows的用户手册可以获取该异常代码的含义。
下面是从某个线程中导致服务器崩溃的请求的相关日志中提取的摘要信息:
为了进一步分析,重新执行查询来检查其是否是崩溃的原因:
提示 提示
当我推荐你重现错误的时候,我假定你是在开发服务器而不是生产服务器中进行的。6.3节将讨论如何安全地在特定环境下进行问题调优。请不要尝试重试示例中的语句,这是一个已知的bug#47780,已经在当前版本修复了。从5.0.88、5.1.41、5.5.0和6.0.14版本开始,该bug已经修复。
当目前为止,你已经找到并确认崩溃的原因,然而你还需要重写请求,从而避免下次服务器再次崩溃。现在,我们可以从日志的堆栈信息中获得帮助:
与错误相关的行是调用Item_subselect和Item_singlerow_subselect的部分:
我是如何确定这是罪魁祸首的呢?在这个示例中,我发现在之前排错过程中的调用。不过经验告诉我,最好还是从头开始排查问题。最前面的几个函数通常是操作系统调用的,这些函数可能会和问题相关,不过在当前环境下没有任何帮助,因为对它们你什么都做不了,接下来是对MySQL库的调用。自上而下地检查这些函数,以便找到哪些是与你相关的。例如,对于String4copy或Item_cache_str5store函数你没什么可做的,但是你可以重写子查询,因此我们从这里开始。
这里,哪怕不去看mysqld的源码,我们也可以找到崩溃的原因。推测子查询可能是问题的所在,这是一个不错的假设,因为子查询可以很容易地转换成JOIN。尝试重写查询然后测试它:
新查询并没有崩溃,因此你需要做的就是把应用程序中的查询改成等价的形式。
你刚刚学到了一些MySQL问题排查中的重要事情:当遇到未知的错误时首先应该做的是检查错误日志文件。始终要打开日志。
这里我想补充一点关于bug的内容。当你遇到崩溃并确定了原因的时候,应检查一下MySQL的bug数据库,看看有无类似的问题。如果你找到可能与你相关的bug,确认它是否修复了。如果已经修复了,那么把你的服务器升级到bug已修复的版本(或者更新的版本)。这样做可以节约你的时间,因为你不再需要修改有问题的语句了。
如果你没找到与你相关的bug,尝试下载最新的MySQL版本,然后再执行查询。如果bug再次出现,请把它提交给我们。使用最新的稳定版本是非常重要的,因为它包含当前修复的所有bug,许多老的问题在这里不会重现。第6章中会讨论如何在沙盒环境下安全地测试崩溃的情形。
不仅是特定的查询会引起崩溃,而且服务器运行的环境也有可能引起崩溃。最常见的原因就是缺少可用的内存(RAM)。特别当用户分配超大缓冲区时最容易发生。正如我之前提到的那样,mysqld始终需要比所有缓冲区容量总和略多的内存。通常情况下,错误日志文件包含可用内存的粗略估计。它看起来如下所示:
这种估计不是精确的,不过仍然值得确认。上面展示的信息表明mysqld可以使用高达20GB的内存。虽然现在你可以很容易地获得强大的计算机,但是仍有必要确认你是否真的拥有20GB内存。
该环境中的另一个问题是,有其他的应用程序与MySQL服务器一起运行。在生产环境中,最好为MySQL指定一台专门的服务器,因为其他应用程序可能会占用你希望MySQL使用的资源。第4章将讨论如何调试其他应用程序对mysqld的影响。