1
0
mirror of https://github.com/php/doc-ru.git synced 2026-03-25 16:22:18 +01:00
Files
archived-doc-ru/reference/mongodb/tutorial/apm.xml
2024-06-07 02:41:18 +03:00

201 lines
7.9 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?xml version="1.0" encoding="utf-8"?>
<!-- EN-Revision: e9214a2619efc5906fab59cd42fb7404c4dc49a5 Maintainer: rjhdby Status: ready -->
<!-- Reviewed: no -->
<chapter xml:id="mongodb.tutorial.apm" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Мониторинг производительности приложения (Application Performance Monitoring или APM)</title>
<para>
Модуль содержит API подписчика события, который позволяет приложениям отслеживать команды и внутреннюю активность,
которая относится к «<link xlink:href="&url.mongodb.sdam;">Спецификации обнаружения и мониторинга серверов</link>».
В этом руководстве будет продемонстрирован мониторинг команд
с помощью интерфейса <classname>MongoDB\Driver\Monitoring\CommandSubscriber</classname>.
</para>
<para>
Интерфейс <classname>MongoDB\Driver\Monitoring\CommandSubscriber</classname>
определяет три метода: <literal>commandStarted</literal>,
<literal>commandSucceeded</literal> и <literal>commandFailed</literal>.
Каждый из них принимает один параметр <parameter>event</parameter> класса,
соответствующего нужному событию. К примеру, <literal>commandSucceeded</literal>
принимает аргумент <parameter>$event</parameter> класса
<classname>MongoDB\Driver\Monitoring\CommandSucceededEvent</classname>.
</para>
<para>
В данном руководстве вы реализуем подписчика, который создаёт список
профилировок всех запросов и среднего времени их исполнения.
</para>
<section>
<title>Класс подписчик Scaffolding</title>
<para>
Мы начнём с шаблона для нашего подписчика:
</para>
<programlisting role="php">
<![CDATA[
<?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 {}
}
?>
]]>
</programlisting>
</section>
<section>
<title>Регистрация подписчика</title>
<para>
Как только объект подписчика создан, необходимо его зарегистрировать
в системе мониторинга модуля. Регистрация производится методом
<methodname>MongoDB\Driver\Monitoring\addSubscriber</methodname>
или <methodname>MongoDB\Driver\Manager::addSubscriber</methodname>
для регистрации подписчика глобально или с помощью определённого класса Manager соответственно.
</para>
<programlisting role="php">
<![CDATA[
<?php
\MongoDB\Driver\Monitoring\addSubscriber( new QueryTimeCollector() );
?>
]]>
</programlisting>
</section>
<section>
<title>Реализуем логику</title>
<para>
Теперь займёмся реализацией логики класа подписчика.
Для сопоставления двух событий, относящихся к успешно выполненной
команды (commandStarted and commandSucceeded), каждый объект события
предоставляет поле <literal>requestId</literal>.
</para>
<para>
Для записи среднего времени выполнения запроса мы начнём с
отслеживания команды <literal>find</literal> в событии commandStarted.
Мы будем добавлять элемент в массив <literal>pendingCommands</literal>
с индексом соответствующим <literal>requestId</literal> и значением, соответствующим
запросу.
</para>
<para>
Когда мы получим соответствующее событие commandSucceeded с соответствующим
<literal>requestId</literal>, мы добавим время выполнения (из
<literal>durationMicros</literal>) к общему времени и увеличим счётчик операций.
</para>
<para>
Если мы получим событие commandFailed, мы просто удалим соответствующую запись из
<literal>pendingCommands</literal>.
</para>
<programlisting role="php">
<![CDATA[
<?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 ( 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 ): 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 );
?>
]]>
</programlisting>
</section>
</chapter>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->