【问题标题】:PHP script stops working suddenly without reasonPHP脚本无故停止工作
【发布时间】:2023-03-20 04:04:01
【问题描述】:

我正在运行一个大型 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,它会停止从while 向 PHP 循环提供记录吗?如果发生错误,它会导致整个脚本崩溃吗?它是否有任何使整个脚本崩溃的超时?

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


更新

我在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,可以这样吗?

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

【问题讨论】:

  • 您是否尝试检查 PHP、Apache 和 MySQL 日志?
  • @ualinker 是的,谢谢,我刚刚做了.. 问题已更新
  • Shutting down for system halt 是机器本身关闭时写入系统日志的内核消息。这当然也会终止您的脚本。这很可能不是您要查找的错误
  • 在这个文件(fastcgi.conf)中搜索并修改如下 Server type="application/x-httpd-php" CommandLine="C:\Program Files\Zend\bin\php -cgi.exe" ConnectionTimeout="60" RequestTimeout="60" StartProcesses="8" Impersonate="1" SetEnv="PHP_FCGI_MAX_REQUESTS=10000" SetEnv="PHP_FCGI_CHILDREN=1" SetEnv="PATH=?" SetEnv="TEMP=C:\Program Files\Zend\Core For Oracle\temp" SetEnv="PROCESSOR_IDINTITY=HPR92500212345" SetEnv="OS=?" SetEnv="SystemRoot=?" SetEnv="ComSpec=?" MinDynamicServers 8 MaxDynamicServers 16 IpcDir "C:\Program Files\Zend\temp"
  • 服务器类型="application/x-httpd-php" CommandLine="C:\Program Files\Zend\bin\php-cgi.exe" ConnectionTimeout="60" RequestTimeout="60" StartProcesses ="8" Impersonate="1" SetEnv="PHP_FCGI_MAX_REQUESTS=10000" SetEnv="PHP_FCGI_CHILDREN=1" SetEnv="PATH=?" SetEnv="TEMP=C:\Program Files\Zend\Core For Oracle\temp" SetEnv="PROCESSOR_IDINTITY=HPR92500212345" SetEnv="OS=?" SetEnv="SystemRoot=?" SetEnv="ComSpec=?" MinDynamicServers 8 MaxDynamicServers 16 IpcDir "C:\Program Files\Zend\temp

标签: php mysql linux apache shell


【解决方案1】:

还有其他很多我们普遍面临的问题。

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

【讨论】:

    【解决方案2】:

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

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

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

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

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

    【讨论】:

      【解决方案3】:

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

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

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

      jobs -l
      

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

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

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

      【讨论】:

      • 目前正在测试这个解决方案.. nohup 日志文件在哪里?万一发生什么事我可以查一下
      • 在我上面的表格中,这不是任何日志,但如果你想要日志,你可以将 php 执行的输出重定向到这样的日志文件:nohup php /home/cron.php >/home /logs.txt 2>&1 & 这样,如果 php 崩溃,我认为您将能够在 logs.txt 文件中捕获错误。
      • 经过几次尝试,我不得不应用你的方式并删除 ignore_user_abort 并且还采用 curl 如何在循环后关闭它,我让它工作现在已经大约 12 小时了,没有问题或其他一切似乎都很好,谢谢!
      【解决方案4】:

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

      2:您可以使用 multi curl handler 缩短 cURL 请求的长度

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

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

      【讨论】:

        【解决方案5】:

        首先我遇到了这个问题并解决了,但我想强调你的 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);
        

        【讨论】:

        • 你的回答似乎很有趣。阅读问题更新可能有助于猜测原因
        • 从命令行调用 php 脚本根本不涉及 apache。还有执行时间 1000
        • @MichelFeldheim 我不认为它的“命令行”字面意思..如果你读了这个问题,我说我从另一个 PHP 文件执行命令行,我猜这是与 apache 相关的
        • 我意识到它正在执行curl_exec 多次(3)然后关闭 curl,是否需要在每次打开 url 时关闭并启动新的 curl?
        【解决方案6】:

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

        所以你要做的是打开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/ 还可以

        【讨论】:

          【解决方案7】:

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

          【讨论】:

          • 我必须在每个循环记录上运行这个函数吗?
          • 你应该循环运行它。
          • @Licson 什么 Apache 配置属性定义了超时?它适用于 Apache 2.2 吗?
          【解决方案8】:

          您是否尝试过使用 nohup?

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

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

          【讨论】:

            【解决方案9】:

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

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2015-12-03
              • 1970-01-01
              • 2021-11-22
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多