Почему запуск PHP скрипта под Apache на много медленее, чем под CLI?
У меня есть скрипт, который запускается раз в несколько минут и производит около миллиона записей в БД Redis. Скрипт запускается через Apache (т.е. по URL удаленным планировщиком задач). Я был удивлен, что такой скрипт работает очень долго, примерно со скоростью 1.6К комманд в секунду, хотя бенчмарки показывают скорость в ~250К комманд в секунду. Причем чем дольше работает скрипт, тем медленее он пишет в Redis. Памяти на сервере валом (да и в скрипте все оптимизированно). Долго проверял что не так с Redis, но потом запустил этот скрипт через консоль и о чудо, вместо обычных 550-600 секунд, скрипт отработал за 7 (!) секунд.
Теперь пытаюсь понять почему через Apache все так медленно работает?
Какие могут быть причины?
Как можно сделать профайлинг Apache?
Ктото сталкивался с подобной проблемой?
Конфиги PHP в Apache и CLI режимах одинаковые.
Apache: 2.4.29
Server: Ubuntu
PHP: 7.3
P.S. Предложения обновить пхп или изменить апаче на другой сервер - не интересуют. Хочу понять в чем проблема в данном случае.
Sand, Весь скрипт большой, нет смысла его приводить здесь, там много логики, время работы я засекал именно на функции отправки команд в Redis. Для этого используется библеотека Predis и вот такая обертка на Pipeline которая сбрасывает содержимое в Redis каждые 10К команд.
class PipelineBatchProxy implements \Countable
{
/** @var \Predis\Pipeline\Pipeline */
private $pipeline;
private $totalCounter = 0;
private $currentCounter = 0;
private $batchSize;
public function __construct(\Predis\Pipeline\Pipeline $pipeline, int $batchSize = 10000)
{
$this->pipeline = $pipeline;
$this->batchSize = $batchSize;
}
public function __call($method, $arguments)
{
$ret = call_user_func_array([$this->pipeline, $method], $arguments);
$isExecuted = false;
if ($method === 'execute') {
$isExecuted = true;
} else {
$this->totalCounter++;
$this->currentCounter++;
}
if ($this->currentCounter >= $this->batchSize) {
$this->pipeline->execute();
$isExecuted = true;
}
if ($isExecuted) {
$this->currentCounter = 0;
}
return $ret;
}
public function count(): int
{
return $this->totalCounter;
}
}
Краткий код для проверки можно написать примерно так:
$pipeline = new \PipelineBatchProxy($redis->pipeline());
for ($i = 0; $i < 1000000; ++$i) {
$pipeline->set('somekey'.$i, $i);
}
$pipeline->execute();
А можете подключить xdebug и попрофилировать скрипт или как-то ещё измерить время выполнения самого скрипта?
Судя по гигантской разнице во времени я бы заподозрил какую-то проблему с DNS, но это совсем пальцем в небо.
Очевидно что надо смотреть конфиги апача, сколько ему разрешено использовать оперы на процесс, и в каком режиме там работает пхп (обычный через модуль апача или как fpm).