防止PHP脚本在运行时耗尽所有资源?

jov*_*van 15 php

我有一个每天的cron工作,大约需要5分钟才能运行(它会收集一些数据,然后进行各种数据库更新).它工作正常,但问题是,在这5分钟内,网站完全没有响应任何请求,HTTP或其他.

看起来cron作业脚本在运行时会占用所有资源.我在PHP文档中找不到任何帮助我的东西 - 如何让脚本知道只用掉50%的可用资源?我宁愿让它运行10分钟并在此期间让用户可以使用该站点,而不是让它运行5分钟并且每天都有用户抱怨停机时间.

我确信我可以想出一种方法来配置服务器本身来实现这一点,但我更喜欢在PHP中有一个内置的方法来解决这个问题.在那儿?

或者,作为计划B,我们可以在脚本运行时将所有用户请求重定向到静态停机页面(与现在发生的情况相反,这是页面无限期加载或最终超时).

Pau*_*ulV 6

你没有提到哪些资源是你的瓶颈;CPU、内存或磁盘 I/O。

但是,如果是 CPU 或内存,您可以在脚本中执行此操作:http : //php.net/manual/en/function.sys-getloadavg.php http://php.net/manual/en/function.memory -get-usage.php

$yourlimit = 100000000; 
$load = sys_getloadavg();
if ($load[0] > 0.80 || memory_get_usage() > $yourlimit) {
    sleep(5);
}
Run Code Online (Sandbox Code Playgroud)

要尝试的另一件事是在脚本中设置进程优先级。不过,这需要 SU,这对于 cronjob 来说应该没问题? http://php.net/manual/en/function.proc-nice.php

 proc_nice(50);
Run Code Online (Sandbox Code Playgroud)

我对两者进行了快速测试,它的工作原理很有趣,感谢您询问我也有这样的 cronjob 并将实施它。看起来 proc_nice 只会做得很好。

我的测试代码:

proc_nice(50);
$yourlimit = 100000000;
while (1) {
    $x = $x+1;
    $load = sys_getloadavg();
    if ($load[0] > 0.80 || memory_get_usage() > $yourlimit) {
        sleep(5);
    }
    echo $x."\n";
}
Run Code Online (Sandbox Code Playgroud)


Mar*_*ijn 5

普通脚本不能占用100%的资源,资源会分散在进程上.它可以减慢一切,但不会锁定所有资源(没有做一些时髦的东西).您可以通过top -s在命令行中进行提示,查看哪个进程占用了很多.

这导致得出结论,锁定所有进一步的过程.正如Arkascha评论的那样,您的数据库很可能被锁定.这个答案解释了你应该使用哪种表类型 ; 如果您没有将它设置为InnoDB,那么您至少在锁定表中可能需要它.

它也可能是磁盘I/O,如果您编写大文件,尝试将其拆分为较小的读/写或尝试将一些信息(例如,如果它是带有列表的文件)放入您的数据库(假设有空余的空间) ).

它也可能是CPU.要解决这个问题,您需要提高代码的效率.重新检查您的代码,看看您是否进行了繁重的操作并尝试将它们缩小.通常,您希望尽可能快地使用它,现在您希望它们尽可能轻量化,这会改变您编写代码的方式.

如果它仍然锁定,则需要进行调试.关闭大部分代码并检查锁定是否仍然发生.继续打开代码,直到你注意到锁定.然后修复它.试着弄清楚是什么让你如此费钱.只有少数脚本需要大量资源,现在是优化的时候了.一种选择可能是将其分成两个(或更多)步骤.运行一个准备/清理数据的cron,以及一个处理数据的cron.这些不必同步运行,它们之间可能有几分钟.

如果这不是一个选项,请对代码进行基准测试并尽可能地进行改进.如果您有大量查询,可以通过在重度查询中仅选择ID来改进,并使用第二个查询来获取数据.如果可以,使用数据库来过滤,排序和管理数据,不要在PHP中这样做.
我曾经实施的一次是每N次行动都要睡一觉.

如果您的脚本确实如此极端,另一种解决方案可能是将其移动到您网站上很少/没有访问者的时间.即使你消除了瓶颈,也没有人喜欢慢速的网站.

并且始终可以选择增加硬件.


NVR*_*VRM 5

这真的取决于你的环境.

如果使用unix base,则有内置工具来限制给定进程的cpu/priority.

你可以单独限制服务器或PHP,这可能不是你想要的.

您首先要做的是在单独的过程中分离您的任务.

popen这样的,但我发现将这个过程作为一个bash脚本更容易.让我们hugetask为这个例子命名.

#!/usr/bin/php
<?php
// Huge task here 
Run Code Online (Sandbox Code Playgroud)

然后从命令行(或cron)调用:

nice -n 15 ./hugetask
Run Code Online (Sandbox Code Playgroud)

这将限制日程安排.这意味着它会降低任务对其他人的优先级.该系统将完成这项工作.

您也可以直接从您的php中调用它:

exec("nice -n 15 ./hugetask &");
Run Code Online (Sandbox Code Playgroud)

用法:很好[OPTION] [COMMAND [ARG] ...]运行COMMAND,调整好的,这会影响进程调度.没有COMMAND,打印当前的好看.良好值范围从-20(最有利于过程)到19(最不利于过程).

要创建cpu限制,请参阅cpulimit具有更多选项的工具.

这就是说,通常我只是将一些usleep()放在我的脚本中,以减慢速度并避免创建数据漏斗.如果您在脚本中使用循环,则可以.如果你把你的任务放慢到30分钟来运行,那就不会有太多问题了.

另见proc_nice http://php.net/manual/en/function.proc-nice.php

proc_nice()按递增中指定的量更改当前进程的优先级.正增量将降低当前进程的优先级,而负增量将提高优先级.

并且sys_getloadavg还可以提供帮助.它将在最后的1,5和15分钟内返回系统负载的数组.在启动庞大的任务之前,它可以用作测试条件.或者记录平均值以找到发布大任务的最佳日期时间.这可能是令人惊讶的!

print_r(sys_getloadavg());
Run Code Online (Sandbox Code Playgroud)

http://php.net/manual/en/function.sys-getloadavg.php