Скрипт / очередь не хватает памяти

Мое приложение имеет огромный объем данных, которые необходимо обрабатывать всякий раз, когда пользователь запрашивает его. Первоначально скрипт был организован в цикле foreach, но это приводило к тому, что PHP каждый раз зависал. Я перешел на использование очередей Redis, но у меня возникли проблемы с памятью.

mmap() failed: [12] Cannot allocate memory

а также

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

Теперь я установил в очередь только один процесс. Это работает лучше, но через некоторое время я снова начинаю получать ошибки памяти. И это только я проверяю это. Как только пользователи начнут использовать его, он просто упадет.

Я выделяю сценарий 1024MB, потому что он просто не хватает памяти, если я не на одно использование. Мне интересно, могу ли я что-нибудь сделать после каждого запуска скрипта, чтобы освободить память. Как сбросить переменные? Я не понимаю, как это могло бы помочь, так как сценарий заканчивается и снова запускается с нуля работником очереди.

Я использую бродячую машину (Homestead) с 2 ГБ оперативной памяти

ОБНОВИТЬ:

Тестирование начинается, когда мы выполняем диспетчерскую проверку, и проходит через 10 лиг и 10 лет.

Класс диспетчера:

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));

Первоначально данные были извлечены из файла JSON размером 50 МБ. Я заменил файл json жестко закодированным массивом PHP (размер файла 100 МБ). Я знаю, что новый файл больше, но я предполагал, что не будет, хотя json_decode ускорит процесс.

Я также удалил вставку из базы данных в конце сценария, но я бы предпочел, чтобы она осталась, потому что это облегчит мою жизнь.

1 ответ

Решение

Итак, я исправил проблему, разбив файл данных. Поскольку у меня есть полный доступ к исходному файлу данных, и мне не нужны все данные в нем для каждого запроса, я разбил его на около 50 небольших файлов.

Я был удивлен увеличением производительности. От 30 с лишним секунд плюс время ожидания уменьшилось до 2 секунд. Большинство запросов выполнено менее чем за секунду.

Другие вопросы по тегам