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

Драйвер MongoDB содержит 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 )
    {
    }

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

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

?>

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

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

<?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_encodearray_keys$filter ) );
    }

    public function 
commandStarted( \MongoDB\Driver\Monitoring\CommandStartedEvent $event )
    {
        if ( 
array_key_exists'find', (array) $event->getCommand() ) )
        {
            
$queryShape $this->createQueryShape( (array) $event->getCommand()->filter );
            
$this->pendingCommands[$event->getRequestId()] = $queryShape;
        }
    }

    public function 
commandSucceeded( \MongoDB\Driver\Monitoring\CommandSucceededEvent $event )
    {
        
$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 )
    {
        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 add a note

User Contributed Notes

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