У меня есть приложение на основе Laravel, которое работает поверх php 7.0
У меня проблема с работниками очереди php artisan queue:work --daemon в том смысле, что он со временем потребляет память.
Базовый код, который начинает обработку, выглядит так (показана только важная часть)
<?php
namespace App\Jobs;
class TaskCronJoib extends Job implements ShouldQueue
{
use InteractsWithQueue, SerializesModels;
private $type;
public function __construct(string $type)
{
$this->type = $type;
}
public function handle()
{
$handler = app()->make(HandlerFactory::class)->get($this->type);
$handler->process();
}
}
Я тестировал (и это работает), что когда я добавляю gc_collect_cycles () в конце handle(), со временем он потребляет гораздо меньше памяти.
Как это
Я тестировал (и это работает), что когда я добавляю gc_collect_cycles () в конце handle(), со временем он потребляет гораздо меньше памяти.
public function handle()
{
$handler = app()->make(HandlerFactory::class)->get($this->type);
$handler->process();
gc_collect_cycles();
}
Рабочие Laravel работают бесконечно, поэтому это обычный случай, когда каждый php-процесс работает 6 часов, а событие - 12 часов. Я использую php artisan queue:restart в crontab и супервизоре для периодического перезапуска процессов, чтобы в любом случае избежать потребления памяти.
TL; DR: почему добавление gc_collect_cycles () заставляет PHP намного меньше потреблять память?
Сборщик мусора включен по умолчанию
php -i | grep enable_gc
zend.enable_gc => On => On
НЕТ таких звонков, как gc_disable (); ini_set ('zend.enable_gc', ложь);






Насколько я могу судить, --daemon действительно является постоянным запросом, поэтому он не очищает память по умолчанию. Если handle () недолговечен, я бы подумал о queue:listen, так как это завершит запрос после завершения задачи, что автоматически освободит память. Если есть вероятность, что две из этих задач могут совпадать вместе (то есть очень длинные задачи, выполнение которых занимает много времени), то, вероятно, будет достаточно флага gc_collect_cycles () и --daemon.
Однако есть накладные расходы производительности, связанные с ручным сбросом циклов gc. Поэтому слишком частое выполнение этого может привести к снижению производительности - если handle () - недолговечный процесс, возможно, не стоит вводить gc_collect_cycles (). Зависит от архитектуры и того, что происходит в фоновом режиме. Если это недолговечный процесс, который быстро и постоянно вызывается, это может быть сценарий для сохранения постоянного демона и ручного сброса gc вместо начальной загрузки Laravel вверх и вниз. На самом деле просто зависит.
gc_collect_cycles () просто сбрасывает циклы с большей частотой, а не автоматически. Обычно для одиночных запросов он ожидает произвольного количества zval, 10 000, прежде чем он автоматически проверит, что можно выгрузить из корневого буфера. Или он автоматически обрабатывает его в конце запроса. Номер можно изменить через конфигурацию PHP и перекомпиляцию.
PHP 7.3 также внесет некоторые улучшения в сборку мусора (для определенных сценариев, но не в целом), поэтому обязательно обновите PHP, если это возможно.
Источники:
Я использую следующий код для удаления файла гостевого сеанса, который может помочь:
$c = 0;
$files = File::files(storage_path().'/framework/sessions');
foreach ($files as $f) {
$file_content = file_get_contents($f);
$arrFileData = unserialize($file_content);
$dtCreated = Carbon::createFromTimestamp($arrFileData['_sf2_meta']['u']);
$dtNow = Carbon::now();
$diffInHours = $dtNow->diffInHours($dtCreated);
//if file is older than 2h & not found 'login_web_' then remove file
if ($diffInHours > 2 && strpos($file_content, 'login_web_') === false) {
$c++;
@unlink($f);
}
}
echo "Clear unnecessary sessions: ".$c;