应用程序性能监控 (APM)

该扩展包含一个事件订阅 API,允许应用程序监视与 » 服务器发现和监控规范 相关的命令和内部活动。本教程将演示如何使用 MongoDB\Driver\Monitoring\CommandSubscriber 接口来监控命令。

MongoDB\Driver\Monitoring\CommandSubscriber 接口定义了三个方法:commandStartedcommandSucceededcommandFailed。这三个方法都接受一个 event 参数,该参数是对应事件的特定类。例如,commandSucceeded$event 参数是一个 MongoDB\Driver\Monitoring\CommandSucceededEvent 对象。

在本教程中,我们将实现一个订阅者,它将创建一个包含所有查询配置文件及其平均执行时间的列表。

订阅者类框架

我们从订阅者的框架开始

<?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()MongoDB\Driver\Manager::addSubscriber() 来完成,分别用于全局注册订阅者或与特定 Manager 注册。

<?php

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

?>

实现逻辑

对象注册后,唯一剩下的工作是实现订阅者类中的逻辑。为了将构成成功执行的命令的两个事件(commandStarted 和 commandSucceeded)相关联,每个事件对象都公开了一个 requestId 字段。

为了记录每个查询形状的平均时间,我们将从检查 commandStarted 事件中的 find 命令开始。然后,我们将向 pendingCommands 属性添加一个项目,该项目由其 requestId 索引,其值表示查询形状。

如果我们接收到具有相同 requestId 的相应 commandSucceeded 事件,我们将把事件的持续时间(来自 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, " (", $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 );

?>
添加备注

用户贡献的备注

此页面没有用户贡献的备注。
To Top