-
Notifications
You must be signed in to change notification settings - Fork 76
/
Copy pathapm.xml
196 lines (165 loc) · 7.72 KB
/
apm.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
<?xml version="1.0" encoding="utf-8"?>
<!-- EN-Revision: 3e871fe7eab38f9b0398569c57a1dd0c21e69652 Maintainer: rjhdby Status: ready -->
<!-- Reviewed: no -->
<section 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>,
а для конкретного объекта класса Manager — методом
<methodname>MongoDB\Driver\Manager::addSubscriber</methodname>.
</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 ('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);
?>
]]>
</programlisting>
</section>
</section>
<!-- 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
-->