-
Notifications
You must be signed in to change notification settings - Fork 1
/
prometheus-client-java.drawio
431 lines (431 loc) · 98.8 KB
/
prometheus-client-java.drawio
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
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
<mxfile host="Electron" modified="2024-09-06T13:18:08.758Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/21.6.5 Chrome/114.0.5735.243 Electron/25.3.1 Safari/537.36" etag="jNjY7RzymYJ5mjfu6Fxq" version="21.6.5" type="device">
<diagram name="第 1 页" id="bCxN-LvEiLH-SmEH9Oog">
<mxGraphModel dx="3785" dy="799" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-1" value="<h1><font style="font-size: 16px;">Prometheus client java 工作原理(1.3.1)</font></h1><div style="font-size: 11px;"><span style="background-color: initial;"><font style="font-size: 11px;">测试代码: prometheus/prometheus-client-01。</font></span></div><div style="font-size: 11px;">这个Demo中注册了两种监控指标,JvmMetrics 和 自定义的 Counter 类型监控指标。</div><div style="font-size: 11px;"><font style="font-size: 11px;"><br></font></div>" style="text;html=1;strokeColor=none;fillColor=none;spacing=5;spacingTop=-20;whiteSpace=wrap;overflow=hidden;rounded=0;" parent="1" vertex="1">
<mxGeometry x="40" y="10" width="420" height="90" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-4" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;fontSize=10;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-2" target="ZjhWudJOdr6Pg1GAmp3d-3" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-8" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-2" target="ZjhWudJOdr6Pg1GAmp3d-7" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-2" value="<b>JvmMetrics 监控指标注册<br></b><font color="#007fff">JvmMetrics内部向 PrometheusRegistry 注册了一组监控指标</font>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="40" y="240" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-6" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=10;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-3" target="ZjhWudJOdr6Pg1GAmp3d-5" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-10" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-3" target="ZjhWudJOdr6Pg1GAmp3d-9" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-3" value="<b>自定义 Counter 类型监控指标注册<br></b><font color="#007fff">向 PrometheusRegistry 注册了一个自定义监控指标</font>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="40" y="560" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-14" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-5" target="ZjhWudJOdr6Pg1GAmp3d-13" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-5" value="<b>HTTPServer</b> 启动 HTTP 服务<br style="font-size: 10px;">提供监控接口<br><font color="#007fff"><b>HttpServer 只是四种 Exporter 中的其中一种</b></font>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="40" y="740" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-17" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-18" target="ZjhWudJOdr6Pg1GAmp3d-16" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-33" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-7" target="ZjhWudJOdr6Pg1GAmp3d-32" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-34" value="1" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="ZjhWudJOdr6Pg1GAmp3d-33" vertex="1" connectable="0">
<mxGeometry x="0.2667" y="1" relative="1" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-7" value="JvmMetrics<br>.<b>builder</b>() //1<br><div style=""><span style="background-color: initial;">.</span><b style="background-color: initial;">register</b><span style="background-color: initial;">(); //2</span></div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;" parent="1" vertex="1">
<mxGeometry x="280" y="240" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-12" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-9" target="ZjhWudJOdr6Pg1GAmp3d-11" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-29" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-9" target="ZjhWudJOdr6Pg1GAmp3d-28" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-9" value="<div><div><div>Counter counter = Counter.builder()</div><div>&nbsp; &nbsp; .name("my_count_total") <font color="#007fff">//写到元数据</font></div><div>&nbsp; &nbsp; .help("example counter")</div><div>&nbsp; &nbsp; .labelNames("status")</div><div>&nbsp; &nbsp; .<b>register</b>();</div></div></div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;" parent="1" vertex="1">
<mxGeometry x="280" y="560" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-11" value="<div>counter.labelValues("ok").inc();</div><div>counter.labelValues("ok").inc();</div><div>counter.labelValues("error").inc();<br></div><div><font color="#007fff">这里写死了两条监控数据</font></div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;" parent="1" vertex="1">
<mxGeometry x="280" y="640" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-62" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-13" target="ZjhWudJOdr6Pg1GAmp3d-61" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-13" value="<div>HTTPServer server = HTTPServer.builder()</div><div>&nbsp; &nbsp; .port(9400)</div><div>&nbsp; &nbsp; .<b>buildAndStart</b>();</div><div><font color="#007fff">HTTPServer 是借助JDK <b>HTTPServer</b> 实现的简单 HTTP服务器</font></div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;" parent="1" vertex="1">
<mxGeometry x="280" y="740" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-31" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;endArrow=open;endFill=0;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-15" target="ZjhWudJOdr6Pg1GAmp3d-30" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-15" value="<p style="margin: 4px 0px 0px; text-align: center; font-size: 10px;"><b style="font-size: 10px;">JvmMetrics$</b><b style="background-color: initial; font-size: 10px;">Builder</b></p><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><font color="#007fff" style="font-size: 10px;">// 通过 PrometheusPropertiesLoader.load() 加载的属性</font><br style="font-size: 10px;"></p><p style="margin: 0px 0px 0px 4px; font-size: 10px;">private final <b style="font-size: 10px;">PrometheusProperties</b> <b style="font-size: 10px;">config</b>;</p><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><br style="font-size: 10px;"></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=10;fontFamily=Helvetica;html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="-440" y="120" width="400" height="80" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-22" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-16" target="ZjhWudJOdr6Pg1GAmp3d-21" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-16" value="<div><font color="#007fff">// 根据后面的代码这里面实际就是向 PrometheusRegistry 单例对象中注册了多组监控指标,每组监控指标有多个监控指标(采集器),基本每种 <b>Metrics</b> 类型对应一种 <b>MXBean</b></font></div><div>public void register(PrometheusRegistry registry) {</div><div>&nbsp; &nbsp; <b>JvmThreadsMetrics</b>.builder(this.config).register(registry);</div><div>&nbsp; &nbsp; <b>JvmBufferPoolMetrics</b>.builder(this.config).register(registry);</div><div>&nbsp; &nbsp; <b>JvmClassLoadingMetrics</b>.builder(this.config).register(registry);</div><div>&nbsp; &nbsp; <b>JvmCompilationMetrics</b>.builder(this.config).register(registry);</div><div>&nbsp; &nbsp; <b>JvmGarbageCollectorMetrics</b>.builder(this.config).register(registry);</div><div>&nbsp; &nbsp; <b>JvmMemoryPoolAllocationMetrics</b>.builder(this.config).register(registry);</div><div>&nbsp; &nbsp; <b>JvmMemoryMetrics</b>.builder(this.config).register(registry);</div><div>&nbsp; &nbsp; <b>JvmNativeMemoryMetrics</b>.builder(this.config).register(registry);</div><div>&nbsp; &nbsp; <b>JvmRuntimeInfoMetric</b>.builder(this.config).register(registry);</div><div>&nbsp; &nbsp; <b>ProcessMetrics</b>.builder(this.config).register(registry);</div><div>}</div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=6;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="760" y="340" width="440" height="180" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-19" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-7" target="ZjhWudJOdr6Pg1GAmp3d-18" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="480" y="270" as="sourcePoint" />
<mxPoint x="800" y="320" as="targetPoint" />
<Array as="points">
<mxPoint x="500" y="270" />
<mxPoint x="500" y="430" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-35" value="2" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="ZjhWudJOdr6Pg1GAmp3d-19" vertex="1" connectable="0">
<mxGeometry x="0.8978" y="1" relative="1" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-58" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-18" target="ZjhWudJOdr6Pg1GAmp3d-57" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-18" value="this.<b>register</b>(PrometheusRegistry<br>.<b>defaultRegistry</b>);" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;" parent="1" vertex="1">
<mxGeometry x="520" y="400" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-20" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>PrometheusRegistry</b><br></p><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><font color="#007fff" style="font-size: 10px;"><b>单例模式,Prometheus监控指标注册列表</b></font></p><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><br style="font-size: 10px;"></p><p style="margin: 0px 0px 0px 4px;">public <b>static</b> final PrometheusRegistry <b>defaultRegistry</b> = new PrometheusRegistry();</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff"><b>// 指标名称集合</b></font></p><p style="margin: 0px 0px 0px 4px;">private final Set&lt;String&gt; prometheusNames = ConcurrentHashMap.newKeySet();</p><p style="margin: 0px 0px 0px 4px;"><b><font color="#007fff">// 注册的数据采集器</font></b></p><p style="margin: 0px 0px 0px 4px;">private final List&lt;Collector&gt; collectors = new CopyOnWriteArrayList();</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">// MultiCollector, todo</font></p><p style="margin: 0px 0px 0px 4px;">private final List&lt;MultiCollector&gt; multiCollectors = new CopyOnWriteArrayList();</p><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><br style="font-size: 10px;"></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=10;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="-440" y="240" width="400" height="160" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-24" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-21" target="ZjhWudJOdr6Pg1GAmp3d-23" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-21" value="<div><b>ThreadMXBean</b> threadBean = this.threadBean != null ? this.threadBean : <br><span style="white-space: pre;">	</span>ManagementFactory.getThreadMXBean();</div><div>boolean isNativeImage = this.isNativeImage != null ? this.isNativeImage : <br><span style="white-space: pre;">	</span>NativeImageChecker.isGraalVmNativeImage;</div><div>(new <b>JvmThreadsMetrics</b>(isNativeImage, threadBean, this.config)).<b>register</b>(registry);</div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=6;" parent="1" vertex="1">
<mxGeometry x="1240.5" y="390" width="440" height="80" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-27" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-23" target="ZjhWudJOdr6Pg1GAmp3d-26" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-23" value="<font color="#007fff"><b>注册一组监控指标,这里举一个例子, jvm_threads_current 这个监控指标查询当前JVM线程数量</b><br></font><div>((GaugeWithCallback.Builder)((GaugeWithCallback.Builder)GaugeWithCallback.builder(this.config)</div><div>.name("jvm_threads_current")).help("Current thread count of a JVM"))<br>.callback((callback) -&gt; {</div><div>&nbsp; &nbsp; callback.call((double)this.threadBean.getThreadCount(), new String[0]);</div><div>}).<b>register</b>(registry);</div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=6;" parent="1" vertex="1">
<mxGeometry x="1720" y="390" width="440" height="80" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-26" value="<div><font color="#007fff"><b>// 构建的是 Metric 类型,也即数据采集器</b></font></div><div>M metric = this.<b>build</b>();</div><div>registry.<b>register</b>(metric);</div><div>return metric;</div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=6;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="2200" y="400" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-56" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-28" target="ZjhWudJOdr6Pg1GAmp3d-26" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="2180" y="590" />
<mxPoint x="2180" y="430" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-59" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-28" target="ZjhWudJOdr6Pg1GAmp3d-57" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-28" value="return this.<b>register</b>(<br>PrometheusRegistry.<b>defaultRegistry</b>);" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;" parent="1" vertex="1">
<mxGeometry x="520" y="560" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-30" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>PrometheusProperties</b><br></p><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><b><font color="#007fff">单例模式,Prometheus 配置属性</font></b></p><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><br style="font-size: 10px;"></p><p style="margin: 0px 0px 0px 4px;">private static final PrometheusProperties <b>instance</b> = PrometheusPropertiesLoader.load();</p><p style="margin: 0px 0px 0px 4px;">private final MetricsProperties defaultMetricsProperties;</p><p style="margin: 0px 0px 0px 4px;">private final Map&lt;String, MetricsProperties&gt; metricProperties = new HashMap();</p><p style="margin: 0px 0px 0px 4px;">private final ExemplarsProperties exemplarProperties;</p><p style="margin: 0px 0px 0px 4px;">private final ExporterProperties exporterProperties;</p><p style="margin: 0px 0px 0px 4px;">private final ExporterFilterProperties exporterFilterProperties;</p><p style="margin: 0px 0px 0px 4px;">private final ExporterHttpServerProperties exporterHttpServerProperties;</p><p style="margin: 0px 0px 0px 4px;">private final ExporterOpenTelemetryProperties exporterOpenTelemetryProperties;</p><p style="margin: 0px 0px 0px 4px;">private final ExporterPushgatewayProperties exporterPushgatewayProperties;</p><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><br style="font-size: 10px;"></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=10;fontFamily=Helvetica;html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="-880" y="120" width="400" height="200" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-32" value="return new Builder(<b>PrometheusProperties</b>.get());" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;" parent="1" vertex="1">
<mxGeometry x="520" y="240" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-37" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;dashed=1;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-36" target="ZjhWudJOdr6Pg1GAmp3d-32" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-36" value="PrometheusProperties instance = PrometheusPropertiesLoader.<b>load</b>();<br><font color="#007fff">左边获取的配置属性来源于load()方法,加载逻辑参考方法实现,包括从ClassPath、文件、系统属性等</font>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="760" y="240" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-91" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;endArrow=open;endFill=0;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-38" target="ZjhWudJOdr6Pg1GAmp3d-90" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-38" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>Collector (I)</b><br></p><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><font color="#007fff"><b>监控数据采集器接口</b></font></p><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><br style="font-size: 10px;"></p><p style="margin: 0px 0px 0px 4px;">MetricSnapshot collect();<br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=10;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="-440" y="440" width="400" height="80" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-39" value="<font color="#007fff">JVM监控数据都是通过 MXBean 查询的</font>" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="160" y="320" width="230" height="30" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-41" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;dashed=1;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-42" target="ZjhWudJOdr6Pg1GAmp3d-38" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="-240" y="560" as="sourcePoint" />
</mxGeometry>
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-42" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>Metric(A)</b><br></p><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><font color="#007fff" style="font-size: 10px;"><b>监控指标</b></font></p><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><font color="#007fff" style="font-size: 10px;"><br></font></p><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><font color="#007fff" style="font-size: 10px;">// 监控指标的标签列表</font></p><p style="margin: 0px 0px 0px 4px;">protected final Labels <b>constLabels</b>;<br></p><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><br style="font-size: 10px;"></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=10;fontFamily=Helvetica;html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="-440" y="560" width="400" height="120" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-44" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-43" target="ZjhWudJOdr6Pg1GAmp3d-42" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-43" value="<div style="text-align: center;"><b>MetricWithFixedMetadata</b><b style="background-color: initial;">(A)</b></div><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><font color="#007fff" style="font-size: 10px;"><b>带者元数据的监控指标</b></font></p><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><br></p><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><font color="#007fff">// 元数据包括指标名称、prometheusName、帮助信息、unit (单位,比如s, 可选)</font></p><p style="margin: 0px 0px 0px 4px;">private final <b>MetricMetadata</b> metadata;</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">// 指标下标签名称,可以当作是子指标</font></p><p style="margin: 0px 0px 0px 4px;">protected final String[] <b>labelNames</b>;</p><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><br style="font-size: 10px;"></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=10;fontFamily=Helvetica;html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="-440" y="720" width="400" height="120" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-46" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-45" target="ZjhWudJOdr6Pg1GAmp3d-43" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-45" value="<div style="text-align: center;"><b>CallbackMetric</b></div><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><font color="#007fff"><b>子类都会有一个回调方法(Consumer&lt;Callback&gt;),通过这个方法采集监控数据</b></font></p><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><font color="#007fff"><b>此类型包含多种实现,下面只列了两种</b></font></p><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><br style="font-size: 10px;"></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=10;fontFamily=Helvetica;html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="-440" y="880" width="400" height="80" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-48" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-47" target="ZjhWudJOdr6Pg1GAmp3d-45" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-47" value="<div style="text-align: center;"><b>GaugeWithCallback</b><br></div><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px;">private final Consumer&lt;Callback&gt; <b>callback</b>;</p><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><br style="font-size: 10px;"></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=10;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="-440" y="1000" width="400" height="80" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-50" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-49" target="ZjhWudJOdr6Pg1GAmp3d-45" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-49" value="<div style="text-align: center;"><b>CounterWithCallback</b><br></div><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px;">private final Consumer&lt;Callback&gt; <b>callback</b>;</p><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><br style="font-size: 10px;"></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=10;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="-880" y="1000" width="400" height="80" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-53" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-52" target="ZjhWudJOdr6Pg1GAmp3d-43" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="-240" y="840" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-100" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;endArrow=open;endFill=0;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-52" target="ZjhWudJOdr6Pg1GAmp3d-98" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-52" value="<div style="text-align: center;"><b>StatefulMetric&lt;D extends DataPoint, T extends D&gt;</b><br></div><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">// 存储指标数据的容器,有状态的指标数据需要存储起来,后面在此基础上增量修改</font></p><p style="margin: 0px 0px 0px 4px;">private final ConcurrentHashMap&lt;List&lt;String&gt;, T&gt; <b>data</b> = new ConcurrentHashMap();<br></p><p style="margin: 0px 0px 0px 4px;">private volatile T <b>noLabels</b>;<br></p><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><br style="font-size: 10px;"></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=10;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="-1320" y="880" width="400" height="80" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-55" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-54" target="ZjhWudJOdr6Pg1GAmp3d-52" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-54" value="<div style="text-align: center;"><b>Counter</b><br></div><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px;">private final boolean <b>exemplarsEnabled</b>;</p><p style="margin: 0px 0px 0px 4px;">private final ExemplarSamplerConfig <b>exemplarSamplerConfig</b>;</p><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><br style="font-size: 10px;"></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=10;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="-1320" y="1000" width="400" height="80" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-57" value="<font color="#007fff">将采集器注册到 <br><b>PrometheusRegistry</b> 单例对象</font>" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="525" y="495" width="190" height="40" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-64" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-61" target="ZjhWudJOdr6Pg1GAmp3d-63" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-61" value="<font color="#007fff">// 创建 JDK HttpServer 实例</font><br>httpServer = HttpServer.<b>create</b>(this.makeInetSocketAddress(), 3);<br><div>ExecutorService executorService = this.makeExecutorService();</div><div>((HttpServer)httpServer).setExecutor(executorService);</div><div>return new <b>HTTPServer</b>(this.config, executorService, (HttpServer)httpServer, this.registry, this.authenticator, this.defaultHandler);<br></div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;" parent="1" vertex="1">
<mxGeometry x="520" y="730" width="440" height="80" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-68" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-63" target="ZjhWudJOdr6Pg1GAmp3d-65" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1460" y="770" />
<mxPoint x="1460" y="870" />
<mxPoint x="260" y="870" />
<mxPoint x="260" y="910" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-69" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-63" target="ZjhWudJOdr6Pg1GAmp3d-66" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1460" y="770" />
<mxPoint x="1460" y="870" />
<mxPoint x="260" y="870" />
<mxPoint x="260" y="990" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-70" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-63" target="ZjhWudJOdr6Pg1GAmp3d-67" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1460" y="770" />
<mxPoint x="1460" y="870" />
<mxPoint x="260" y="870" />
<mxPoint x="260" y="1070" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-63" value="<div>this.server = httpServer;</div><div>this.executorService = executorService;</div><div><font color="#007fff">// 注册了3个请求路由</font></div><div>this.<b>registerHandler</b>("<b>/</b>", (HttpHandler)(defaultHandler == null ? new DefaultHandler() : defaultHandler), authenticator);</div><div>this.<b>registerHandler</b>("<b>/metrics</b>", new MetricsHandler(config, registry), authenticator);</div><div>this.<b>registerHandler</b>("<b>/-/healthy</b>", new HealthyHandler(), authenticator);</div><div>...</div><div>ExecutorService var10000 = this.executorService;</div><div>HttpServer var10001 = this.server;</div><div>...</div><div><font color="#007fff">// HTTPServer 启动</font></div><div>var10000.<b>submit</b>(var10001::<b>start</b>).get();</div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=3;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="1000" y="690" width="440" height="160" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-65" value="<div>“/” -&gt; <b>DefaultHandler</b></div><div><font color="#007fff">DefaultHandler 是默认的处理器, 处理逻辑只是返回一个固定的静态页面</font></div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;" parent="1" vertex="1">
<mxGeometry x="280" y="880" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-73" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-66" target="ZjhWudJOdr6Pg1GAmp3d-72" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-66" value="<div></div>“/metrics” -&gt;&nbsp;<b>MetricsHandler</b>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="280" y="960" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-67" value="<div>“/-/healthy” -&gt; <b>HealthyHandler</b></div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;" parent="1" vertex="1">
<mxGeometry x="280" y="1040" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-75" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-72" target="ZjhWudJOdr6Pg1GAmp3d-74" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-72" value="<div></div>this.<b>prometheusScrapeHandler</b><br>.<b>handleRequest</b>(<br>new HttpExchangeAdapter(t));<br><font color="#007fff">内部借助&nbsp;PrometheusScrapeHandler 处理请求</font>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;" parent="1" vertex="1">
<mxGeometry x="520" y="960" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-79" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-74" target="ZjhWudJOdr6Pg1GAmp3d-78" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-74" value="<div></div><div>PrometheusHttpRequest request = exchange.getRequest();</div><div>PrometheusHttpResponse response = exchange.getResponse();</div><div><font color="#007fff">// 通过上面配置的收集器抓取监控数据</font></div><div>MetricSnapshots snapshots = this.<b>scrape</b>(request);</div><div><font color="#007fff">// 写响应</font></div><div>...</div><div><div>ByteArrayOutputStream responseBuffer = new ByteArrayOutputStream(<br><span style="white-space: pre;">	</span>this.lastResponseSize.get() + 1024);</div><div>String acceptHeader = request.getHeader("Accept");</div><div><font color="#007fff">// writer 写时执行序列化</font></div><div>ExpositionFormatWriter writer = this.expositionFormats.<b>findWriter</b>(acceptHeader);</div></div><div>writer.<b>write</b>(responseBuffer, snapshots); <font color="#007fff">//后面再将Buffer数据写到 Response</font><br></div><div>...</div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;fillColor=#dae8fc;strokeColor=#6c8ebf;arcSize=4;" parent="1" vertex="1">
<mxGeometry x="760" y="910" width="440" height="160" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-76" value="PrometheusScrapeHandler" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="895" y="880" width="170" height="30" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-82" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-78" target="ZjhWudJOdr6Pg1GAmp3d-81" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-78" value="<div></div><div><div><font color="#007fff">抓取流程添加一个名称过滤器,这说明<b>可以通过在请求中设置设个参数进行过滤数据</b></font></div><div>Predicate&lt;String&gt; filter = this.makeNameFilter(request.getParameterValues("name[]"));</div><div><font color="#007fff">遍历注册的所有数据采集器,抓取监控数据</font></div><div>return filter != null ? this.registry.<b>scrape</b>(filter, request) : this.registry.<b>scrape</b>(request);</div></div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;" parent="1" vertex="1">
<mxGeometry x="1241" y="950" width="439" height="80" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-81" value="<div style="font-size: 9px;"></div><div style="font-size: 9px;"><div style="font-size: 9px;">if (includedNames == null) {</div><div style="font-size: 9px;">&nbsp; &nbsp; return scrape(scrapeRequest);</div><div style="font-size: 9px;">}</div><div style="font-size: 9px;">MetricSnapshots.Builder <b>result</b> = MetricSnapshots.builder();</div><div style="font-size: 9px;"><b>for</b> (Collector collector : <b>collectors</b>) {</div><div style="font-size: 9px;">&nbsp; &nbsp; String prometheusName = collector.getPrometheusName();</div><div style="font-size: 9px;"><font color="#007fff">&nbsp; &nbsp; // prometheusName == null 采集器是通用采集器,即不需要通过 includedNames 过滤</font></div><div style="font-size: 9px;"><span style="background-color: initial;">&nbsp; &nbsp; if (prometheusName == null || includedNames.test(prometheusName)) {</span><br></div><div style="font-size: 9px;"><span style="background-color: initial;"><b><font color="#007fff"><span style="white-space: pre;">	</span>// 调用各个采集器的监控数据采集方法</font></b><br></span></div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; MetricSnapshot snapshot = scrapeRequest == null ? collector.<b>collect</b>(includedNames) : <br><span style=""><span style="white-space: pre;">&nbsp;&nbsp;&nbsp;&nbsp;</span></span>&nbsp; &nbsp; collector.<b>collect</b>(includedNames, scrapeRequest);</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; if (snapshot != null) {</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result.metricSnapshot(snapshot);</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; }</div><div style="font-size: 9px;">&nbsp; &nbsp; }</div><div style="font-size: 9px;">}</div><div style="font-size: 9px;"><b>for</b> (MultiCollector collector : <b>multiCollectors</b>) {</div><div style="font-size: 9px;">&nbsp; &nbsp; List&lt;String&gt; prometheusNames = collector.getPrometheusNames();</div><div style="font-size: 9px;"><font color="#007fff">&nbsp; &nbsp; // prometheusName == null 采集器是通用采集器,即不需要通过 includedNames 过滤</font></div><div style="font-size: 9px;"><span style="background-color: initial;">&nbsp; &nbsp; boolean excluded = !prometheusNames.isEmpty();</span><br></div><div style="font-size: 9px;">&nbsp; &nbsp; for (String prometheusName : prometheusNames) {</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; if (includedNames.test(prometheusName)) {</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; excluded = false;</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; }</div><div style="font-size: 9px;">&nbsp; &nbsp; }</div><div style="font-size: 9px;">&nbsp; &nbsp; if (!excluded) {</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; MetricSnapshots snapshots = scrapeRequest == null ? collector.<b>collect</b>(includedNames) : <br><span style="white-space: pre;">	</span>&nbsp; &nbsp; collector.<b>collect</b>(includedNames, scrapeRequest);</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; for (MetricSnapshot snapshot : snapshots) {</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (snapshot != null) {</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result.metricSnapshot(snapshot);</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; }</div><div style="font-size: 9px;">&nbsp; &nbsp; }</div><div style="font-size: 9px;">}</div><div style="font-size: 9px;">return result.build();</div></div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=9;align=left;arcSize=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="1720" y="950" width="440" height="410" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-86" value="重要概念说明:<br style="font-size: 10px;"><div style=""><ul style=""><li style="font-size: 10px;"><b style="font-size: 10px;">Exporter</b><br style="font-size: 10px;"><font color="#007fff" style="font-size: 10px;">即输出者,更准确地说是被封装的通信组件,负责数据上报,业务服务收集监控数据需要通过某种通信方式传给数据中心,client_java 中现在支持 HttpServer、Servlet、Pushgateway、Opentelemetry 四种方式。</font></li><li style="font-size: 10px;"><b style="font-size: 10px;">Instrumentation<br style="font-size: 10px;"></b><font color="#007fff" style="font-size: 10px;">封装了监控指标(Metric)的组件,负责数据采集。</font></li><li style=""><b style="font-size: 10px;">Metric<br style="font-size: 10px;"></b><font color="#007fff" style="">监控指标,还是数据采集器(内部实现了 Collector 接口),定义指标类型、指标数据结构、以及采集方法。<br>关于指标类型测试参考 prometheus-client-01 中的单元测试。<br></font></li><li style="font-size: 10px;"><b style="font-size: 10px;">PrometheusRegistry<br style="font-size: 10px;"></b><font color="#007fff" style="font-size: 10px;">一系列监控指标的注册表,Instruemntation 组件中的监控指标或自定义的监控指标都要注册到这个单例对象,在数据采集时遍历所有监控指标(也是数据采集器)进行数据采集。</font></li></ul></div>" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=top;whiteSpace=wrap;rounded=0;fontSize=10;" parent="1" vertex="1">
<mxGeometry x="480" y="10" width="720" height="190" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-87" value="<b>Servlet Exporter</b><br><font color="#007fff">TODO</font>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="40" y="1160" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-88" value="<b>Pushgateway&nbsp;Exporter<br></b><font color="#007fff">TODO</font><b><br></b>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="40" y="1260" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-89" value="<b>Opentelemetry&nbsp;Exporter<br></b><font color="#007fff">TODO</font><b><br></b>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="40" y="1360" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-93" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;endArrow=open;endFill=0;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-90" target="ZjhWudJOdr6Pg1GAmp3d-92" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-90" value="<div style="text-align: center;"><b>MetricSnapshot (</b><b style="background-color: initial;">A)</b></div><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><font color="#007fff" style="font-size: 10px;"><b>指标数据快照</b></font></p><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><font color="#007fff" style="font-size: 10px;"><br></font></p><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><font color="#007fff" style="font-size: 10px;"><b>// 指标元数据信息</b></font></p><p style="margin: 0px 0px 0px 4px;">private final MetricMetadata <b>metadata</b>;</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff"><b>// 监控指标数据列表</b></font></p><p style="margin: 0px 0px 0px 4px;">protected final List&lt;? extends DataPointSnapshot&gt; <b>dataPoints</b>;</p><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><br style="font-size: 10px;"></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=10;fontFamily=Helvetica;html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="-880" y="440" width="400" height="120" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-92" value="<div style="text-align: center;"><b>DataPointSnapshot</b><b style="background-color: initial;">&nbsp;(</b><b style="background-color: initial;">A)</b></div><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><font color="#007fff" style="font-size: 10px;"><b>指标数据点快照</b></font></p><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><font color="#007fff" style="font-size: 10px;"><br></font></p><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><font color="#007fff" style="font-size: 10px;">// 指标标签</font></p><p style="margin: 0px 0px 0px 4px;">private final Labels <b>labels</b>;</p><p style="margin: 0px 0px 0px 4px;">private final long <b>createdTimestampMillis</b>;</p><p style="margin: 0px 0px 0px 4px;">private final long <b>scrapeTimestampMillis</b>;</p><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><br style="font-size: 10px;"></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=10;fontFamily=Helvetica;html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="-1320" y="440" width="400" height="120" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-95" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-94" target="ZjhWudJOdr6Pg1GAmp3d-90" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-94" value="<div style="text-align: center;"><b>CounterSnapshot</b></div><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><font color="#007fff" style="font-size: 10px;"><b>Counter指标数据快照</b></font></p><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><font color="#007fff" style="font-size: 10px;"><br></font></p><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><font color="#007fff" style="font-size: 10px;"><b>// 指标元数据信息</b></font></p><p style="margin: 0px 0px 0px 4px;">private final MetricMetadata <b>metadata</b>;</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff"><b>// 监控指标数据列表</b></font></p><p style="margin: 0px 0px 0px 4px;">protected final List&lt;? extends DataPointSnapshot&gt; <b>dataPoints</b>;</p><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><br style="font-size: 10px;"></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=10;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="-880" y="600" width="400" height="120" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-97" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;endArrow=block;endFill=1;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-96" target="ZjhWudJOdr6Pg1GAmp3d-92" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-96" value="<div style="text-align: center;"><b>CounterSnapshot$CounterDataPointSnapshot</b></div><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><font color="#007fff" style="font-size: 10px;"><b>指标数据点快照</b></font></p><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><font color="#007fff" style="font-size: 10px;"><br></font></p><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><font color="#007fff" style="font-size: 10px;">// 实际是用 double 存储的递增数据值</font></p><p style="margin: 0px 0px 0px 4px;">private final double <b>value</b>;</p><p style="margin: 0px 0px 0px 4px;">private final Exemplar <b>exemplar</b>;</p><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><br style="font-size: 10px;"></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=10;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="-1320" y="600" width="400" height="120" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-98" value="<div style="text-align: center;"><b>DataPoint</b><b style="background-color: initial;">&nbsp;(I)</b></div><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><b><font color="#007fff">指标数据容器接口</font></b></p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=10;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="-1760" y="880" width="400" height="80" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-101" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-99" target="ZjhWudJOdr6Pg1GAmp3d-98" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-99" value="<div style="text-align: center;"><b>CounterDataPoint</b><b style="background-color: initial;">&nbsp;(I)</b></div><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><font color="#007fff">就是计数器</font></p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;">void inc(double amount);<br></p><p style="margin: 0px 0px 0px 4px;">void incWithExemplar(double amount, Labels labels);<br></p><p style="margin: 0px 0px 0px 4px;">double get();<br></p><p style="margin: 0px 0px 0px 4px;">long getLongValue();<br></p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=10;fontFamily=Helvetica;html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="-1760" y="1000" width="400" height="100" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-103" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-102" target="ZjhWudJOdr6Pg1GAmp3d-98" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-102" value="<div style="text-align: center;"><b>GaugeDataPoint</b></div><hr style="font-size: 10px;"><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><span style="background-color: initial;">void inc(double amount);</span><br></p><p style="margin: 0px 0px 0px 4px;">void incWithExemplar(double amount, Labels labels);<br></p><p style="margin: 0px 0px 0px 4px;">default void dec(double amount);<br></p><p style="margin: 0px 0px 0px 4px;">default void decWithExemplar(double amount, Labels labels);<br></p><p style="margin: 0px 0px 0px 4px;">void set(double value);<br></p><p style="margin: 0px 0px 0px 4px;">void setWithExemplar(double value, Labels labels);<br></p><p style="margin: 0px 0px 0px 4px;">double get();</p><p style="margin: 0px 0px 0px 4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=10;fontFamily=Helvetica;html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="-2200" y="1000" width="400" height="120" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-106" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-104" target="ZjhWudJOdr6Pg1GAmp3d-108" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="280" y="1490" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-104" value="<b style="border-color: var(--border-color);">&nbsp;Summary&nbsp;</b><b>指标类型的数据收集原理</b><br><font color="#007fff">这里其实是涉及到一个<b>目标分位数问题,</b>使用 CKMS 算法解决的<br></font>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="40" y="1460" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-107" value="<font color="#007fff">这个算法直接看代码有点难以理解,<br style="font-size: 10px;">建议先看下目标分位数问题</font>" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontSize=10;" parent="1" vertex="1">
<mxGeometry x="40" y="1520" width="180" height="40" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-110" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-108" target="ZjhWudJOdr6Pg1GAmp3d-109" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-108" value="<div>这里通过源码 CKMSQuantilesTest#<b>testGet</b>()</div><div>分析 CKMS 算法原理</div><div><font color="#007fff">为了方便测试,将 compresInterval 从128改为了8, 将误差设置为0.1</font></div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=center;" parent="1" vertex="1">
<mxGeometry x="280" y="1460" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-112" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-109" target="ZjhWudJOdr6Pg1GAmp3d-111" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-113" value="1" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="ZjhWudJOdr6Pg1GAmp3d-112" vertex="1" connectable="0">
<mxGeometry x="0.1583" y="-1" relative="1" as="geometry">
<mxPoint x="-1" y="-9" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-117" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.935;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;exitPerimeter=0;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-109" target="ZjhWudJOdr6Pg1GAmp3d-116" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-118" value="2" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="ZjhWudJOdr6Pg1GAmp3d-117" vertex="1" connectable="0">
<mxGeometry x="0.808" y="-1" relative="1" as="geometry">
<mxPoint x="1" y="55" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-109" value="<font color="#007fff">//注册1个0.5分位数,误差 0.1 (误差值越大,压缩程度越高)<br></font><div>Quantile q50 = new Quantile(0.5, 0.1);<span style=""><span style="white-space: pre;">&nbsp;&nbsp;&nbsp;&nbsp;</span></span></div><div>CKMSQuantiles ckms = new CKMSQuantiles(q50);</div>CKMSQuantiles ckms = new CKMSQuantiles(q50, q95, q99);<br><font color="#007fff">//使用随机源打乱 1-16 对应的双精度浮点数列表,然后分两批插入 ckms</font><br><div>Random random = new Random(0);</div><div>List&lt;Double&gt; input = shuffledValues(16, random);</div><div>for (int i = 0; i &lt; 8; i++) {</div><div>&nbsp; &nbsp; ckms.insert(input.get(i));</div><div>}</div><div>for (int i = 8; i &lt; 16; i++) {</div><div>&nbsp; &nbsp; ckms.insert(input.get(i));</div><div>}&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</div><div><font color="#007fff">//校验每个分位数对应的观测值是否在允许的范围内</font></div><div>validateResults(ckms);<br></div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=4;" parent="1" vertex="1">
<mxGeometry x="520" y="1460" width="440" height="200" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-115" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-111" target="ZjhWudJOdr6Pg1GAmp3d-114" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="4s08r3_KoatAhovvTcsq-6" value="1" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="ZjhWudJOdr6Pg1GAmp3d-115">
<mxGeometry x="0.3" y="1" relative="1" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="4s08r3_KoatAhovvTcsq-11" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0.003;entryY=0.59;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-111" target="4s08r3_KoatAhovvTcsq-10">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1460" y="1520" />
<mxPoint x="1460" y="2052" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="4s08r3_KoatAhovvTcsq-12" value="2" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="4s08r3_KoatAhovvTcsq-11">
<mxGeometry x="0.8229" y="-2" relative="1" as="geometry">
<mxPoint x="3" y="27" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-111" value="<span style="background-color: initial;">buffer[bufferPos++] = value;</span><br><div></div><font color="#007fff">// buffer 是固定大小的数组,默认size为128,即buffer 存满后会 flush()</font><div>if (bufferPos == buffer.length) {</div><div>&nbsp; &nbsp; <b>flush</b>();<span style="white-space: pre;">	</span><font color="#007fff"><b>//1 将 buffer 中的数据转移到 samples</b></font></div><div>}</div><div><font color="#007fff">// 从上次压缩后插入观测值数量达到&nbsp;compressInterval(默认128)执行压缩</font></div><div>if (++insertsSinceLastCompress == compressInterval) {</div><div>&nbsp; &nbsp; <b>compress</b>(); <b><font color="#007fff">//2 将差值不超过误差百分比的元素合并,这样可以减少samples中存储的元素个数</font></b></div><div>&nbsp; &nbsp; insertsSinceLastCompress = 0;</div><div>}</div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=4;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="1000" y="1460" width="440" height="120" as="geometry" />
</mxCell>
<mxCell id="4s08r3_KoatAhovvTcsq-2" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-114" target="4s08r3_KoatAhovvTcsq-1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-114" value="<div><font color="#007fff">//将数组中元素进行排序</font></div><div>Arrays.<b>sort</b>(buffer, 0, bufferPos);</div><div><font color="#007fff">//批量合并到 samples</font></div><div><b>insertBatch</b>(buffer, bufferPos);</div><div>bufferPos = 0;</div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=14;" parent="1" vertex="1">
<mxGeometry x="1480" y="1490" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-120" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1.003;exitY=0.111;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="ZjhWudJOdr6Pg1GAmp3d-116" target="ZjhWudJOdr6Pg1GAmp3d-119" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-121" value="1" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="ZjhWudJOdr6Pg1GAmp3d-120" vertex="1" connectable="0">
<mxGeometry x="0.4923" y="3" relative="1" as="geometry">
<mxPoint y="19" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-116" value="<div>for (Quantile q : ckms.quantiles) {</div><div>&nbsp; &nbsp; <font color="#007fff">//1</font>&nbsp;</div><div>&nbsp; &nbsp; double actual = ckms.<b>get</b>(q.quantile);</div><div>&nbsp; &nbsp; double lowerBound, upperBound;</div><div>&nbsp; &nbsp; if (q.quantile == 0) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; lowerBound = 1;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; upperBound = 1;</div><div>&nbsp; &nbsp; } else if (q.quantile == 1) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; lowerBound = ckms.n;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; upperBound = ckms.n;</div><div>&nbsp; &nbsp; } else {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; <b>lowerBound = Math.floor(ckms.n * (q.quantile - 2 * q.epsilon));</b></div><div><b>&nbsp; &nbsp; &nbsp; &nbsp; upperBound = Math.ceil(ckms.n * (q.quantile + 2 * q.epsilon));</b></div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; boolean ok =<b> actual &gt;= lowerBound &amp;&amp; actual &lt;= upperBound</b>;</div><div>&nbsp; &nbsp; if (!ok) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; for (CKMSQuantiles.Sample sample : ckms.samples) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.err.println(sample);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; String errorMessage = q + ": " + actual + " not in [" + lowerBound + ", " + upperBound + "], n=" + ckms.n + ", " +&nbsp; q.quantile + "*" + ckms.n + "=" + (q.quantile*ckms.n);</div><div>&nbsp; &nbsp; assertTrue(errorMessage, ok);</div><div>}</div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=2;" parent="1" vertex="1">
<mxGeometry x="1000" y="2240" width="440" height="300" as="geometry" />
</mxCell>
<mxCell id="ZjhWudJOdr6Pg1GAmp3d-119" value="<div style="font-size: 9px;"><font color="#007fff" style="font-size: 9px;"><b style="font-size: 9px;">// 即get()前先执行一下flush操作,将buffer中的数据批量转移到 samples</b></font></div><div style="font-size: 9px;"><b style="font-size: 9px;">flush</b>();</div><div style="font-size: 9px;"><font color="#007fff" style="font-size: 9px;">// 一些边界值的特殊处理,比如 0分位 1分位 samples为空</font></div><div style="font-size: 9px;">...</div><div style="font-size: 9px;">int r = 0; // sum of g's left of the current sample</div><div style="font-size: 9px;"><font color="#007fff" style="font-size: 9px;">// 期望的观测值索引,比如 0.95 百分位,如果 samples 中有100个元素,就是取第95个观测值</font></div><div style="font-size: 9px;"><font color="#007fff" style="font-size: 9px;">// 期望索引:如果有 50个元素就取第48个元素</font></div><div style="font-size: 9px;">int <b style="font-size: 9px;">desiredRank</b> = (int) Math.ceil(q * n);</div><div style="font-size: 9px;"><font color="#007fff" style="font-size: 9px;">// 上边界索引</font></div><div style="font-size: 9px;">int upperBound = desiredRank + <b style="font-size: 9px;">f(desiredRank) / 2</b>;</div><div style="font-size: 9px;">ListIterator&lt;Sample&gt; iterator = samples.listIterator();</div><div style="font-size: 9px;">while (iterator.hasNext()) {</div><div style="font-size: 9px;">&nbsp; &nbsp; Sample sample = iterator.next();</div><div style="font-size: 9px;">&nbsp; &nbsp; if (<b style="font-size: 9px;">r + sample.g + sample.delta</b> &gt; upperBound) {<span style="white-space: pre;">	</span><font color="#007fff">//超过上边界索引就取前一个观测值</font></div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; iterator.previous(); // roll back the item.next() above</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; if (iterator.hasPrevious()) {</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Sample result = iterator.previous();</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <b style="font-size: 9px;">return</b> result.value;</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; } else {</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <b style="font-size: 9px;">return</b> sample.value;</div><div style="font-size: 9px;">&nbsp; &nbsp; &nbsp; &nbsp; }</div><div style="font-size: 9px;">&nbsp; &nbsp; }</div><div style="font-size: 9px;">&nbsp; &nbsp; <b style="font-size: 9px;">r += sample.g;</b></div><div style="font-size: 9px;">}</div><div style="font-size: 9px;"><b style="font-size: 9px;">return</b> samples.getLast().value; <font color="#007fff">// 逻辑上应该获取 Sample 的 r 值,但是由于 r 值没有接口,且由于此测试的特殊性 r 和&nbsp; value 相等,所以返回 value&nbsp;代替 r</font></div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=9;align=left;arcSize=2;" parent="1" vertex="1">
<mxGeometry x="1480" y="2240" width="440" height="300" as="geometry" />
</mxCell>
<mxCell id="4s08r3_KoatAhovvTcsq-5" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="4s08r3_KoatAhovvTcsq-1" target="4s08r3_KoatAhovvTcsq-4">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="4s08r3_KoatAhovvTcsq-1" value="<div>void <b>insertBatch</b>(double[] sortedBuffer, int toIndex) { <font color="#007fff">// toIndex 即buffer中元素个数</font></div><div>&nbsp; &nbsp; if (toIndex == 0) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; return;</div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; ListIterator&lt;Sample&gt; iterator = samples.listIterator();</div><div>&nbsp; &nbsp; int i = 0; // position in buffer</div><div>&nbsp; &nbsp; int r = 0; // sum of g's left of the current sample</div><div><font color="#007fff">&nbsp; &nbsp; // 这里合并逻辑就是最常规能想到的合并方式</font></div><div>&nbsp; &nbsp; while (iterator.hasNext() &amp;&amp; i &lt; toIndex) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; Sample item = iterator.next();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; while (i &lt; toIndex) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (sortedBuffer[i] &gt; item.value) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div><b><font color="#007fff"><span style="white-space: pre;">	</span>&nbsp; &nbsp; // 插入到旧值前面的新值的 delta = f(r) - 1</font>&nbsp;<br></b></div><div><b><font color="#007fff"><span style="white-space: pre;">	</span>&nbsp; &nbsp; // 比如前面的例子 buffer 中的 2.0 插入到 5.0之前,此时r=1, delta =f(1)-1</font><br></b></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <b>insertBefore</b>(iterator, sortedBuffer[i], <b>r</b>);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; r++; // new item with g=1 was inserted before, so increment r</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; i++;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; n++;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; <b>r += item.g;</b></div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; while (i &lt; toIndex) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; samples.add(new Sample(sortedBuffer[i], 0));</div><div>&nbsp; &nbsp; &nbsp; &nbsp; i++;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; n++;</div><div>&nbsp; &nbsp; }</div><div>}</div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=2;" vertex="1" parent="1">
<mxGeometry x="1720" y="1460" width="440" height="360" as="geometry" />
</mxCell>
<mxCell id="4s08r3_KoatAhovvTcsq-9" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="4s08r3_KoatAhovvTcsq-4" target="4s08r3_KoatAhovvTcsq-8">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="4s08r3_KoatAhovvTcsq-4" value="<div>private void insertBefore(ListIterator&lt;Sample&gt; iterator, double value, int r) {</div><div><font color="#007fff">&nbsp; &nbsp; //被插入目标sample值前面没有更小的值,就直接插入链表头部即可</font></div><div>&nbsp; &nbsp; if (!iterator.hasPrevious()) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; samples.addFirst(new Sample(value, 0));</div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; <font color="#007fff">//找到上一个值,在其后面插入新值,<b>关键是这个 f(r) -1 是做什么的?</b></font></div><div>&nbsp; &nbsp; else {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; iterator.previous();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; iterator.add(new Sample(value, <b>f(r) - 1)</b>);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; iterator.next();</div><div>&nbsp; &nbsp; }</div><div>}</div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=2;" vertex="1" parent="1">
<mxGeometry x="2200" y="1560" width="440" height="160" as="geometry" />
</mxCell>
<mxCell id="4s08r3_KoatAhovvTcsq-7" value="<font color="#007fff">CKMS 算法直接从源码看不太容易理解数据结构中某些字段的含义,所以这里从测试数据入手,<br>对比这两批数据分别 flush() compress() 之后数据变化;<br><br><b>第一批数据 flush() 后,samples:<br></b></font><div><font color="#007fff">0 = {CKMSQuantiles$Sample@1427} "Sample{val=1.000, g=1, delta=0}"</font></div><div><font color="#007fff">1 = {CKMSQuantiles$Sample@1428} "Sample{val=5.000, g=1, delta=0}"</font></div><div><font color="#007fff">2 = {CKMSQuantiles$Sample@1429} "Sample{val=6.000, g=1, delta=0}"</font></div><div><font color="#007fff">3 = {CKMSQuantiles$Sample@1430} "Sample{val=7.000, g=1, delta=0}"</font></div><div><font color="#007fff">4 = {CKMSQuantiles$Sample@1431} "Sample{val=8.000, g=1, delta=0}"</font></div><div><font color="#007fff">5 = {CKMSQuantiles$Sample@1432} "Sample{val=10.000, g=1, delta=0}"</font></div><div><font color="#007fff">6 = {CKMSQuantiles$Sample@1433} "Sample{val=11.000, g=1, delta=0}"</font></div><div><font color="#007fff">7 = {CKMSQuantiles$Sample@1434} "Sample{val=13.000, g=1, delta=0}"</font></div><div><font color="#007fff"><b>第一批数据 compress() 后,samples:</b></font></div><div><font color="#007fff">和上面一组数据比没有变化。</font></div><div><font color="#007fff"><b>第二批数据 flush() 后, samples:</b></font></div><div><font color="#007fff"><div><div>0 = {CKMSQuantiles$Sample@1206} "Sample{val=1.000, g=1, delta=0}"</div><div>1 = {CKMSQuantiles$Sample@1438} "Sample{val=2.000, g=1, delta=1}"</div><div>2 = {CKMSQuantiles$Sample@1439} "Sample{val=3.000, g=1, delta=1}"</div><div>3 = {CKMSQuantiles$Sample@1440} "Sample{val=4.000, g=1, delta=1}"</div><div>4 = {CKMSQuantiles$Sample@1207} "Sample{val=5.000, g=1, delta=0}"</div><div>5 = {CKMSQuantiles$Sample@1208} "Sample{val=6.000, g=1, delta=0}"</div><div>6 = {CKMSQuantiles$Sample@1209} "Sample{val=7.000, g=1, delta=0}"</div><div>7 = {CKMSQuantiles$Sample@1210} "Sample{val=8.000, g=1, delta=0}"</div><div>8 = {CKMSQuantiles$Sample@1441} "Sample{val=9.000, g=1, delta=2}"</div><div>9 = {CKMSQuantiles$Sample@1211} "Sample{val=10.000, g=1, delta=0}"</div><div>10 = {CKMSQuantiles$Sample@1212} "Sample{val=11.000, g=1, delta=0}"</div><div>11 = {CKMSQuantiles$Sample@1442} "Sample{val=12.000, g=1, delta=3}"</div><div>12 = {CKMSQuantiles$Sample@1213} "Sample{val=13.000, g=1, delta=0}"</div><div>13 = {CKMSQuantiles$Sample@1443} "Sample{val=14.000, g=1, delta=0}"</div><div>14 = {CKMSQuantiles$Sample@1444} "Sample{val=15.000, g=1, delta=0}"</div><div>15 = {CKMSQuantiles$Sample@1445} "Sample{val=16.000, g=1, delta=0}"</div></div><div><b>第二批数据 compress() 后,samples:</b><br></div><div><div style="">0 = {CKMSQuantiles$Sample@1206} "Sample{val=1.000, g=1, delta=0}"</div><div style="">1 = {CKMSQuantiles$Sample@1207} "Sample{val=5.000, g=4, delta=0}"</div><div style="">2 = {CKMSQuantiles$Sample@1210} "Sample{val=8.000, g=3, delta=0}"</div><div style="">3 = {CKMSQuantiles$Sample@1211} "Sample{val=10.000, g=2, delta=0}"</div><div style="">4 = {CKMSQuantiles$Sample@1213} "Sample{val=13.000, g=3, delta=0}"</div><div style="">5 = {CKMSQuantiles$Sample@1442} "Sample{val=16.000, g=3, delta=0}"</div></div><div><b><br></b></div></font></div>" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontSize=10;" vertex="1" parent="1">
<mxGeometry x="280" y="1680" width="450" height="480" as="geometry" />
</mxCell>
<mxCell id="4s08r3_KoatAhovvTcsq-8" value="<div><b>int f(int r)</b> {</div><div>&nbsp; &nbsp; int minResult = Integer.MAX_VALUE;</div><div>&nbsp; &nbsp; for (Quantile q : quantiles) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; if (q.quantile == 0 || q.quantile == 1) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; continue;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; int result;</div><div><span style=""><span style="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span></span><font color="#007fff">// 以前面的例子第二批数据flush(),当 2.0 插入到 5.0 前面,r=1, quantile=0.5, n=8<br></font></div><div><div><font color="#007fff"><span style="white-space: pre;">	</span>//delta 的计算方式:<span style=""></span></font></div><div><font color="#007fff">&nbsp; &nbsp; &nbsp; &nbsp; //对于 r &gt;= q.quantile * n 的元素, 即 &gt;= 期望元素索引的元素</font></div><div><font color="#007fff">&nbsp; &nbsp; &nbsp; &nbsp; // delta = (int) 2*epsilon*r/quantile - 1</font></div><div><font color="#007fff">&nbsp; &nbsp; &nbsp; &nbsp; //对于 r &lt; q.quantile * n 的元素</font></div><div><font color="#007fff">&nbsp; &nbsp; &nbsp; &nbsp; // delta = (int) 2*epsilon*(n-r)/(1-quantile) - 1, 当前例子就是 delta = 1</font></div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; if (r &gt;= q.quantile * n) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result = (int) (q.v * r + 0.00000000001);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; } else {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result = (int) (q.u * (n - r) + 0.00000000001);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; if (result &lt; minResult) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; minResult = result;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; return Math.max(minResult, 1);</div><div>}</div><div><br></div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=2;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxGeometry x="2680" y="1480" width="440" height="320" as="geometry" />
</mxCell>
<mxCell id="4s08r3_KoatAhovvTcsq-10" value="<div>void <b>compress</b>() {</div><div>&nbsp; &nbsp; if (samples.size() &lt; 3) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; return;</div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; Iterator&lt;Sample&gt; descendingIterator = samples.descendingIterator();</div><div><font color="#007fff">&nbsp; &nbsp; // 假设 1 2 3 4 5,从未压缩过,初始 r= 5</font></div><div>&nbsp; &nbsp; int r = n; // n is equal to the sum of the g's of all samples</div><div>&nbsp; &nbsp; Sample right; <font color="#007fff">//右值,即大值</font></div><div>&nbsp; &nbsp; Sample left = descendingIterator.next(); <font color="#007fff">//挨着右值的小值</font></div><div>&nbsp; &nbsp; r -= left.g;<span style=""><span style="">&nbsp;&nbsp;&nbsp;&nbsp;<font color="#007fff">// </font></span></span><font color="#007fff">r 其实是元素在历史中所有被统计的元素中的索引,这里 r 指 left 元素的历史索引</font></div><div><font color="#007fff">&nbsp; &nbsp; // 倒序遍历,即从大值开始压缩</font></div><div>&nbsp; &nbsp; while (descendingIterator.hasNext()) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; right = left;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; left = descendingIterator.next();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; r = r - left.g;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; if (left == samples.getFirst()) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // The min sample must never be merged.</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><font color="#007fff">&nbsp; &nbsp; &nbsp; &nbsp; // 压缩条件:left.g + right.g + right.delta &lt; f(r)</font><br><div><font color="#007fff"><span style=""><span style="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span></span>// 小值删除,大值的g加上小值的g,&nbsp;<br></font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; if (<b>left.g + right.g + right.delta &lt; f(r)</b>) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; right.g += left.g;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; descendingIterator.remove();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; left = right;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; }</div><div>}</div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=10;align=left;arcSize=2;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxGeometry x="1480" y="1840" width="440" height="360" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>