7

我正在运行一个 BIG PHP 脚本,它可能需要一整天才能完成它的工作,
这个脚本从 MySQL 数据库中获取数据并将其与 curl 一起使用来测试东西..它使用大约40,000条记录来完成它..
所以让它只要需要就在后台运行,我使用终端来执行它。在 PHP 脚本本身中,它具有这些设置,以确保它尽可能长时间地运行,直到它完成:

set_time_limit(0); // run without timeout limit

因为我从另一个单独的 PHP 脚本执行它,所以我使用这个函数

ignore_user_abort(1); // ignore my abort

因为直接从命令行执行它,它会给我两个选择..
1)等到脚本完成
2)取消整个过程

在搜索之后,有一篇文章给了我第三个选择,它通过创建一个外部 PHP 脚本来使用这个函数在后台执行主要的 BIG PHP 脚本,从而尽可能地在后台运行它:

exec("php bigfile.php");

这意味着我可以从浏览器正常打开此外部页面并无需担心退出它,因为ignore_user_abort它将使其在后台运行..这仍然不是问题

问题是..在一段未知时期之后,脚本停止工作..我怎么知道?我告诉它在一个外部文件中写入它工作的每条记录的当前日期时间,所以我每次都刷新到那个外部页面,看看它是否停止更新,

在一段未知的时间之后,它实际上无缘无故地停止了,脚本没有说停止或任何东西..如果发生任何错误,我告诉它跳过记录(没有任何错误发生,它们都在同一行工作,如果一个工作,然后一切都应该工作)

