MongoDB 애플리케이션 성능 모니터링(APM)

버전 1.3부터 ​​MongoDB 드라이버에는 성능 모니터링을 위한 API가 포함되어 있습니다. 이 API를 사용하면 구독자를 설정하여 특정 작업에 걸리는 시간을 알 수 있습니다. 각 구독자는 MongoDB\Driver\Monitoring 네임스페이스 아래에 하나 이상의 인터페이스를 구현해야 합니다. 현재 MongoDB\Driver\Monitoring\CommandSubscriber 인터페이스만 사용할 수 있습니다.

MongoDB\Driver\Monitoring\CommandSubscriber 인터페이스는 commandStarted, commandSucceededcommandFailed의 세 가지 메서드를 정의합니다. 이 세 가지 메서드 각각은 해당 이벤트에 대한 특정 클래스의 단일 event 인수를 허용합니다. 예를 들어 commandSucceeded$event 인수는 MongoDB\Driver\Monitoring\CommandSucceededEvent 개체입니다.

이 튜토리얼에서는 모든 쿼리 프로필과 평균 소요 시간 목록을 생성하는 구독자를 구현합니다.


Subscriber Class 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 )
    {
    }
}

?>
                  
                

Registering the Subscriber

가입자 개체가 인스턴스화되면 드라이버의 모니터링 시스템에 등록해야 합니다. 이는 MongoDB\Driver\Monitoring\addSubscriber() 또는 MongoDB\Driver\Manager::addSubscriber()를 호출하여 구독자를 전역적으로 또는 특정 Manager에 각각 등록함으로써 수행됩니다.

                  
<?php

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

?>
                  
                

Implementing the Logic

등록된 개체와 함께 남은 유일한 것은 구독자 클래스에서 논리를 구현하는 것입니다. 성공적으로 실행된 명령(commandStarted 및 commandSucceeded)을 구성하는 두 이벤트의 상관 관계를 지정하기 위해 각 이벤트 개체는 requestId 필드를 노출합니다.

쿼리 형태당 평균 시간을 기록하기 위해 먼저 commandStarted 이벤트에서 find 명령을 확인합니다. 그런 다음 requestId 및 쿼리 모양을 나타내는 값으로 인덱싱된 pendingCommands 속성에 항목을 추가합니다.

동일한 requestId를 가진 해당 commandSucceeded 이벤트를 수신하면 이벤트 기간(durationMicros에서)을 총 시간에 추가하고 작업 수를 증가시킵니다.

해당하는 commandFailed 이벤트가 발생하면 pendingCommands 속성에서 항목을 제거하기만 하면 됩니다.

                  
<?php

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

    /* Creates a query shape out of the filter argument. Right now it only
     * takes the top level fields into account */
    private function createQueryShape( array $filter )
    {
        return json_encode( array_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' );

/* Add the subscriber */
\MongoDB\Driver\Monitoring\addSubscriber( new QueryTimeCollector() );

/* Do a bunch of queries */
$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 );

?>