Мониторинг производительности приложения (Application Performance Monitoring или APM)
Модуль содержит API подписчика события, который позволяет приложениям отслеживать команды и внутреннюю активность,
которая относится к «Спецификации обнаружения и мониторинга серверов».
В этом руководстве будет продемонстрирован мониторинг команд
с помощью интерфейса MongoDB\Driver\Monitoring\CommandSubscriber.
Интерфейс MongoDB\Driver\Monitoring\CommandSubscriber
определяет три метода: commandStarted,
commandSucceeded и commandFailed.
Каждый из них принимает один параметр event класса,
соответствующего нужному событию. К примеру, commandSucceeded
принимает аргумент $event класса
MongoDB\Driver\Monitoring\CommandSucceededEvent.
В данном руководстве вы реализуем подписчика, который создаёт список
профилировок всех запросов и среднего времени их исполнения.
Класс подписчик Scaffolding
Мы начнём с шаблона для нашего подписчика:
]]>
Регистрация подписчика
Как только объект подписчика создан, необходимо его зарегистрировать
в системе мониторинга модуля. Регистрация производится методом
MongoDB\Driver\Monitoring\addSubscriber
или MongoDB\Driver\Manager::addSubscriber
для регистрации подписчика глобально или с помощью определённого класса Manager соответственно.
]]>
Реализуем логику
Теперь займёмся реализацией логики класа подписчика.
Для сопоставления двух событий, относящихся к успешно выполненной
команды (commandStarted and commandSucceeded), каждый объект события
предоставляет поле requestId.
Для записи среднего времени выполнения запроса мы начнём с
отслеживания команды find в событии commandStarted.
Мы будем добавлять элемент в массив pendingCommands
с индексом соответствующим requestId и значением, соответствующим
запросу.
Когда мы получим соответствующее событие commandSucceeded с соответствующим
requestId, мы добавим время выполнения (из
durationMicros) к общему времени и увеличим счётчик операций.
Если мы получим событие commandFailed, мы просто удалим соответствующую запись из
pendingCommands.
getCommand() ) )
{
$queryShape = $this->createQueryShape( (array) $event->getCommand()->filter );
$this->pendingCommands[$event->getRequestId()] = $queryShape;
}
}
public function commandSucceeded( \MongoDB\Driver\Monitoring\CommandSucceededEvent $event ): void
{
$requestId = $event->getRequestId();
if ( array_key_exists( $requestId, $this->pendingCommands ) )
{
$this->queryShapeStats[$this->pendingCommands[$requestId]]['count']++;
$this->queryShapeStats[$this->pendingCommands[$requestId]]['duration'] += $event->getDurationMicros();
unset( $this->pendingCommands[$requestId] );
}
}
public function commandFailed( \MongoDB\Driver\Monitoring\CommandFailedEvent $event ): void
{
if ( array_key_exists( $event->getRequestId(), $this->pendingCommands ) )
{
unset( $this->pendingCommands[$event->getRequestId()] );
}
}
public function __destruct()
{
foreach( $this->queryShapeStats as $shape => $stats )
{
echo "Shape: ", $shape, " (", $stats['count'], ")\n ",
$stats['duration'] / $stats['count'], "µs\n\n";
}
}
}
$m = new \MongoDB\Driver\Manager( 'mongodb://localhost:27016' );
/* Добавляем подписчика */
\MongoDB\Driver\Monitoring\addSubscriber( new QueryTimeCollector() );
/* Запускаем пачку запросов */
$query = new \MongoDB\Driver\Query( [
'region_slug' => 'scotland-highlands', 'age' => [ '$gte' => 20 ]
] );
$cursor = $m->executeQuery( 'dramio.whisky', $query );
$query = new \MongoDB\Driver\Query( [
'region_slug' => 'scotland-lowlands', 'age' => [ '$gte' => 15 ]
] );
$cursor = $m->executeQuery( 'dramio.whisky', $query );
$query = new \MongoDB\Driver\Query( [ 'region_slug' => 'scotland-lowlands' ] );
$cursor = $m->executeQuery( 'dramio.whisky', $query );
?>
]]>