PHP脚本限流的建议/技巧

7
我有一个定期运行脚本的计划任务(每小时一次)。该脚本与数据库和文件系统进行了大量交互,通常需要几分钟才能运行。问题是,当脚本运行时,服务器的cpu使用率会飙升,并减慢正常操作。有没有办法限制此进程,使其时间更长但不消耗太多资源?
我查看了不同的PHP配置选项,但似乎都不能满足我的需求。
将php.ini中的memory_limit设置为较低的值会导致我的数据对象很容易溢出。
我看过类似的帖子,在其中人们建议在脚本的某些点上使用sleep(),但这并不能防止脚本使服务器峰值。
最佳解决方案应该是告诉Lamp(在这种情况下是Wamp)堆栈仅使用10%的最大CPU利用率。如果它意味着每秒节省CPU周期,我完全不担心运行时间变长。我的备选解决方案是设置具有数据库复制的不同服务器,以便cron可以自由运行而不会减缓其他所有操作。
环境:Windows Server 2k3,Apache 2.2.11,PHP 5.2.9,MySQL 5.1
非常感谢您对此情况的任何见解。
编辑:感谢所有答案,即使是*nix特定的答案。我情况仍然很早,可以更改托管环境。希望这个问题将帮助其他人,无论操作系统如何。
9个回答

8
这是一个棘手的问题。如果您通过命令行运行PHP脚本,可以将进程的调度优先级设置为低(start /low php.exe myscript.php)。这可能会有所帮助,但如果您的PHP脚本实际上正在执行大部分占用CPU的处理工作,这个解决方法可能无效。根据您的情况,似乎MySQL的INSERT和UPDATE查询中有一个“LOW_PRIORITY”提示,这可能会对您有所帮助,但我没有尝试过。

3

UNIX(LAMP)中,我通过检查循环继续之前服务器的负载来解决了问题。

function get_server_load($windows = 0) {
    $os = strtolower(PHP_OS);
    if(strpos($os, "win") === false) {
        if(file_exists("/proc/loadavg")) {
         $load = file_get_contents("/proc/loadavg");
         $load = explode(' ', $load);
         return $load;
        }
        elseif(function_exists("shell_exec")) {
         $load = explode(' ', `uptime`);
         return $load;
        }
        else {
         return "";
        }
    }
}

for(... ... ...){
    $data = get_server_load(); 
    if($data[0] < 0.2){
     // continue
    }else{
        sleep(1);
    }
}

这个函数在Windows上也应该可以运行,但我不能保证。在Linux上,它会返回一个数组,其中包含最近1分钟、5分钟和15分钟的负载情况。

此外,考虑以较低的优先级(Linux中使用“nice”)启动脚本(如果通过CLI)。

在继续循环之前,您还可以使用其他值,例如Apache活动进程的数量(如果您在httpd.conf中启用了mod_status,则可以解析页面127.0.0.1/server_status?auto),或者MySQL的情况(活动连接?)。


3

2

您能修改cron条目,使用nice来启动您的脚本吗?


(说明:该段话询问用户是否可以使用nice命令来运行他们的脚本)

抱歉,看来你正在使用Windows系统。我被“lamp”和“cron”标签所迷惑了! - grossvogel
谢谢你的回答。无论如何,在我的情况下仍然有可能改变环境,所以我仍然觉得你的解决方案很有帮助。 - Mike B

2

不建议使用服务器为客户端提供服务并分析数据。

因此,如果您正在寻找最终解决方案,请对应用程序进行重新设计,并将数据分析从前端和实时数据库转移到专门用于此任务的另一个系统。

即使您可以成功地限制分析器的使用,它也会占用本应可用于为用户提供服务的宝贵资源。


1

这可能是一个困难的改变,但将数据结构重构为迭代器可能是值得的。此外,如果您的代码中存在循环引用,请提供一个像clearReferences()这样的方法来取消设置这些对象。顺便说一下,PHP 5.3已经解决了这个问题。

所以如果你有:

class Row
{
    protected $_table;

    public function __construct($table)
    {
        $this->_table = $table;
    }
}

class Table
{
    protected $_row;

    public function __construct()
    {
        $this->_row = new Row($this);
    }
}

在Row类中添加一个clearReferences()方法:
class Row
{
    public function clearReferences()
    {
        $this->_table = null;
    }
}

目前这就是我能想到的全部了。


1

我有一堆脚本,我以类似的方式使用nice从cron运行:

0 * * * * nice -n19 php myscript.php

这不会帮助RAM利用率(只有更改脚本编写方式才能做到这一点),但它只使用本来空闲的CPU。

编辑:没有看到问题涉及Windows环境,抱歉...对于任何*nix用户遇到相同问题的人,我将其保留在内。


1

也许你的脚本一次性尝试做太多事情了。如果它每小时运行三次,会不会做得更少?

另一个解决方案可能是设置一个额外的服务器,专门用于运行这种“后端”处理。如果它没有给数据库带来过多负载,只是网页服务器,那么这将特别有效。

另一种方法是看看它的工作是否可以朝不同的方向分解。这些脚本通常有几个大型SQL语句生成结果,用于生成许多小型SQL语句。如果后者可以放在某个地方,它们可以作为后续步骤运行到数据库中。这样的方法也可以让您使用未缓冲查询来获取预处理数据,这可以显著减少PHP代码的内存消耗。


0
如果您将其(Apache)作为服务运行,可以在Win控制中心/服务中更改优先级设置。 无论如何,您的CPU使用率都会飙升,但其他程序将首选调度程序。 还可以尝试将数据库/服务器放在与您的应用程序不同的硬盘上。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接