脚本/队列内存不足

时间:2017-10-23 15:48:37

标签: php laravel-5 redis push-queue

我的应用程序在用户请求时需要处理大量数据。该脚本最初是在foreach循环中组织的,但每次都会导致PHP超时。我开始使用Redis队列,但后来我遇到了内存问题。

mmap() failed: [12] Cannot allocate memory

PHP Fatal error:  Out of memory (allocated 79691776) (tried to allocate 134217728 bytes) 

现在我将队列设置为只有一个进程。它工作得更好,但一段时间后我又开始得到内存错误。这只是我测试它。一旦用户开始使用它,它就会崩溃。

我将脚本分配为1024MB,因为如果我不单独使用它就会耗尽内存。我想知道在每次运行脚本以释放内存后是否可以执行某些操作。像未设置的变量?我看不出这会有什么帮助,因为脚本结束并且队列工作人员从头开始再次运行。

我正在使用带有2GB RAM的流浪汉机器(Homestead)

更新:

当我们执行调度员并经历10个联赛和10年时,回测开始。

Dispatcher class:

class Dispatcher
{
    use Attributes;
    use DataRetriever;
    public function runBacktest($token)
    {
        $authUserId = Auth::user()->id;
        $system = System::where('token', $token)->first();
        $this->getSystem( $authUserId, $system->id);
        foreach ($this->leagues as $league) {
            foreach ($this->years as $year) {
                BacktestJob::dispatch($authUserId, $system->id, $token, $league, $year);
            }
        }
    }
}

调度员执行作业:

class BacktestJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    private $token;
    private $league;
    private $year;
    private $authUserId;
    private $systemId;

    public $timeout = 10000;


    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct($authUserId, $systemId, $token, $league, $year)
    {
        $this->token = $token;
        $this->league = $league;
        $this->year = $year;
        $this->authUserId = $authUserId;
        $this->systemId = $systemId;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        $backtest = new Backtest;
        $backtest->init($this->authUserId, $this->systemId, $this->token, $this->league, $this->year);
    }
}

下面是主脚本的精简版,因为它做了很多:

public function init($authUserId, $systemId, $token, $league, $year)
    {
//      ini_set('memory_limit', -1);
        ini_set('max_execution_time', 300); //300 seconds = 5 minutes
        ini_set('memory_limit', '1024M'); // or you could use 1G
        $this->authUserId = $authUserId;
        $this->systemId = $systemId;
        $this->token = $token;
include(storage_path("app/matches/{$league->key}/{$year}.php"));
        $this->leagueResults[$league->key][$year] = collect($this->leagueResults[$league->key][$year]);
//Loops through the data - saves to new array
fwrite($file, serialize($backtest));

最初数据来自50MB的json文件。我用一个硬编码的PHP数组(文件大小100MB)替换了json文件。我知道较新的文件较大,但我认为不会,但json_decode会加快速度。

我还在脚本的末尾删除了一个数据库插入,但我希望它能留在原点,因为它会让我的生活更轻松。

1 个答案:

答案 0 :(得分:0)

好的,所以我通过分解数据文件解决了这个问题。因为我可以完全访问原始数据文件,并且我不需要为每个请求提供所有数据,所以我将其分解为大约50个较小的文件。

我对性能提升感到惊讶。从30多秒加上超时,它下降到不到2秒。大多数请求在不到一秒的时间内完成。