但是,我的主要疑问如下:

  • Apache有一个超时杀死它
  • 这不是在后台执行 PHP 脚本的正确方法
  • 在某个地方存在超时,无论是在 PHP 还是 Apache 或(MySQL!?
    这就是我最大的疑问所在。MySQL,它会停止向 PHP 循环提供记录while吗?如果发生错误,它会导致整个脚本崩溃吗?它是否有任何使整个脚本崩溃的超时?

如果这些都不适用,有什么方法可以记录脚本现在到底发生了什么?或者为什么会崩溃?任何详细的方式来记录一切?


更新

我在以下messages文件中找到了这个/var/log/

Dec 29 16:29:56 i0sa shutdown[5609]: shutting down for system halt
Dec 29 16:30:14 i0sa exiting on signal 15
Dec 29 16:30:28 i0sa syslogd 1.5.0#6: restart.
Dec 29 16:50:28 i0sa -- MARK --
            .....
Dec 29 18:50:31 i0sa -- MARK --
Dec 29 19:02:36 i0sa shutdown[3641]: shutting down for system halt
Dec 29 19:03:11 i0sa exiting on signal 15
Dec 29 19:03:48 i0sa syslogd 1.5.0#6: restart.

它说系统停止..我会尽量确保这可能是未来的崩溃和比赛时间,这可能是造成它的原因吗?为什么?memory_limit是 128M 而我有2GB服务器内存 ram,可能是这样吗?

PS:我手动重启了几次服务器..但是这个说shutdown and halt ?

4

9 回答 9

6

对于这种情况,我使用这样的成功 nohup 命令:

nohup php  /home/cron.php >/dev/null  2>&1 &

您可以在此之后检查脚本是否正在运行:

jobs -l

注意:当您使用 nohup 命令时,php 文件的路径必须是绝对的,而不是相对的。我认为从一个 php 文件调用另一个 php 文件只是为了防止执行在完成工作之前停止是不太优雅的。

外部参考: http ://en.wikipedia.org/wiki/Nohup

还要确保您的脚本中没有内存泄漏,这会使脚本在一段时间后因为“内存不足”而崩溃。

于 2012-12-30T11:40:41.337 回答
2

您是否尝试过使用 nohup?

exec("nohup php bigfile.php &");

如果您的主机允许使用 nohup 命令,则该命令应在后台运行,并且调用 exec 的脚本应立即继续。

于 2012-12-30T11:36:06.413 回答
1

Osa,你的 Apache 很可能已经杀死了这个,我可以详细介绍一下可能的原因,其他人肯定会这样做。我宁愿回答你的问题而不是你的问题,并建议你使用tmux你描述的任务(或者screen如果tmux不可用)。

所以你要做的就是打开tmux并从那里启动脚本。分离ctrl-b d并稍后重新连接tmux attach以查看它有多远。分离时,您可以在不停止的情况下注销。

对于其他内容的简短介绍tmux,您还不需要,但可以帮助您理解方法http://victorquinn.com/blog/2011/06/20/tmux/ 或更高版本 http://blog.hawkhost .com/2010/06/28/tmux-the-terminal-multiplexer/还可以

于 2012-12-30T11:33:49.133 回答
0

执行时间不是唯一需要考虑的事情。下一个可能的罪魁祸首是脚本超过 max_memory_limit

您是否检查/启用了错误记录?可能会默默地失败。

于 2012-12-30T11:32:20.770 回答
0

如果您使用 Apache,大约有 300 秒的超时。apache_reset_timeout();如果您不停止脚本,定期调用可以让脚本永远运行。

于 2012-12-30T11:38:16.583 回答
0

首先,我遇到了这个问题并解决了,但我想强调你的 MySQL 服务器不负责这个挂起只有你需要更改 Apache 中的一些设置。将以下这些行放在 PHP 文件的上面。

ini_set('max_execution_time', 1000);
ini_set('memory_limit', '50M');
set_time_limit(0); 

并且每个获取数据都应该使用:

$url_class = $URL_path;
//open connection
$ch_school_class = curl_init();
curl_setopt($ch_school_class, CURLOPT_URL, $url_class);
$result_school_class = curl_exec($ch_school_class);
//clean up
curl_close($ch_school_class);

//Each fetch like this 
$url_class = $URL_path;
//open connection
$ch_school_class = curl_init();
curl_setopt($ch_school_class, CURLOPT_URL, $url_class);
$result_school_class = curl_exec($ch_school_class);
//clean up
curl_close($ch_school_class);
于 2012-12-30T11:43:09.143 回答
0

1:考虑使用popen()pclose()等在外部运行 PHP 脚本。

2:您可以使用multi curl 处理程序缩短 cURL 请求的长度

3:如果可能的话,你应该尝试用不同的语言来做。众所周知,PHP 对于较大的任务相当慢。为什么要花一整天时间,最多只能在几个小时内完成(我说几个小时,因为它必须向 40,000 个不同的地址发出网络请求)

4:而且,正如许多其他人所说,如果可以,请尝试使用 nohup。

于 2012-12-30T11:55:23.453 回答
0

使用 ignore_user_abort 通过 apache 运行长时间运行的脚本是一种肮脏的方式。

最简单的方法是使用GNU screen,只需键入 screen ,您将连接到当前控制台内的新控制台,启动脚本然后使用ctrl-a d (此处为完整手册)从屏幕分离,屏幕将继续即使您与服务器断开连接也能正常工作。

要重新连接到您的屏幕,请使用screen -r,您将返回到正在运行的脚本。

最难的方法(也是最干净的方法)是重写你的脚本以作为系统守护进程工作,有很多库可以帮助你做到这一点,我建议你深入研究 pear 的守护进程库(这里有一个例子)。

至于内存限制问题(?),在决定更新 memory_limit 配置之前,您必须检查您的脚本消耗的内存是否比当前配置中写入的更多,制作一个简单的ps aux|grep php并查找RSS专栏,这就是你的脚本正在吃的所有内存。

于 2012-12-31T08:05:03.373 回答
0

我们通常会面临其他许多问题。

  1. 您失败的程序可能正在以不适当的用户权限连接到任何其他用户/服务/服务器。因为通常 web-php 使用的是用户 apache(centos) 或 www-data (在 ubuntu 中),它们不是执行 sudo list 的一部分。给予相关许可,然后尝试。
    1. 检查 php.ini 并检查 disabled_function 行:exec、shell_exec 或其他内容,删除/注释该行,然后尝试。
于 2018-01-17T08:47:56.267 回答