Мониторинг производительности приложения (Application Performance Monitoring, или APM)

Модуль содержит API-интерфейс подписчика события, который разрешает приложениям отслеживать команды и внутреннюю активность, которая относится к » Спецификации обнаружения и мониторинга серверов. Это руководство продемонстрирует мониторинг команд через интерфейс MongoDB\Driver\Monitoring\CommandSubscriber.

Интерфейс MongoDB\Driver\Monitoring\CommandSubscriber определяет три метода: commandStarted, commandSucceeded и commandFailed. Каждый из них принимает один параметр event класса, соответствующего нужному событию. К примеру, commandSucceeded принимает аргумент $event класса MongoDB\Driver\Monitoring\CommandSucceededEvent.

Руководство реализует подписчика, который создаст список профилировок каждого запроса и среднего времени, которое заняли запросы.

Класс-подписчик Scaffolding

Начнём с шаблона для подписчика:

<?php

class QueryTimeCollector implements \MongoDB\Driver\Monitoring\CommandSubscriber
{
public function
commandStarted( \MongoDB\Driver\Monitoring\CommandStartedEvent $event ): void {}

public function
commandSucceeded( \MongoDB\Driver\Monitoring\CommandSucceededEvent $event ): void {}

public function
commandFailed( \MongoDB\Driver\Monitoring\CommandFailedEvent $event ): void {}
}

?>

Регистрация подписчика

Как только объект подписчика создали, подписчика необходимо зарегистрировать в системе мониторинга модуля. Глобально подписчика регистрируют методом MongoDB\Driver\Monitoring\addSubscriber(), а для конкретного объекта класса Manager — методом MongoDB\Driver\Manager::addSubscriber().

<?php

\MongoDB\Driver\Monitoring\addSubscriber
( new QueryTimeCollector() );

?>

Реализуем логику

Теперь займёмся реализацией логики класа подписчика. Для сопоставления двух событий, относящихся к успешно выполненной команды (commandStarted and commandSucceeded), каждый объект события предоставляет поле requestId.

Для записи среднего времени выполнения запроса мы начнём с отслеживания команды find в событии commandStarted. Мы будем добавлять элемент в массив pendingCommands с индексом соответствующим requestId и значением, соответствующим запросу.

Когда мы получим соответствующее событие commandSucceeded с соответствующим requestId, мы добавим время выполнения (из durationMicros) к общему времени и увеличим счётчик операций.

Если мы получим событие commandFailed, мы просто удалим соответствующую запись из pendingCommands.

<?php

class QueryTimeCollector implements \MongoDB\Driver\Monitoring\CommandSubscriber
{
private
$pendingCommands = [];
private
$queryShapeStats = [];

/* Создаёт форму запроса из аргумента фильтра. Учитываются
* только поля верхнего уровня. */
private function createQueryShape(array $filter)
{
return
json_encode(array_keys($filter));
}

public function
commandStarted(\MongoDB\Driver\Monitoring\CommandStartedEvent $event): void
{
if (
'find' === $event->getCommandName()) {
$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);

?>
add a note

User Contributed Notes

There are no user contributed notes for this page.
To Top