如何在等待长时间运行的MySQL查询时优雅地使PHP脚本超时?

时间:2010-05-14 10:37:53

标签: php mysql drupal timeout

我有一个运行大量数据库查询的PHP站点。使用某些参数组合,这些查询可能会长时间运行,从而触发丑陋的超时消息。我想根据我网站风格的其余部分用一个很好的超时消息替换它。

预测这类问题的通常答案:

  1. “优化您的查询,以便它们不会运行这么久” - 我正在记录长时间运行的查询并对其进行优化,但我只是在用户受到影响后才了解这些查询。

    < / LI>
  2. “增加PHP超时设置(例如set_time_limit,max_execution_time),以便长时间运行的查询可以完成” - 有时查询可以运行几分钟。我想告诉用户之前有问题(例如30秒后)。

  3. “使用register_tick_function监视脚本运行的时间” - 这只在我的脚本中的代码行之间执行。当脚本等待数据库的响应时,不会调用tick函数。

  4. 如果它有帮助,该站点使用Drupal(具有大量自定义)构建,并且在PHP 5.2上使用MySQL 5在虚拟专用Linux服务器上运行。

3 个答案:

答案 0 :(得分:3)

没有异步的mysql调用,也没有分支轻量级线程的范围。

虽然您可以将PHP代码拆分为两层,并在它们之间使用可以异步调用的连接,但这种方法的问题是,在上层放弃获取后,数据库层仍会尝试运行查询返回结果 - 可能会阻止其他用户使用DBMS。 (你更有可能得到更频繁的超时页面请求。)

如果您将超时处理推送到位于网络服务器前面的反向代理中,您将遇到同样的问题。

实现超时的最明智的地方是数据库本身 - 但AFAIK,mysql不支持。

所以接下来的选择是在PHP和数据库之间构建一个代理 - 这可能是自包含的 - 为每个请求生成2个lighweight线程(1个用于运行查询,第2个用作监视器以杀死第一个,如果它也需要但是这不仅需要在支持轻量级线程的lnaguage中编写代码,还需要定义与PHP通信的协议。

然而,对代理模型采用不同的方法 - 您可以使用proc_open生成单独的PHP进程并将stdout流设置为非阻塞 - 这样您的PHP可以继续运行并检查代理是否已运行查询。如果它超时,那么作为代理的父节点,它可以发信号通知它关闭(proc_terminate()),这应该停止在数据库上运行查询。

当然,这意味着很多开发工作。

设置一个或多个从属DBMS来运行慢速查询可能会更加简单 - 可能需要智能负载平衡。或者看看让慢速查询变得更快的其他方法 - 比如预先整合。

HTH

下进行。

答案 1 :(得分:0)

connection handling文档是您需要的。

基本上,您需要使用register_shutdown_function()注册关机功能。无论脚本是否已成功完成,用户是否已取消(或已超时),脚本完成时都会调用此函数。

然后,关闭函数可以调用connection_status()函数。如果connection_status()返回2(TIMEOUT)并且前一页是运行麻烦查询的页面,则可以将用户重定向到说“抱歉,但我们现在正在经历高服务器负载的页面。”< / em>或其他什么。

答案 2 :(得分:-1)

您的服务器是否使用APC,Memcache,Boost和Drupal Cache进行了调整?这些是非常好的替代路线。

否则,在Drupal中运行哪种脚本会导致这种情况?出于好奇,你在运行视图和面板吗?