Я хочу написать работника для beanstalkd в php, используя контроллер Zend Framework 2. Он запускается через CLI и будет работать вечно, требуя рабочих мест от beanstalkd, таких как this example.Вопросы памяти для длинных сценариев php
В простом псевдо-подобный код:
while (true) {
$data = $beanstalk->reserve();
$class = $data->class;
$params = $data->params;
$job = new $class($params);
$job();
}
$job
имеет здесь в __invoke()
метод конечно. Однако некоторые вещи на этих работах могут работать в течение длительного времени. Некоторые могут работать со значительным объемом памяти. Некоторые могли бы ввести объект $beanstalk
, сами начать создавать новые задания или создать экземпляр Zend\Di\Locator
для извлечения объектов из DIC.
Я беспокоюсь об этой установке для производственных сред в долгосрочной перспективе, так как, возможно, могут возникнуть круговые ссылки и (на данный момент) я не делаю «сбор» каких-либо мусора, пока это действие может выполняться в течение недель/месяцев/лет *.
*) В beanstalk reserve
является блокирующим вызовом, и если задание не доступно, этот работник будет ждать, пока он не получит ответ от beanstalk.
Мой вопрос: как PHP будет обрабатывать это в долгосрочной перспективе, и я должен принять любую специальную меру предосторожности, чтобы это не блокировалось?
Это я рассмотреть и может быть полезным (но, пожалуйста, поправьте, если я ошибаюсь, и добавить больше, если это возможно):
- Использование gc_enable() перед началом цикла
- Использование gc_collect_cycles() в каждой итерации
- Unset
$job
в каждой итерации - Явное неустановленных ссылок в
__destruct()
от а$job
(NB: Обновление здесь)
Я несколько тестов с произвольными рабочими местами. Работы, которые я включил, были: «простые», просто установили значение; «longarray», создайте массив из 1000 значений; «продюсер», пусть цикл вводит $pheanstalk
и добавляет три очереди в очередь (так что теперь есть ссылка с задания на beanstalk); «locatoraware», где указывается Zend\Di\Locator
, и все типы заданий создаются (хотя и не вызываются). Я добавил 10 000 заданий в очередь, затем я зарезервировал все задания в очереди.
Результаты для "simplejob" (потребление памяти на 1000 рабочих мест, с memory_get_usage()
)
0: 56392
1000: 548832
2000: 1074464
3000: 1538656
4000: 2125728
5000: 2598112
6000: 3054112
7000: 3510112
8000: 4228256
9000: 4717024
10000: 5173024
выбирая случайную работу, измеряя то же самое, что и выше.Распределение:
["Producer"] => int(2431)
["LongArray"] => int(2588)
["LocatorAware"] => int(2526)
["Simple"] => int(2456)
Память:
0: 66164
1000: 810056
2000: 1569452
3000: 2258036
4000: 3083032
5000: 3791256
6000: 4480028
7000: 5163884
8000: 6107812
9000: 6824320
10000: 7518020
Выполнение кода сверху обновляется до этого:
$baseMemory = memory_get_usage();
gc_enable();
for ($i = 0; $i <= 10000; $i++) {
$data = $bheanstalk->reserve();
$class = $data->class;
$params = $data->params;
$job = new $class($params);
$job();
$job = null;
unset($job);
if ($i % 1000 === 0) {
gc_collect_cycles();
echo sprintf('%8d: ', $i), memory_get_usage() - $baseMemory, "<br>";
}
}
Как все замечает, потребление памяти в PHP не заемных средств и сведен к минимуму, но со временем увеличивается.
Это интересный вопрос, я добавил некоторые связанные исследования об использовании 'gc_collect_cycles' http://stackoverflow.com/questions/38850391/when-does-php-run-garbage-collection-in-long-running-scripts/ 38850392 # 38850392 – mcfedr