简体   繁体   English

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

[英]How can I make PHP scripts timeout gracefully while waiting for long-running MySQL queries?

I have a PHP site which runs quite a lot of database queries. 我有一个运行了大量数据库查询的PHP站点。 With certain combinations of parameters, these queries can end up running for a long time, triggering an ugly timeout message. 使用某些参数组合,这些查询可能会长时间运行,从而触发丑陋的超时消息。 I want to replace this with a nice timeout message themed according to the rest of my site style. 我希望用一个很好的超时消息替换它,根据我的网站风格的其余部分主题。

Anticipating the usual answers to this kind of question: 预见到这类问题的常见答案:

  1. "Optimise your queries so they don't run for so long" - I am logging long-running queries and optimising them, but I only know about these after a user has been affected. “优化您的查询,以便它们不会运行这么长时间” - 我正在记录长时间运行的查询并对其进行优化,但我只是在用户受到影响后才知道这些查询。

  2. "Increase your PHP timeout setting (eg set_time_limit, max_execution_time) so that the long-running query can finish" - Sometimes the query can run for several minutes. “增加PHP超时设置(例如set_time_limit,max_execution_time),以便长时间运行的查询可以完成” - 有时查询可以运行几分钟。 I want to tell the user there's a problem before that (eg after 30 seconds). 我想告诉用户之前有问题(例如30秒后)。

  3. "Use register_tick_function to monitor how long scripts have been running" - This only gets executed between lines of code in my script. “使用register_tick_function监视脚本运行的时间” - 这只在我的脚本中的代码行之间执行。 While the script is waiting for a response from the database, the tick function doesn't get called. 当脚本等待数据库的响应时,不会调用tick函数。

In case it helps, the site is built using Drupal (with lots of customisation), and is running on a virtual dedicated Linux server on PHP 5.2 with MySQL 5. 如果它有帮助,该站点使用Drupal(具有大量自定义)构建,并且在PHP 5.2上使用MySQL 5在虚拟专用Linux服务器上运行。

There is no asynchronous mysql calls and no scope for forking lightweight threads. 没有异步mysql调用,也没有分支轻量级线程的范围。

While you could split your PHP code into two tiers and use a connection between them which you can invoke asynchronously, the problem with this approach is the DB tier will still try to run the query after the upper tier has given up on getting the results back - potentially blocking the DBMS for other users. 虽然您可以将PHP代码拆分为两层并在它们之间使用可以异步调用的连接,但这种方法的问题是,在上层已放弃获取结果后,DB层仍会尝试运行查询 - 可能阻止其他用户使用DBMS。 (you're more likely to get more frequent requests for pages which are timing out). (您更有可能获得更频繁的超时页面请求)。

You'll have the same problem if you push the timeout handling up into a reverse proxy sitting in front of the webserver. 如果将超时处理推送到位于Web服务器前面的反向代理中,则会遇到同样的问题。

The most sensible place to implement the timeout is the database itself - but AFAIK, mysql does not support that. 实现超时的最明智的地方是数据库本身 - 但是AFAIK,mysql不支持它。

So next option is building a proxy between the PHP and the database - this could be self-contained - generating 2 lighweight threads for each request (1 to run the query, 2nd as a watchdog to kill the first if it takes too long) - but this not only requires writing code in a lnaguage which supports lightweight threads, but also defining a protocol for communications with the PHP. 所以接下来的选择是在PHP和数据库之间构建一个代理 - 这可能是自包含的 - 为每个请求生成2个lighweight线程(1个用于运行查询,第2个用作监视器,如果它需要太长时间来杀死第一个) - 但这不仅需要在支持轻量级线程的lnaguage中编写代码,还需要定义与PHP通信的协议。

However taking a different approach to the proxy model - you could spawn a separate PHP process using proc_open and set the stdout stream to be non-blocking - that way your PHP can continue to run and check to see if the proxy has run the query. 但是对代理模型采用不同的方法 - 您可以使用proc_open生成单独的PHP进程并将stdout流设置为非阻塞 - 这样您的PHP可以继续运行并检查代理是否运行了查询。 If it times out, then as the parent of the proxy, it can signal it to shutdown (proc_terminate()) which should stop the query running on the database. 如果它超时,那么作为代理的父代,它可以发信号通知它关闭(proc_terminate()),这应该停止在数据库上运行的查询。

Certainly, it's going to mean a lot of development work. 当然,这意味着很多开发工作。

It may prove a lot simpler to set up one or more slave DBMS to run your slow queries against - potentially with smart load balancing. 设置一个或多个从DBMS以运行慢速查询可能会更加简单 - 可能具有智能负载平衡。 Or look at other ways of making the slow queries go faster - like pre-consolidation. 或者看看让慢速查询变得更快的其他方法 - 比如预先整合。

HTH HTH

C. C。

The connection handling docs are what you need. 连接处理文档是您所需要的。

Basically, you need to register a shutdown function using register_shutdown_function() . 基本上,您需要使用register_shutdown_function()注册关闭函数。 This function will be called whenever a script is finished, regardless of whether it has completed successfully, been cancelled by the user (ESC key), or has timed out. 无论脚本是否已成功完成,用户是否已取消(或已超时),脚本完成时都会调用此函数。

That shutdown function can then call the connection_status() function. 然后,关闭函数可以调用connection_status()函数。 If connection_status() returns 2 (TIMEOUT) and the previous page was the one that runs the troublesome query, you can redirect the user to a page saying "Sorry, but we're experiencing high server load right now." 如果connection_status()返回2(TIMEOUT)并且前一页是运行麻烦查询的页面,则可以将用户重定向到“抱歉,但我们现在正在经历高服务器负载”的页面 or whatever. 管他呢。

Is your server tuned with APC, Memcache, Boost and Drupal Cache? 您的服务器是否使用APC,Memcache,Boost和Drupal Cache进行了调整? Those are alternate routes that work very well. 那些是非常好的替代路线。

Otherwise, what kind of scripts are running in Drupal that would cause this? 否则,在Drupal中运行哪种脚本会导致这种情况? Just out of curiosity, are you running Views and Panels? 出于好奇,你在运行视图和面板吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 长时间运行的php脚本的内存注意事项 - Memory considerations for long-running php scripts 如何在Apache中创建一个长期运行的PHP进程? - How do I create a long-running PHP process in Apache? 如何在长时间运行的进程中防止浏览器超时? - How to prevent browser timeout in long-running processes? 长期运行的MySQL查询从Apache下的PHP运行:浏览器不输出结果,并保持“正在传输数据…” - Long-running MySQL queries run from PHP under Apache: browser does not output result and keeps “Transferring data…” 如何使长时间运行的PHP脚本立即显示成功消息? - How do you make a long-running PHP script display a success message immediately? 如何诊断长期运行的PHP curl请求 - How to diagnose long-running PHP curl requests PHP:在服务器强制执行时间限制时编写长时间运行的脚本 - PHP: Coding long-running scripts when servers impose an execution time limit 如何在长时间运行的脚本上保持 Apache 和 PHP 之间的连接有效? - How can I keep the connection between Apache and PHP alive on long running scripts? 在后台长时间运行的PHP任务 - Long-running PHP task in background 如何在运行长PHP脚本时清除内存? 尝试unset() - How can I clear the memory while running a long PHP script? tried unset()
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM