1use async_stream::stream;
13use mz_persist_types::stats::PartStatsMetrics;
14use std::collections::BTreeMap;
15use std::sync::{Arc, Mutex, Weak};
16use std::time::{Duration, Instant};
17use tokio::sync::{OnceCell, OwnedSemaphorePermit, Semaphore};
18
19use async_trait::async_trait;
20use bytes::Bytes;
21use futures_util::StreamExt;
22use mz_ore::bytes::SegmentedBytes;
23use mz_ore::cast::{CastFrom, CastLossy};
24use mz_ore::instrument;
25use mz_ore::metric;
26use mz_ore::metrics::{
27 ComputedGauge, ComputedIntGauge, ComputedUIntGauge, Counter, DeleteOnDropCounter,
28 DeleteOnDropGauge, IntCounter, MakeCollector, MetricVecExt, MetricsRegistry, UIntGauge,
29 UIntGaugeVec, raw,
30};
31use mz_ore::stats::histogram_seconds_buckets;
32use mz_persist::location::{
33 Blob, BlobMetadata, CaSResult, Consensus, ExternalError, ResultStream, SeqNo, VersionedData,
34};
35use mz_persist::metrics::{ColumnarMetrics, S3BlobMetrics};
36use mz_persist::retry::RetryStream;
37use mz_persist_types::Codec64;
38use mz_postgres_client::metrics::PostgresClientMetrics;
39use prometheus::core::{AtomicI64, AtomicU64, Collector, Desc, GenericGauge};
40use prometheus::proto::MetricFamily;
41use prometheus::{CounterVec, Gauge, GaugeVec, Histogram, HistogramVec, IntCounterVec};
42use timely::progress::Antichain;
43use tokio_metrics::TaskMonitor;
44use tracing::{Instrument, debug, info, info_span};
45
46use crate::fetch::{FETCH_SEMAPHORE_COST_ADJUSTMENT, FETCH_SEMAPHORE_PERMIT_ADJUSTMENT};
47use crate::internal::paths::BlobKey;
48use crate::{PersistConfig, ShardId};
49
50pub struct Metrics {
55 _vecs: MetricsVecs,
56 _uptime: ComputedGauge,
57
58 pub blob: BlobMetrics,
60 pub consensus: ConsensusMetrics,
62 pub cmds: CmdsMetrics,
64 pub retries: RetriesMetrics,
66 pub user: BatchWriteMetrics,
69 pub read: BatchPartReadMetrics,
71 pub compaction: CompactionMetrics,
73 pub gc: GcMetrics,
75 pub lease: LeaseMetrics,
77 pub codecs: CodecsMetrics,
79 pub state: StateMetrics,
81 pub shards: ShardsMetrics,
83 pub audit: UsageAuditMetrics,
85 pub locks: LocksMetrics,
87 pub watch: WatchMetrics,
89 pub pubsub_client: PubSubClientMetrics,
91 pub pushdown: PushdownMetrics,
93 pub consolidation: ConsolidationMetrics,
95 pub blob_cache_mem: BlobMemCache,
97 pub tasks: TasksMetrics,
99 pub columnar: ColumnarMetrics,
101 pub schema: SchemaMetrics,
103 pub inline: InlineMetrics,
105 pub(crate) semaphore: SemaphoreMetrics,
107
108 pub sink: SinkMetrics,
110
111 pub s3_blob: S3BlobMetrics,
113 pub postgres_consensus: PostgresClientMetrics,
115
116 #[allow(dead_code)]
117 pub(crate) registry: MetricsRegistry,
118}
119
120impl std::fmt::Debug for Metrics {
121 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122 f.debug_struct("Metrics").finish_non_exhaustive()
123 }
124}
125
126impl Metrics {
127 pub fn new(cfg: &PersistConfig, registry: &MetricsRegistry) -> Self {
129 let vecs = MetricsVecs::new(registry);
130 let start = Instant::now();
131 let uptime = registry.register_computed_gauge(
132 metric!(
133 name: "mz_persist_metadata_seconds",
134 help: "server uptime, labels are build metadata",
135 const_labels: {
136 "version" => cfg.build_version,
137 "build_type" => if cfg!(release) { "release" } else { "debug" }
138 },
139 ),
140 move || start.elapsed().as_secs_f64(),
141 );
142 let s3_blob = S3BlobMetrics::new(registry);
143 let columnar = ColumnarMetrics::new(registry);
144 Metrics {
145 blob: vecs.blob_metrics(),
146 consensus: vecs.consensus_metrics(),
147 cmds: vecs.cmds_metrics(registry),
148 retries: vecs.retries_metrics(),
149 codecs: vecs.codecs_metrics(),
150 user: BatchWriteMetrics::new(registry, "user"),
151 read: vecs.batch_part_read_metrics(),
152 compaction: CompactionMetrics::new(registry),
153 gc: GcMetrics::new(registry),
154 lease: LeaseMetrics::new(registry),
155 state: StateMetrics::new(registry),
156 shards: ShardsMetrics::new(registry),
157 audit: UsageAuditMetrics::new(registry),
158 locks: vecs.locks_metrics(),
159 watch: WatchMetrics::new(registry),
160 pubsub_client: PubSubClientMetrics::new(registry),
161 pushdown: PushdownMetrics::new(registry),
162 consolidation: ConsolidationMetrics::new(registry),
163 blob_cache_mem: BlobMemCache::new(registry),
164 tasks: TasksMetrics::new(registry),
165 columnar,
166 schema: SchemaMetrics::new(registry),
167 inline: InlineMetrics::new(registry),
168 semaphore: SemaphoreMetrics::new(cfg.clone(), registry.clone()),
169 sink: SinkMetrics::new(registry),
170 s3_blob,
171 postgres_consensus: PostgresClientMetrics::new(registry, "mz_persist"),
172 _vecs: vecs,
173 _uptime: uptime,
174 registry: registry.clone(),
175 }
176 }
177
178 pub fn write_amplification(&self) -> f64 {
183 let total_written = self.blob.set.bytes.get();
186 let user_written = self.user.goodbytes.get();
187 #[allow(clippy::as_conversions)]
188 {
189 total_written as f64 / user_written as f64
190 }
191 }
192}
193
194#[derive(Debug)]
195struct MetricsVecs {
196 cmd_started: IntCounterVec,
197 cmd_cas_mismatch: IntCounterVec,
198 cmd_succeeded: IntCounterVec,
199 cmd_failed: IntCounterVec,
200 cmd_seconds: CounterVec,
201
202 external_op_started: IntCounterVec,
203 external_op_succeeded: IntCounterVec,
204 external_op_failed: IntCounterVec,
205 external_op_bytes: IntCounterVec,
206 external_op_seconds: CounterVec,
207 external_consensus_truncated_count: IntCounter,
208 external_blob_delete_noop_count: IntCounter,
209 external_blob_sizes: Histogram,
210 external_rtt_latency: GaugeVec,
211 external_op_latency: HistogramVec,
212
213 retry_started: IntCounterVec,
214 retry_finished: IntCounterVec,
215 retry_retries: IntCounterVec,
216 retry_sleep_seconds: CounterVec,
217
218 encode_count: IntCounterVec,
219 encode_seconds: CounterVec,
220 decode_count: IntCounterVec,
221 decode_seconds: CounterVec,
222
223 read_part_bytes: IntCounterVec,
224 read_part_goodbytes: IntCounterVec,
225 read_part_count: IntCounterVec,
226 read_part_seconds: CounterVec,
227 read_ts_rewrite: IntCounterVec,
228
229 lock_acquire_count: IntCounterVec,
230 lock_blocking_acquire_count: IntCounterVec,
231 lock_blocking_seconds: CounterVec,
232
233 alerts_metrics: Arc<AlertsMetrics>,
235}
236
237impl MetricsVecs {
238 fn new(registry: &MetricsRegistry) -> Self {
239 MetricsVecs {
240 cmd_started: registry.register(metric!(
241 name: "mz_persist_cmd_started_count",
242 help: "count of commands started",
243 var_labels: ["cmd"],
244 )),
245 cmd_cas_mismatch: registry.register(metric!(
246 name: "mz_persist_cmd_cas_mismatch_count",
247 help: "count of command retries from CaS mismatch",
248 var_labels: ["cmd"],
249 )),
250 cmd_succeeded: registry.register(metric!(
251 name: "mz_persist_cmd_succeeded_count",
252 help: "count of commands succeeded",
253 var_labels: ["cmd"],
254 )),
255 cmd_failed: registry.register(metric!(
256 name: "mz_persist_cmd_failed_count",
257 help: "count of commands failed",
258 var_labels: ["cmd"],
259 )),
260 cmd_seconds: registry.register(metric!(
261 name: "mz_persist_cmd_seconds",
262 help: "time spent applying commands",
263 var_labels: ["cmd"],
264 )),
265
266 external_op_started: registry.register(metric!(
267 name: "mz_persist_external_started_count",
268 help: "count of external service calls started",
269 var_labels: ["op"],
270 )),
271 external_op_succeeded: registry.register(metric!(
272 name: "mz_persist_external_succeeded_count",
273 help: "count of external service calls succeeded",
274 var_labels: ["op"],
275 )),
276 external_op_failed: registry.register(metric!(
277 name: "mz_persist_external_failed_count",
278 help: "count of external service calls failed",
279 var_labels: ["op"],
280 )),
281 external_op_bytes: registry.register(metric!(
282 name: "mz_persist_external_bytes_count",
283 help: "total size represented by external service calls",
284 var_labels: ["op"],
285 )),
286 external_op_seconds: registry.register(metric!(
287 name: "mz_persist_external_seconds",
288 help: "time spent in external service calls",
289 var_labels: ["op"],
290 )),
291 external_consensus_truncated_count: registry.register(metric!(
292 name: "mz_persist_external_consensus_truncated_count",
293 help: "count of versions deleted by consensus truncate calls",
294 )),
295 external_blob_delete_noop_count: registry.register(metric!(
296 name: "mz_persist_external_blob_delete_noop_count",
297 help: "count of blob delete calls that deleted a non-existent key",
298 )),
299 external_blob_sizes: registry.register(metric!(
300 name: "mz_persist_external_blob_sizes",
301 help: "histogram of blob sizes at put time",
302 buckets: mz_ore::stats::HISTOGRAM_BYTE_BUCKETS.to_vec(),
303 )),
304 external_rtt_latency: registry.register(metric!(
305 name: "mz_persist_external_rtt_latency",
306 help: "roundtrip-time to external service as seen by this process",
307 var_labels: ["external"],
308 )),
309 external_op_latency: registry.register(metric!(
310 name: "mz_persist_external_op_latency",
311 help: "rountrip latency observed by individual performance-critical operations",
312 var_labels: ["op"],
313 buckets: histogram_seconds_buckets(0.000_500, 32.0),
316 )),
317
318 retry_started: registry.register(metric!(
319 name: "mz_persist_retry_started_count",
320 help: "count of retry loops started",
321 var_labels: ["op"],
322 )),
323 retry_finished: registry.register(metric!(
324 name: "mz_persist_retry_finished_count",
325 help: "count of retry loops finished",
326 var_labels: ["op"],
327 )),
328 retry_retries: registry.register(metric!(
329 name: "mz_persist_retry_retries_count",
330 help: "count of total attempts by retry loops",
331 var_labels: ["op"],
332 )),
333 retry_sleep_seconds: registry.register(metric!(
334 name: "mz_persist_retry_sleep_seconds",
335 help: "time spent in retry loop backoff",
336 var_labels: ["op"],
337 )),
338
339 encode_count: registry.register(metric!(
340 name: "mz_persist_encode_count",
341 help: "count of op encodes",
342 var_labels: ["op"],
343 )),
344 encode_seconds: registry.register(metric!(
345 name: "mz_persist_encode_seconds",
346 help: "time spent in op encodes",
347 var_labels: ["op"],
348 )),
349 decode_count: registry.register(metric!(
350 name: "mz_persist_decode_count",
351 help: "count of op decodes",
352 var_labels: ["op"],
353 )),
354 decode_seconds: registry.register(metric!(
355 name: "mz_persist_decode_seconds",
356 help: "time spent in op decodes",
357 var_labels: ["op"],
358 )),
359
360 read_part_bytes: registry.register(metric!(
361 name: "mz_persist_read_batch_part_bytes",
362 help: "total encoded size of batch parts read",
363 var_labels: ["op"],
364 )),
365 read_part_goodbytes: registry.register(metric!(
366 name: "mz_persist_read_batch_part_goodbytes",
367 help: "total logical size of batch parts read",
368 var_labels: ["op"],
369 )),
370 read_part_count: registry.register(metric!(
371 name: "mz_persist_read_batch_part_count",
372 help: "count of batch parts read",
373 var_labels: ["op"],
374 )),
375 read_part_seconds: registry.register(metric!(
376 name: "mz_persist_read_batch_part_seconds",
377 help: "time spent reading batch parts",
378 var_labels: ["op"],
379 )),
380 read_ts_rewrite: registry.register(metric!(
381 name: "mz_persist_read_ts_rewite",
382 help: "count of updates read with rewritten ts",
383 var_labels: ["op"],
384 )),
385
386 lock_acquire_count: registry.register(metric!(
387 name: "mz_persist_lock_acquire_count",
388 help: "count of locks acquired",
389 var_labels: ["op"],
390 )),
391 lock_blocking_acquire_count: registry.register(metric!(
392 name: "mz_persist_lock_blocking_acquire_count",
393 help: "count of locks acquired that required blocking",
394 var_labels: ["op"],
395 )),
396 lock_blocking_seconds: registry.register(metric!(
397 name: "mz_persist_lock_blocking_seconds",
398 help: "time spent blocked for a lock",
399 var_labels: ["op"],
400 )),
401
402 alerts_metrics: Arc::new(AlertsMetrics::new(registry)),
403 }
404 }
405
406 fn cmds_metrics(&self, registry: &MetricsRegistry) -> CmdsMetrics {
407 CmdsMetrics {
408 init_state: self.cmd_metrics("init_state"),
409 add_rollup: self.cmd_metrics("add_rollup"),
410 remove_rollups: self.cmd_metrics("remove_rollups"),
411 upgrade_version: self.cmd_metrics("upgrade_version"),
412 register: self.cmd_metrics("register"),
413 compare_and_append: self.cmd_metrics("compare_and_append"),
414 compare_and_append_noop: registry.register(metric!(
415 name: "mz_persist_cmd_compare_and_append_noop",
416 help: "count of compare_and_append retries that were discoverd to have already committed",
417 )),
418 compare_and_downgrade_since: self.cmd_metrics("compare_and_downgrade_since"),
419 downgrade_since: self.cmd_metrics("downgrade_since"),
420 expire_reader: self.cmd_metrics("expire_reader"),
421 expire_writer: self.cmd_metrics("expire_writer"),
422 merge_res: self.cmd_metrics("merge_res"),
423 become_tombstone: self.cmd_metrics("become_tombstone"),
424 compare_and_evolve_schema: self.cmd_metrics("compare_and_evolve_schema"),
425 spine_exert: self.cmd_metrics("spine_exert"),
426 fetch_upper_count: registry.register(metric!(
427 name: "mz_persist_cmd_fetch_upper_count",
428 help: "count of fetch_upper calls",
429 ))
430 }
431 }
432
433 fn cmd_metrics(&self, cmd: &str) -> CmdMetrics {
434 CmdMetrics {
435 name: cmd.to_owned(),
436 started: self.cmd_started.with_label_values(&[cmd]),
437 succeeded: self.cmd_succeeded.with_label_values(&[cmd]),
438 cas_mismatch: self.cmd_cas_mismatch.with_label_values(&[cmd]),
439 failed: self.cmd_failed.with_label_values(&[cmd]),
440 seconds: self.cmd_seconds.with_label_values(&[cmd]),
441 }
442 }
443
444 fn retries_metrics(&self) -> RetriesMetrics {
445 RetriesMetrics {
446 determinate: RetryDeterminate {
447 apply_unbatched_cmd_cas: self.retry_metrics("apply_unbatched_cmd::cas"),
448 },
449 external: RetryExternal {
450 batch_delete: Arc::new(self.retry_metrics("batch::delete")),
451 batch_set: self.retry_metrics("batch::set"),
452 blob_open: self.retry_metrics("blob::open"),
453 compaction_noop_delete: Arc::new(self.retry_metrics("compaction_noop::delete")),
454 consensus_open: self.retry_metrics("consensus::open"),
455 fetch_batch_get: self.retry_metrics("fetch_batch::get"),
456 fetch_state_scan: self.retry_metrics("fetch_state::scan"),
457 gc_truncate: self.retry_metrics("gc::truncate"),
458 maybe_init_cas: self.retry_metrics("maybe_init::cas"),
459 rollup_delete: self.retry_metrics("rollup::delete"),
460 rollup_get: self.retry_metrics("rollup::get"),
461 rollup_set: self.retry_metrics("rollup::set"),
462 hollow_run_get: self.retry_metrics("hollow_run::get"),
463 hollow_run_set: self.retry_metrics("hollow_run::set"),
464 storage_usage_shard_size: self.retry_metrics("storage_usage::shard_size"),
465 },
466 compare_and_append_idempotent: self.retry_metrics("compare_and_append_idempotent"),
467 fetch_latest_state: self.retry_metrics("fetch_latest_state"),
468 fetch_live_states: self.retry_metrics("fetch_live_states"),
469 idempotent_cmd: self.retry_metrics("idempotent_cmd"),
470 next_listen_batch: self.retry_metrics("next_listen_batch"),
471 snapshot: self.retry_metrics("snapshot"),
472 }
473 }
474
475 fn retry_metrics(&self, name: &str) -> RetryMetrics {
476 RetryMetrics {
477 name: name.to_owned(),
478 started: self.retry_started.with_label_values(&[name]),
479 finished: self.retry_finished.with_label_values(&[name]),
480 retries: self.retry_retries.with_label_values(&[name]),
481 sleep_seconds: self.retry_sleep_seconds.with_label_values(&[name]),
482 }
483 }
484
485 fn codecs_metrics(&self) -> CodecsMetrics {
486 CodecsMetrics {
487 state: self.codec_metrics("state"),
488 state_diff: self.codec_metrics("state_diff"),
489 batch: self.codec_metrics("batch"),
490 key: self.codec_metrics("key"),
491 val: self.codec_metrics("val"),
492 }
493 }
494
495 fn codec_metrics(&self, op: &str) -> CodecMetrics {
496 CodecMetrics {
497 encode_count: self.encode_count.with_label_values(&[op]),
498 encode_seconds: self.encode_seconds.with_label_values(&[op]),
499 decode_count: self.decode_count.with_label_values(&[op]),
500 decode_seconds: self.decode_seconds.with_label_values(&[op]),
501 }
502 }
503
504 fn blob_metrics(&self) -> BlobMetrics {
505 BlobMetrics {
506 set: self.external_op_metrics("blob_set", true),
507 get: self.external_op_metrics("blob_get", true),
508 list_keys: self.external_op_metrics("blob_list_keys", false),
509 delete: self.external_op_metrics("blob_delete", false),
510 restore: self.external_op_metrics("restore", false),
511 delete_noop: self.external_blob_delete_noop_count.clone(),
512 blob_sizes: self.external_blob_sizes.clone(),
513 rtt_latency: self.external_rtt_latency.with_label_values(&["blob"]),
514 }
515 }
516
517 fn consensus_metrics(&self) -> ConsensusMetrics {
518 ConsensusMetrics {
519 list_keys: self.external_op_metrics("consensus_list_keys", false),
520 head: self.external_op_metrics("consensus_head", false),
521 compare_and_set: self.external_op_metrics("consensus_cas", true),
522 scan: self.external_op_metrics("consensus_scan", false),
523 truncate: self.external_op_metrics("consensus_truncate", false),
524 truncated_count: self.external_consensus_truncated_count.clone(),
525 rtt_latency: self.external_rtt_latency.with_label_values(&["consensus"]),
526 }
527 }
528
529 fn external_op_metrics(&self, op: &str, latency_histogram: bool) -> ExternalOpMetrics {
530 ExternalOpMetrics {
531 started: self.external_op_started.with_label_values(&[op]),
532 succeeded: self.external_op_succeeded.with_label_values(&[op]),
533 failed: self.external_op_failed.with_label_values(&[op]),
534 bytes: self.external_op_bytes.with_label_values(&[op]),
535 seconds: self.external_op_seconds.with_label_values(&[op]),
536 seconds_histogram: if latency_histogram {
537 Some(self.external_op_latency.with_label_values(&[op]))
538 } else {
539 None
540 },
541 alerts_metrics: Arc::clone(&self.alerts_metrics),
542 }
543 }
544
545 fn batch_part_read_metrics(&self) -> BatchPartReadMetrics {
546 BatchPartReadMetrics {
547 listen: self.read_metrics("listen"),
548 snapshot: self.read_metrics("snapshot"),
549 batch_fetcher: self.read_metrics("batch_fetcher"),
550 compaction: self.read_metrics("compaction"),
551 unindexed: self.read_metrics("unindexed"),
552 }
553 }
554
555 fn read_metrics(&self, op: &str) -> ReadMetrics {
556 ReadMetrics {
557 part_bytes: self.read_part_bytes.with_label_values(&[op]),
558 part_goodbytes: self.read_part_goodbytes.with_label_values(&[op]),
559 part_count: self.read_part_count.with_label_values(&[op]),
560 seconds: self.read_part_seconds.with_label_values(&[op]),
561 ts_rewrite: self.read_ts_rewrite.with_label_values(&[op]),
562 }
563 }
564
565 fn locks_metrics(&self) -> LocksMetrics {
566 LocksMetrics {
567 applier_read_cacheable: self.lock_metrics("applier_read_cacheable"),
568 applier_read_noncacheable: self.lock_metrics("applier_read_noncacheable"),
569 applier_write: self.lock_metrics("applier_write"),
570 watch: self.lock_metrics("watch"),
571 }
572 }
573
574 fn lock_metrics(&self, op: &str) -> LockMetrics {
575 LockMetrics {
576 acquire_count: self.lock_acquire_count.with_label_values(&[op]),
577 blocking_acquire_count: self.lock_blocking_acquire_count.with_label_values(&[op]),
578 blocking_seconds: self.lock_blocking_seconds.with_label_values(&[op]),
579 }
580 }
581}
582
583#[derive(Debug)]
584pub struct CmdMetrics {
585 pub(crate) name: String,
586 pub(crate) started: IntCounter,
587 pub(crate) cas_mismatch: IntCounter,
588 pub(crate) succeeded: IntCounter,
589 pub(crate) failed: IntCounter,
590 pub(crate) seconds: Counter,
591}
592
593impl CmdMetrics {
594 pub async fn run_cmd<R, E, F, CmdFn>(
595 &self,
596 shard_metrics: &ShardMetrics,
597 cmd_fn: CmdFn,
598 ) -> Result<R, E>
599 where
600 F: std::future::Future<Output = Result<R, E>>,
601 CmdFn: FnOnce() -> F,
602 {
603 self.started.inc();
604 let start = Instant::now();
605 let res = cmd_fn().await;
606 self.seconds.inc_by(start.elapsed().as_secs_f64());
607 match res.as_ref() {
608 Ok(_) => {
609 self.succeeded.inc();
610 shard_metrics.cmd_succeeded.inc();
611 }
612 Err(_) => self.failed.inc(),
613 };
614 res
615 }
616}
617
618#[derive(Debug)]
619pub struct CmdsMetrics {
620 pub(crate) init_state: CmdMetrics,
621 pub(crate) add_rollup: CmdMetrics,
622 pub(crate) remove_rollups: CmdMetrics,
623 pub(crate) upgrade_version: CmdMetrics,
624 pub(crate) register: CmdMetrics,
625 pub(crate) compare_and_append: CmdMetrics,
626 pub(crate) compare_and_append_noop: IntCounter,
627 pub(crate) compare_and_downgrade_since: CmdMetrics,
628 pub(crate) downgrade_since: CmdMetrics,
629 pub(crate) expire_reader: CmdMetrics,
630 pub(crate) expire_writer: CmdMetrics,
631 pub(crate) merge_res: CmdMetrics,
632 pub(crate) become_tombstone: CmdMetrics,
633 pub(crate) compare_and_evolve_schema: CmdMetrics,
634 pub(crate) spine_exert: CmdMetrics,
635 pub(crate) fetch_upper_count: IntCounter,
636}
637
638#[derive(Debug)]
639pub struct RetryMetrics {
640 pub(crate) name: String,
641 pub(crate) started: IntCounter,
642 pub(crate) finished: IntCounter,
643 pub(crate) retries: IntCounter,
644 pub(crate) sleep_seconds: Counter,
645}
646
647impl RetryMetrics {
648 pub(crate) fn stream(&self, retry: RetryStream) -> MetricsRetryStream {
649 MetricsRetryStream::new(retry, self)
650 }
651}
652
653#[derive(Debug)]
654pub struct RetryDeterminate {
655 pub(crate) apply_unbatched_cmd_cas: RetryMetrics,
656}
657
658#[derive(Debug)]
659pub struct RetryExternal {
660 pub(crate) batch_delete: Arc<RetryMetrics>,
661 pub(crate) batch_set: RetryMetrics,
662 pub(crate) blob_open: RetryMetrics,
663 pub(crate) compaction_noop_delete: Arc<RetryMetrics>,
664 pub(crate) consensus_open: RetryMetrics,
665 pub(crate) fetch_batch_get: RetryMetrics,
666 pub(crate) fetch_state_scan: RetryMetrics,
667 pub(crate) gc_truncate: RetryMetrics,
668 pub(crate) maybe_init_cas: RetryMetrics,
669 pub(crate) rollup_delete: RetryMetrics,
670 pub(crate) rollup_get: RetryMetrics,
671 pub(crate) rollup_set: RetryMetrics,
672 pub(crate) hollow_run_get: RetryMetrics,
673 pub(crate) hollow_run_set: RetryMetrics,
674 pub(crate) storage_usage_shard_size: RetryMetrics,
675}
676
677#[derive(Debug)]
678pub struct RetriesMetrics {
679 pub(crate) determinate: RetryDeterminate,
680 pub(crate) external: RetryExternal,
681
682 pub(crate) compare_and_append_idempotent: RetryMetrics,
683 pub(crate) fetch_latest_state: RetryMetrics,
684 pub(crate) fetch_live_states: RetryMetrics,
685 pub(crate) idempotent_cmd: RetryMetrics,
686 pub(crate) next_listen_batch: RetryMetrics,
687 pub(crate) snapshot: RetryMetrics,
688}
689
690#[derive(Debug)]
691pub struct BatchPartReadMetrics {
692 pub(crate) listen: ReadMetrics,
693 pub(crate) snapshot: ReadMetrics,
694 pub(crate) batch_fetcher: ReadMetrics,
695 pub(crate) compaction: ReadMetrics,
696 pub(crate) unindexed: ReadMetrics,
697}
698
699#[derive(Debug, Clone)]
700pub struct ReadMetrics {
701 pub(crate) part_bytes: IntCounter,
702 pub(crate) part_goodbytes: IntCounter,
703 pub(crate) part_count: IntCounter,
704 pub(crate) seconds: Counter,
705 pub(crate) ts_rewrite: IntCounter,
706}
707
708#[derive(Debug, Clone)]
711pub struct BatchWriteMetrics {
712 pub(crate) bytes: IntCounter,
713 pub(crate) goodbytes: IntCounter,
714 pub(crate) seconds: Counter,
715 pub(crate) write_stalls: IntCounter,
716 pub(crate) key_lower_too_big: IntCounter,
717
718 pub(crate) unordered: IntCounter,
719 pub(crate) codec_order: IntCounter,
720 pub(crate) structured_order: IntCounter,
721 _order_counts: IntCounterVec,
722
723 pub(crate) step_stats: Counter,
724 pub(crate) step_part_writing: Counter,
725 pub(crate) step_inline: Counter,
726}
727
728impl BatchWriteMetrics {
729 fn new(registry: &MetricsRegistry, name: &str) -> Self {
730 let order_counts: IntCounterVec = registry.register(metric!(
731 name: format!("mz_persist_{}_write_batch_order", name),
732 help: "count of batches by the data ordering",
733 var_labels: ["order"],
734 ));
735 let unordered = order_counts.with_label_values(&["unordered"]);
736 let codec_order = order_counts.with_label_values(&["codec"]);
737 let structured_order = order_counts.with_label_values(&["structured"]);
738
739 BatchWriteMetrics {
740 bytes: registry.register(metric!(
741 name: format!("mz_persist_{}_bytes", name),
742 help: format!("total encoded size of {} batches written", name),
743 )),
744 goodbytes: registry.register(metric!(
745 name: format!("mz_persist_{}_goodbytes", name),
746 help: format!("total logical size of {} batches written", name),
747 )),
748 seconds: registry.register(metric!(
749 name: format!("mz_persist_{}_write_batch_part_seconds", name),
750 help: format!("time spent writing {} batches", name),
751 )),
752 write_stalls: registry.register(metric!(
753 name: format!("mz_persist_{}_write_stall_count", name),
754 help: format!(
755 "count of {} writes stalling to await max outstanding reqs",
756 name
757 ),
758 )),
759 key_lower_too_big: registry.register(metric!(
760 name: format!("mz_persist_{}_key_lower_too_big", name),
761 help: format!(
762 "count of {} writes that were unable to write a key lower, because the size threshold was too low",
763 name
764 ),
765 )),
766 unordered,
767 codec_order,
768 structured_order,
769 _order_counts: order_counts,
770 step_stats: registry.register(metric!(
771 name: format!("mz_persist_{}_step_stats", name),
772 help: format!("time spent computing {} update stats", name),
773 )),
774 step_part_writing: registry.register(metric!(
775 name: format!("mz_persist_{}_step_part_writing", name),
776 help: format!("blocking time spent writing parts for {} updates", name),
777 )),
778 step_inline: registry.register(metric!(
779 name: format!("mz_persist_{}_step_inline", name),
780 help: format!("time spent encoding {} inline batches", name)
781 )),
782 }
783 }
784}
785
786#[derive(Debug)]
787pub struct CompactionMetrics {
788 pub(crate) requested: IntCounter,
789 pub(crate) dropped: IntCounter,
790 pub(crate) disabled: IntCounter,
791 pub(crate) skipped: IntCounter,
792 pub(crate) started: IntCounter,
793 pub(crate) applied: IntCounter,
794 pub(crate) timed_out: IntCounter,
795 pub(crate) failed: IntCounter,
796 pub(crate) noop: IntCounter,
797 pub(crate) seconds: Counter,
798 pub(crate) concurrency_waits: IntCounter,
799 pub(crate) queued_seconds: Counter,
800 pub(crate) memory_violations: IntCounter,
801 pub(crate) runs_compacted: IntCounter,
802 pub(crate) chunks_compacted: IntCounter,
803 pub(crate) not_all_prefetched: IntCounter,
804 pub(crate) parts_prefetched: IntCounter,
805 pub(crate) parts_waited: IntCounter,
806 pub(crate) fast_path_eligible: IntCounter,
807 pub(crate) admin_count: IntCounter,
808
809 pub(crate) applied_exact_match: IntCounter,
810 pub(crate) applied_subset_match: IntCounter,
811 pub(crate) not_applied_too_many_updates: IntCounter,
812
813 pub(crate) batch: BatchWriteMetrics,
814 pub(crate) steps: CompactionStepTimings,
815 pub(crate) schema_selection: CompactionSchemaSelection,
816
817 pub(crate) _steps_vec: CounterVec,
818}
819
820impl CompactionMetrics {
821 fn new(registry: &MetricsRegistry) -> Self {
822 let step_timings: CounterVec = registry.register(metric!(
823 name: "mz_persist_compaction_step_seconds",
824 help: "time spent on individual steps of compaction",
825 var_labels: ["step"],
826 ));
827 let schema_selection: CounterVec = registry.register(metric!(
828 name: "mz_persist_compaction_schema_selection",
829 help: "count of compactions and how we did schema selection",
830 var_labels: ["selection"],
831 ));
832
833 CompactionMetrics {
834 requested: registry.register(metric!(
835 name: "mz_persist_compaction_requested",
836 help: "count of total compaction requests",
837 )),
838 dropped: registry.register(metric!(
839 name: "mz_persist_compaction_dropped",
840 help: "count of total compaction requests dropped due to a full queue",
841 )),
842 disabled: registry.register(metric!(
843 name: "mz_persist_compaction_disabled",
844 help: "count of total compaction requests dropped because compaction was disabled",
845 )),
846 skipped: registry.register(metric!(
847 name: "mz_persist_compaction_skipped",
848 help: "count of compactions skipped due to heuristics",
849 )),
850 started: registry.register(metric!(
851 name: "mz_persist_compaction_started",
852 help: "count of compactions started",
853 )),
854 failed: registry.register(metric!(
855 name: "mz_persist_compaction_failed",
856 help: "count of compactions failed",
857 )),
858 applied: registry.register(metric!(
859 name: "mz_persist_compaction_applied",
860 help: "count of compactions applied to state",
861 )),
862 timed_out: registry.register(metric!(
863 name: "mz_persist_compaction_timed_out",
864 help: "count of compactions that timed out",
865 )),
866 noop: registry.register(metric!(
867 name: "mz_persist_compaction_noop",
868 help: "count of compactions discarded (obsolete)",
869 )),
870 seconds: registry.register(metric!(
871 name: "mz_persist_compaction_seconds",
872 help: "time spent in compaction",
873 )),
874 concurrency_waits: registry.register(metric!(
875 name: "mz_persist_compaction_concurrency_waits",
876 help: "count of compaction requests that ever blocked due to concurrency limit",
877 )),
878 queued_seconds: registry.register(metric!(
879 name: "mz_persist_compaction_queued_seconds",
880 help: "time that compaction requests spent queued",
881 )),
882 memory_violations: registry.register(metric!(
883 name: "mz_persist_compaction_memory_violations",
884 help: "count of compaction memory requirement violations",
885 )),
886 runs_compacted: registry.register(metric!(
887 name: "mz_persist_compaction_runs_compacted",
888 help: "count of runs compacted",
889 )),
890 chunks_compacted: registry.register(metric!(
891 name: "mz_persist_compaction_chunks_compacted",
892 help: "count of run chunks compacted",
893 )),
894 not_all_prefetched: registry.register(metric!(
895 name: "mz_persist_compaction_not_all_prefetched",
896 help: "count of compactions where not all inputs were prefetched",
897 )),
898 parts_prefetched: registry.register(metric!(
899 name: "mz_persist_compaction_parts_prefetched",
900 help: "count of compaction parts completely prefetched by the time they're needed",
901 )),
902 parts_waited: registry.register(metric!(
903 name: "mz_persist_compaction_parts_waited",
904 help: "count of compaction parts that had to be waited on",
905 )),
906 fast_path_eligible: registry.register(metric!(
907 name: "mz_persist_compaction_fast_path_eligible",
908 help: "count of compaction requests that could have used the fast-path optimization",
909 )),
910 admin_count: registry.register(metric!(
911 name: "mz_persist_compaction_admin_count",
912 help: "count of compaction requests that were performed by admin tooling",
913 )),
914 applied_exact_match: registry.register(metric!(
915 name: "mz_persist_compaction_applied_exact_match",
916 help: "count of merge results that exactly replaced a SpineBatch",
917 )),
918 applied_subset_match: registry.register(metric!(
919 name: "mz_persist_compaction_applied_subset_match",
920 help: "count of merge results that replaced a subset of a SpineBatch",
921 )),
922 not_applied_too_many_updates: registry.register(metric!(
923 name: "mz_persist_compaction_not_applied_too_many_updates",
924 help: "count of merge results that did not apply due to too many updates",
925 )),
926 batch: BatchWriteMetrics::new(registry, "compaction"),
927 steps: CompactionStepTimings::new(step_timings.clone()),
928 schema_selection: CompactionSchemaSelection::new(schema_selection.clone()),
929 _steps_vec: step_timings,
930 }
931 }
932}
933
934#[derive(Debug)]
935pub struct CompactionStepTimings {
936 pub(crate) part_fetch_seconds: Counter,
937 pub(crate) heap_population_seconds: Counter,
938}
939
940impl CompactionStepTimings {
941 fn new(step_timings: CounterVec) -> CompactionStepTimings {
942 CompactionStepTimings {
943 part_fetch_seconds: step_timings.with_label_values(&["part_fetch"]),
944 heap_population_seconds: step_timings.with_label_values(&["heap_population"]),
945 }
946 }
947}
948
949#[derive(Debug)]
950pub struct CompactionSchemaSelection {
951 pub(crate) recent_schema: Counter,
952 pub(crate) no_schema: Counter,
953}
954
955impl CompactionSchemaSelection {
956 fn new(schema_selection: CounterVec) -> CompactionSchemaSelection {
957 CompactionSchemaSelection {
958 recent_schema: schema_selection.with_label_values(&["recent"]),
959 no_schema: schema_selection.with_label_values(&["none"]),
960 }
961 }
962}
963
964#[derive(Debug)]
965pub struct GcMetrics {
966 pub(crate) noop: IntCounter,
967 pub(crate) started: IntCounter,
968 pub(crate) finished: IntCounter,
969 pub(crate) merged: IntCounter,
970 pub(crate) seconds: Counter,
971 pub(crate) steps: GcStepTimings,
972}
973
974#[derive(Debug)]
975pub struct GcStepTimings {
976 pub(crate) find_removable_rollups: Counter,
977 pub(crate) fetch_seconds: Counter,
978 pub(crate) find_deletable_blobs_seconds: Counter,
979 pub(crate) delete_rollup_seconds: Counter,
980 pub(crate) delete_batch_part_seconds: Counter,
981 pub(crate) truncate_diff_seconds: Counter,
982 pub(crate) remove_rollups_from_state: Counter,
983 pub(crate) post_gc_calculations_seconds: Counter,
984}
985
986impl GcStepTimings {
987 fn new(step_timings: CounterVec) -> Self {
988 Self {
989 find_removable_rollups: step_timings.with_label_values(&["find_removable_rollups"]),
990 fetch_seconds: step_timings.with_label_values(&["fetch"]),
991 find_deletable_blobs_seconds: step_timings.with_label_values(&["find_deletable_blobs"]),
992 delete_rollup_seconds: step_timings.with_label_values(&["delete_rollup"]),
993 delete_batch_part_seconds: step_timings.with_label_values(&["delete_batch_part"]),
994 truncate_diff_seconds: step_timings.with_label_values(&["truncate_diff"]),
995 remove_rollups_from_state: step_timings
996 .with_label_values(&["remove_rollups_from_state"]),
997 post_gc_calculations_seconds: step_timings.with_label_values(&["post_gc_calculations"]),
998 }
999 }
1000}
1001
1002impl GcMetrics {
1003 fn new(registry: &MetricsRegistry) -> Self {
1004 let step_timings: CounterVec = registry.register(metric!(
1005 name: "mz_persist_gc_step_seconds",
1006 help: "time spent on individual steps of gc",
1007 var_labels: ["step"],
1008 ));
1009 GcMetrics {
1010 noop: registry.register(metric!(
1011 name: "mz_persist_gc_noop",
1012 help: "count of garbage collections skipped because they were already done",
1013 )),
1014 started: registry.register(metric!(
1015 name: "mz_persist_gc_started",
1016 help: "count of garbage collections started",
1017 )),
1018 finished: registry.register(metric!(
1019 name: "mz_persist_gc_finished",
1020 help: "count of garbage collections finished",
1021 )),
1022 merged: registry.register(metric!(
1023 name: "mz_persist_gc_merged_reqs",
1024 help: "count of garbage collection requests merged",
1025 )),
1026 seconds: registry.register(metric!(
1027 name: "mz_persist_gc_seconds",
1028 help: "time spent in garbage collections",
1029 )),
1030 steps: GcStepTimings::new(step_timings),
1031 }
1032 }
1033}
1034
1035#[derive(Debug)]
1036pub struct LeaseMetrics {
1037 pub(crate) timeout_read: IntCounter,
1038 pub(crate) dropped_part: IntCounter,
1039}
1040
1041impl LeaseMetrics {
1042 fn new(registry: &MetricsRegistry) -> Self {
1043 LeaseMetrics {
1044 timeout_read: registry.register(metric!(
1045 name: "mz_persist_lease_timeout_read",
1046 help: "count of readers whose lease timed out",
1047 )),
1048 dropped_part: registry.register(metric!(
1049 name: "mz_persist_lease_dropped_part",
1050 help: "count of LeasedBatchParts that were dropped without being politely returned",
1051 )),
1052 }
1053 }
1054}
1055
1056struct IncOnDrop(IntCounter);
1057
1058impl Drop for IncOnDrop {
1059 fn drop(&mut self) {
1060 self.0.inc()
1061 }
1062}
1063
1064pub struct MetricsRetryStream {
1065 retry: RetryStream,
1066 pub(crate) retries: IntCounter,
1067 sleep_seconds: Counter,
1068 _finished: IncOnDrop,
1069}
1070
1071impl MetricsRetryStream {
1072 pub fn new(retry: RetryStream, metrics: &RetryMetrics) -> Self {
1073 metrics.started.inc();
1074 MetricsRetryStream {
1075 retry,
1076 retries: metrics.retries.clone(),
1077 sleep_seconds: metrics.sleep_seconds.clone(),
1078 _finished: IncOnDrop(metrics.finished.clone()),
1079 }
1080 }
1081
1082 pub fn attempt(&self) -> usize {
1084 self.retry.attempt()
1085 }
1086
1087 pub fn next_sleep(&self) -> Duration {
1089 self.retry.next_sleep()
1090 }
1091
1092 pub async fn sleep(self) -> Self {
1097 self.retries.inc();
1098 self.sleep_seconds
1099 .inc_by(self.retry.next_sleep().as_secs_f64());
1100 let retry = self.retry.sleep().await;
1101 MetricsRetryStream {
1102 retry,
1103 retries: self.retries,
1104 sleep_seconds: self.sleep_seconds,
1105 _finished: self._finished,
1106 }
1107 }
1108}
1109
1110#[derive(Debug)]
1111pub struct CodecsMetrics {
1112 pub(crate) state: CodecMetrics,
1113 pub(crate) state_diff: CodecMetrics,
1114 pub(crate) batch: CodecMetrics,
1115 pub(crate) key: CodecMetrics,
1116 pub(crate) val: CodecMetrics,
1117 }
1120
1121#[derive(Debug)]
1122pub struct CodecMetrics {
1123 pub(crate) encode_count: IntCounter,
1124 pub(crate) encode_seconds: Counter,
1125 pub(crate) decode_count: IntCounter,
1126 pub(crate) decode_seconds: Counter,
1127}
1128
1129impl CodecMetrics {
1130 pub(crate) fn encode<R, F: FnOnce() -> R>(&self, f: F) -> R {
1131 let now = Instant::now();
1132 let r = f();
1133 self.encode_count.inc();
1134 self.encode_seconds.inc_by(now.elapsed().as_secs_f64());
1135 r
1136 }
1137
1138 pub(crate) fn decode<R, F: FnOnce() -> R>(&self, f: F) -> R {
1139 let now = Instant::now();
1140 let r = f();
1141 self.decode_count.inc();
1142 self.decode_seconds.inc_by(now.elapsed().as_secs_f64());
1143 r
1144 }
1145}
1146
1147#[derive(Debug)]
1148pub struct StateMetrics {
1149 pub(crate) apply_spine_fast_path: IntCounter,
1150 pub(crate) apply_spine_slow_path: IntCounter,
1151 pub(crate) apply_spine_slow_path_lenient: IntCounter,
1152 pub(crate) apply_spine_slow_path_lenient_adjustment: IntCounter,
1153 pub(crate) apply_spine_slow_path_with_reconstruction: IntCounter,
1154 pub(crate) apply_spine_flattened: IntCounter,
1155 pub(crate) update_state_noop_path: IntCounter,
1156 pub(crate) update_state_empty_path: IntCounter,
1157 pub(crate) update_state_fast_path: IntCounter,
1158 pub(crate) update_state_slow_path: IntCounter,
1159 pub(crate) rollup_at_seqno_migration: IntCounter,
1160 pub(crate) fetch_recent_live_diffs_fast_path: IntCounter,
1161 pub(crate) fetch_recent_live_diffs_slow_path: IntCounter,
1162 pub(crate) writer_added: IntCounter,
1163 pub(crate) writer_removed: IntCounter,
1164 pub(crate) force_apply_hostname: IntCounter,
1165 pub(crate) rollup_write_success: IntCounter,
1166 pub(crate) rollup_write_noop_latest: IntCounter,
1167 pub(crate) rollup_write_noop_truncated: IntCounter,
1168}
1169
1170impl StateMetrics {
1171 pub(crate) fn new(registry: &MetricsRegistry) -> Self {
1172 let rollup_write_noop: IntCounterVec = registry.register(metric!(
1173 name: "mz_persist_state_rollup_write_noop",
1174 help: "count of no-op rollup writes",
1175 var_labels: ["reason"],
1176 ));
1177
1178 StateMetrics {
1179 apply_spine_fast_path: registry.register(metric!(
1180 name: "mz_persist_state_apply_spine_fast_path",
1181 help: "count of spine diff applications that hit the fast path",
1182 )),
1183 apply_spine_slow_path: registry.register(metric!(
1184 name: "mz_persist_state_apply_spine_slow_path",
1185 help: "count of spine diff applications that hit the slow path",
1186 )),
1187 apply_spine_slow_path_lenient: registry.register(metric!(
1188 name: "mz_persist_state_apply_spine_slow_path_lenient",
1189 help: "count of spine diff applications that hit the lenient compaction apply path",
1190 )),
1191 apply_spine_slow_path_lenient_adjustment: registry.register(metric!(
1192 name: "mz_persist_state_apply_spine_slow_path_lenient_adjustment",
1193 help: "count of adjustments made by the lenient compaction apply path",
1194 )),
1195 apply_spine_slow_path_with_reconstruction: registry.register(metric!(
1196 name: "mz_persist_state_apply_spine_slow_path_with_reconstruction",
1197 help: "count of spine diff applications that hit the slow path with extra spine reconstruction step",
1198 )),
1199 apply_spine_flattened: registry.register(metric!(
1200 name: "mz_persist_state_apply_spine_flattened",
1201 help: "count of spine diff applications that flatten the trace",
1202 )),
1203 update_state_noop_path: registry.register(metric!(
1204 name: "mz_persist_state_update_state_noop_path",
1205 help: "count of state update applications that no-oped due to shared state",
1206 )),
1207 update_state_empty_path: registry.register(metric!(
1208 name: "mz_persist_state_update_state_empty_path",
1209 help: "count of state update applications that found no new updates",
1210 )),
1211 update_state_fast_path: registry.register(metric!(
1212 name: "mz_persist_state_update_state_fast_path",
1213 help: "count of state update applications that hit the fast path",
1214 )),
1215 update_state_slow_path: registry.register(metric!(
1216 name: "mz_persist_state_update_state_slow_path",
1217 help: "count of state update applications that hit the slow path",
1218 )),
1219 rollup_at_seqno_migration: registry.register(metric!(
1220 name: "mz_persist_state_rollup_at_seqno_migration",
1221 help: "count of fetch_rollup_at_seqno calls that only worked because of the migration",
1222 )),
1223 fetch_recent_live_diffs_fast_path: registry.register(metric!(
1224 name: "mz_persist_state_fetch_recent_live_diffs_fast_path",
1225 help: "count of fetch_recent_live_diffs that hit the fast path",
1226 )),
1227 fetch_recent_live_diffs_slow_path: registry.register(metric!(
1228 name: "mz_persist_state_fetch_recent_live_diffs_slow_path",
1229 help: "count of fetch_recent_live_diffs that hit the slow path",
1230 )),
1231 writer_added: registry.register(metric!(
1232 name: "mz_persist_state_writer_added",
1233 help: "count of writers added to the state",
1234 )),
1235 writer_removed: registry.register(metric!(
1236 name: "mz_persist_state_writer_removed",
1237 help: "count of writers removed from the state",
1238 )),
1239 force_apply_hostname: registry.register(metric!(
1240 name: "mz_persist_state_force_applied_hostname",
1241 help: "count of when hostname diffs needed to be force applied",
1242 )),
1243 rollup_write_success: registry.register(metric!(
1244 name: "mz_persist_state_rollup_write_success",
1245 help: "count of rollups written successful (may not be linked in to state)",
1246 )),
1247 rollup_write_noop_latest: rollup_write_noop.with_label_values(&["latest"]),
1248 rollup_write_noop_truncated: rollup_write_noop.with_label_values(&["truncated"]),
1249 }
1250 }
1251}
1252
1253#[derive(Debug)]
1254pub struct ShardsMetrics {
1255 _count: ComputedIntGauge,
1259 since: mz_ore::metrics::IntGaugeVec,
1260 upper: mz_ore::metrics::IntGaugeVec,
1261 encoded_rollup_size: mz_ore::metrics::UIntGaugeVec,
1262 encoded_diff_size: mz_ore::metrics::IntCounterVec,
1263 hollow_batch_count: mz_ore::metrics::UIntGaugeVec,
1264 spine_batch_count: mz_ore::metrics::UIntGaugeVec,
1265 batch_part_count: mz_ore::metrics::UIntGaugeVec,
1266 batch_part_version_count: mz_ore::metrics::UIntGaugeVec,
1267 batch_part_version_bytes: mz_ore::metrics::UIntGaugeVec,
1268 update_count: mz_ore::metrics::UIntGaugeVec,
1269 rollup_count: mz_ore::metrics::UIntGaugeVec,
1270 largest_batch_size: mz_ore::metrics::UIntGaugeVec,
1271 seqnos_held: mz_ore::metrics::UIntGaugeVec,
1272 seqnos_since_last_rollup: mz_ore::metrics::UIntGaugeVec,
1273 gc_seqno_held_parts: mz_ore::metrics::UIntGaugeVec,
1274 gc_live_diffs: mz_ore::metrics::UIntGaugeVec,
1275 gc_finished: mz_ore::metrics::IntCounterVec,
1276 compaction_applied: mz_ore::metrics::IntCounterVec,
1277 cmd_succeeded: mz_ore::metrics::IntCounterVec,
1278 usage_current_state_batches_bytes: mz_ore::metrics::UIntGaugeVec,
1279 usage_current_state_rollups_bytes: mz_ore::metrics::UIntGaugeVec,
1280 usage_referenced_not_current_state_bytes: mz_ore::metrics::UIntGaugeVec,
1281 usage_not_leaked_not_referenced_bytes: mz_ore::metrics::UIntGaugeVec,
1282 usage_leaked_bytes: mz_ore::metrics::UIntGaugeVec,
1283 pubsub_push_diff_applied: mz_ore::metrics::IntCounterVec,
1284 pubsub_push_diff_not_applied_stale: mz_ore::metrics::IntCounterVec,
1285 pubsub_push_diff_not_applied_out_of_order: mz_ore::metrics::IntCounterVec,
1286 stale_version: mz_ore::metrics::UIntGaugeVec,
1287 blob_gets: mz_ore::metrics::IntCounterVec,
1288 blob_sets: mz_ore::metrics::IntCounterVec,
1289 live_writers: mz_ore::metrics::UIntGaugeVec,
1290 unconsolidated_snapshot: mz_ore::metrics::IntCounterVec,
1291 backpressure_emitted_bytes: IntCounterVec,
1292 backpressure_last_backpressured_bytes: UIntGaugeVec,
1293 backpressure_retired_bytes: IntCounterVec,
1294 rewrite_part_count: UIntGaugeVec,
1295 inline_part_count: UIntGaugeVec,
1296 inline_part_bytes: UIntGaugeVec,
1297 compact_batches: UIntGaugeVec,
1298 compacting_batches: UIntGaugeVec,
1299 noncompact_batches: UIntGaugeVec,
1300 schema_registry_version_count: UIntGaugeVec,
1301 inline_backpressure_count: IntCounterVec,
1302 shards: Arc<Mutex<BTreeMap<ShardId, Weak<ShardMetrics>>>>,
1306}
1307
1308impl ShardsMetrics {
1309 fn new(registry: &MetricsRegistry) -> Self {
1310 let shards = Arc::new(Mutex::new(BTreeMap::new()));
1311 let shards_count = Arc::clone(&shards);
1312 ShardsMetrics {
1313 _count: registry.register_computed_gauge(
1314 metric!(
1315 name: "mz_persist_shard_count",
1316 help: "count of all active shards on this process",
1317 ),
1318 move || {
1319 let mut ret = 0;
1320 Self::compute(&shards_count, |_m| ret += 1);
1321 ret
1322 },
1323 ),
1324 since: registry.register(metric!(
1325 name: "mz_persist_shard_since",
1326 help: "since by shard",
1327 var_labels: ["shard", "name"],
1328 )),
1329 upper: registry.register(metric!(
1330 name: "mz_persist_shard_upper",
1331 help: "upper by shard",
1332 var_labels: ["shard", "name"],
1333 )),
1334 encoded_rollup_size: registry.register(metric!(
1335 name: "mz_persist_shard_rollup_size_bytes",
1336 help: "total encoded rollup size by shard",
1337 var_labels: ["shard", "name"],
1338 )),
1339 encoded_diff_size: registry.register(metric!(
1340 name: "mz_persist_shard_diff_size_bytes",
1341 help: "total encoded diff size by shard",
1342 var_labels: ["shard", "name"],
1343 )),
1344 hollow_batch_count: registry.register(metric!(
1345 name: "mz_persist_shard_hollow_batch_count",
1346 help: "count of hollow batches by shard",
1347 var_labels: ["shard", "name"],
1348 )),
1349 spine_batch_count: registry.register(metric!(
1350 name: "mz_persist_shard_spine_batch_count",
1351 help: "count of spine batches by shard",
1352 var_labels: ["shard", "name"],
1353 )),
1354 batch_part_count: registry.register(metric!(
1355 name: "mz_persist_shard_batch_part_count",
1356 help: "count of batch parts by shard",
1357 var_labels: ["shard", "name"],
1358 )),
1359 batch_part_version_count: registry.register(metric!(
1360 name: "mz_persist_shard_batch_part_version_count",
1361 help: "count of batch parts by shard and version",
1362 var_labels: ["shard", "name", "version"],
1363 )),
1364 batch_part_version_bytes: registry.register(metric!(
1365 name: "mz_persist_shard_batch_part_version_bytes",
1366 help: "total bytes in batch parts by shard and version",
1367 var_labels: ["shard", "name", "version"],
1368 )),
1369 update_count: registry.register(metric!(
1370 name: "mz_persist_shard_update_count",
1371 help: "count of updates by shard",
1372 var_labels: ["shard", "name"],
1373 )),
1374 rollup_count: registry.register(metric!(
1375 name: "mz_persist_shard_rollup_count",
1376 help: "count of rollups by shard",
1377 var_labels: ["shard", "name"],
1378 )),
1379 largest_batch_size: registry.register(metric!(
1380 name: "mz_persist_shard_largest_batch_size",
1381 help: "largest encoded batch size by shard",
1382 var_labels: ["shard", "name"],
1383 )),
1384 seqnos_held: registry.register(metric!(
1385 name: "mz_persist_shard_seqnos_held",
1386 help: "maximum count of gc-ineligible states by shard",
1387 var_labels: ["shard", "name"],
1388 )),
1389 seqnos_since_last_rollup: registry.register(metric!(
1390 name: "mz_persist_shard_seqnos_since_last_rollup",
1391 help: "count of seqnos since last rollup",
1392 var_labels: ["shard", "name"],
1393 )),
1394 gc_seqno_held_parts: registry.register(metric!(
1395 name: "mz_persist_shard_gc_seqno_held_parts",
1396 help: "count of parts referenced by some live state but not the current state (ie. parts kept only to satisfy seqno holds) at GC time",
1397 var_labels: ["shard", "name"],
1398 )),
1399 gc_live_diffs: registry.register(metric!(
1400 name: "mz_persist_shard_gc_live_diffs",
1401 help: "the number of diffs (or, alternatively, the number of seqnos) present in consensus state at GC time",
1402 var_labels: ["shard", "name"],
1403 )),
1404 gc_finished: registry.register(metric!(
1405 name: "mz_persist_shard_gc_finished",
1406 help: "count of garbage collections finished by shard",
1407 var_labels: ["shard", "name"],
1408 )),
1409 compaction_applied: registry.register(metric!(
1410 name: "mz_persist_shard_compaction_applied",
1411 help: "count of compactions applied to state by shard",
1412 var_labels: ["shard", "name"],
1413 )),
1414 cmd_succeeded: registry.register(metric!(
1415 name: "mz_persist_shard_cmd_succeeded",
1416 help: "count of commands succeeded by shard",
1417 var_labels: ["shard", "name"],
1418 )),
1419 usage_current_state_batches_bytes: registry.register(metric!(
1420 name: "mz_persist_shard_usage_current_state_batches_bytes",
1421 help: "data in batches/parts referenced by current version of state",
1422 var_labels: ["shard", "name"],
1423 )),
1424 usage_current_state_rollups_bytes: registry.register(metric!(
1425 name: "mz_persist_shard_usage_current_state_rollups_bytes",
1426 help: "data in rollups referenced by current version of state",
1427 var_labels: ["shard", "name"],
1428 )),
1429 usage_referenced_not_current_state_bytes: registry.register(metric!(
1430 name: "mz_persist_shard_usage_referenced_not_current_state_bytes",
1431 help: "data referenced only by a previous version of state",
1432 var_labels: ["shard", "name"],
1433 )),
1434 usage_not_leaked_not_referenced_bytes: registry.register(metric!(
1435 name: "mz_persist_shard_usage_not_leaked_not_referenced_bytes",
1436 help: "data written by an active writer but not referenced by any version of state",
1437 var_labels: ["shard", "name"],
1438 )),
1439 usage_leaked_bytes: registry.register(metric!(
1440 name: "mz_persist_shard_usage_leaked_bytes",
1441 help: "data reclaimable by a leaked blob detector",
1442 var_labels: ["shard", "name"],
1443 )),
1444 pubsub_push_diff_applied: registry.register(metric!(
1445 name: "mz_persist_shard_pubsub_diff_applied",
1446 help: "number of diffs received via pubsub that applied",
1447 var_labels: ["shard", "name"],
1448 )),
1449 pubsub_push_diff_not_applied_stale: registry.register(metric!(
1450 name: "mz_persist_shard_pubsub_diff_not_applied_stale",
1451 help: "number of diffs received via pubsub that did not apply due to staleness",
1452 var_labels: ["shard", "name"],
1453 )),
1454 pubsub_push_diff_not_applied_out_of_order: registry.register(metric!(
1455 name: "mz_persist_shard_pubsub_diff_not_applied_out_of_order",
1456 help: "number of diffs received via pubsub that did not apply due to out-of-order delivery",
1457 var_labels: ["shard", "name"],
1458 )),
1459 stale_version: registry.register(metric!(
1460 name: "mz_persist_shard_stale_version",
1461 help: "indicates whether the current version of the shard is less than the current version of the code",
1462 var_labels: ["shard", "name"],
1463 )),
1464 blob_gets: registry.register(metric!(
1465 name: "mz_persist_shard_blob_gets",
1466 help: "number of Blob::get calls for this shard",
1467 var_labels: ["shard", "name"],
1468 )),
1469 blob_sets: registry.register(metric!(
1470 name: "mz_persist_shard_blob_sets",
1471 help: "number of Blob::set calls for this shard",
1472 var_labels: ["shard", "name"],
1473 )),
1474 live_writers: registry.register(metric!(
1475 name: "mz_persist_shard_live_writers",
1476 help: "number of writers that have recently appended updates to this shard",
1477 var_labels: ["shard", "name"],
1478 )),
1479 unconsolidated_snapshot: registry.register(metric!(
1480 name: "mz_persist_shard_unconsolidated_snapshot",
1481 help: "in snapshot_and_read, the number of times consolidating the raw data wasn't enough to produce consolidated output",
1482 var_labels: ["shard", "name"],
1483 )),
1484 backpressure_emitted_bytes: registry.register(metric!(
1485 name: "mz_persist_backpressure_emitted_bytes",
1486 help: "A counter with the number of emitted bytes.",
1487 var_labels: ["shard", "name"],
1488 )),
1489 backpressure_last_backpressured_bytes: registry.register(metric!(
1490 name: "mz_persist_backpressure_last_backpressured_bytes",
1491 help: "The last count of bytes we are waiting to be retired in \
1492 the operator. This cannot be directly compared to \
1493 `retired_bytes`, but CAN indicate that backpressure is happening.",
1494 var_labels: ["shard", "name"],
1495 )),
1496 backpressure_retired_bytes: registry.register(metric!(
1497 name: "mz_persist_backpressure_retired_bytes",
1498 help:"A counter with the number of bytes retired by downstream processing.",
1499 var_labels: ["shard", "name"],
1500 )),
1501 rewrite_part_count: registry.register(metric!(
1502 name: "mz_persist_shard_rewrite_part_count",
1503 help: "count of batch parts with rewrites by shard",
1504 var_labels: ["shard", "name"],
1505 )),
1506 inline_part_count: registry.register(metric!(
1507 name: "mz_persist_shard_inline_part_count",
1508 help: "count of parts inline in shard metadata",
1509 var_labels: ["shard", "name"],
1510 )),
1511 inline_part_bytes: registry.register(metric!(
1512 name: "mz_persist_shard_inline_part_bytes",
1513 help: "total size of parts inline in shard metadata",
1514 var_labels: ["shard", "name"],
1515 )),
1516 compact_batches: registry.register(metric!(
1517 name: "mz_persist_shard_compact_batches",
1518 help: "number of fully compact batches in the shard",
1519 var_labels: ["shard", "name"],
1520 )),
1521 compacting_batches: registry.register(metric!(
1522 name: "mz_persist_shard_compacting_batches",
1523 help: "number of batches in the shard with compactions in progress",
1524 var_labels: ["shard", "name"],
1525 )),
1526 noncompact_batches: registry.register(metric!(
1527 name: "mz_persist_shard_noncompact_batches",
1528 help: "number of batches in the shard that aren't compact and have no ongoing compaction",
1529 var_labels: ["shard", "name"],
1530 )),
1531 schema_registry_version_count: registry.register(metric!(
1532 name: "mz_persist_shard_schema_registry_version_count",
1533 help: "count of versions in the schema registry",
1534 var_labels: ["shard", "name"],
1535 )),
1536 inline_backpressure_count: registry.register(metric!(
1537 name: "mz_persist_shard_inline_backpressure_count",
1538 help: "count of CaA attempts retried because of inline backpressure",
1539 var_labels: ["shard", "name"],
1540 )),
1541 shards,
1542 }
1543 }
1544
1545 pub fn shard(&self, shard_id: &ShardId, name: &str) -> Arc<ShardMetrics> {
1546 let mut shards = self.shards.lock().expect("mutex poisoned");
1547 if let Some(shard) = shards.get(shard_id) {
1548 if let Some(shard) = shard.upgrade() {
1549 return Arc::clone(&shard);
1550 } else {
1551 assert!(shards.remove(shard_id).is_some());
1552 }
1553 }
1554 let shard = Arc::new(ShardMetrics::new(shard_id, name, self));
1555 assert!(
1556 shards
1557 .insert(shard_id.clone(), Arc::downgrade(&shard))
1558 .is_none()
1559 );
1560 shard
1561 }
1562
1563 fn compute<F: FnMut(&ShardMetrics)>(
1564 shards: &Arc<Mutex<BTreeMap<ShardId, Weak<ShardMetrics>>>>,
1565 mut f: F,
1566 ) {
1567 let mut shards = shards.lock().expect("mutex poisoned");
1568 let mut deleted_shards = Vec::new();
1569 for (shard_id, metrics) in shards.iter() {
1570 if let Some(metrics) = metrics.upgrade() {
1571 f(&metrics);
1572 } else {
1573 deleted_shards.push(shard_id.clone());
1574 }
1575 }
1576 for deleted_shard_id in deleted_shards {
1577 assert!(shards.remove(&deleted_shard_id).is_some());
1578 }
1579 }
1580}
1581
1582#[derive(Debug)]
1583pub struct ShardMetrics {
1584 pub shard_id: ShardId,
1585 pub name: String,
1586 pub since: DeleteOnDropGauge<AtomicI64, Vec<String>>,
1587 pub upper: DeleteOnDropGauge<AtomicI64, Vec<String>>,
1588 pub largest_batch_size: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1589 pub latest_rollup_size: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1590 pub encoded_diff_size: DeleteOnDropCounter<AtomicU64, Vec<String>>,
1591 pub hollow_batch_count: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1592 pub spine_batch_count: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1593 pub batch_part_count: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1594 batch_part_version_count: mz_ore::metrics::UIntGaugeVec,
1595 batch_part_version_bytes: mz_ore::metrics::UIntGaugeVec,
1596 batch_part_version_map: Mutex<BTreeMap<String, BatchPartVersionMetrics>>,
1597 pub update_count: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1598 pub rollup_count: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1599 pub seqnos_held: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1600 pub seqnos_since_last_rollup: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1601 pub gc_seqno_held_parts: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1602 pub gc_live_diffs: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1603 pub usage_current_state_batches_bytes: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1604 pub usage_current_state_rollups_bytes: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1605 pub usage_referenced_not_current_state_bytes: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1606 pub usage_not_leaked_not_referenced_bytes: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1607 pub usage_leaked_bytes: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1608 pub gc_finished: DeleteOnDropCounter<AtomicU64, Vec<String>>,
1609 pub compaction_applied: DeleteOnDropCounter<AtomicU64, Vec<String>>,
1610 pub cmd_succeeded: DeleteOnDropCounter<AtomicU64, Vec<String>>,
1611 pub pubsub_push_diff_applied: DeleteOnDropCounter<AtomicU64, Vec<String>>,
1612 pub pubsub_push_diff_not_applied_stale: DeleteOnDropCounter<AtomicU64, Vec<String>>,
1613 pub pubsub_push_diff_not_applied_out_of_order: DeleteOnDropCounter<AtomicU64, Vec<String>>,
1614 pub stale_version: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1615 pub blob_gets: DeleteOnDropCounter<AtomicU64, Vec<String>>,
1616 pub blob_sets: DeleteOnDropCounter<AtomicU64, Vec<String>>,
1617 pub live_writers: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1618 pub unconsolidated_snapshot: DeleteOnDropCounter<AtomicU64, Vec<String>>,
1619 pub backpressure_emitted_bytes: Arc<DeleteOnDropCounter<AtomicU64, Vec<String>>>,
1620 pub backpressure_last_backpressured_bytes: Arc<DeleteOnDropGauge<AtomicU64, Vec<String>>>,
1621 pub backpressure_retired_bytes: Arc<DeleteOnDropCounter<AtomicU64, Vec<String>>>,
1622 pub rewrite_part_count: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1623 pub inline_part_count: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1624 pub inline_part_bytes: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1625 pub compact_batches: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1626 pub compacting_batches: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1627 pub noncompact_batches: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1628 pub schema_registry_version_count: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1629 pub inline_backpressure_count: DeleteOnDropCounter<AtomicU64, Vec<String>>,
1630}
1631
1632impl ShardMetrics {
1633 pub fn new(shard_id: &ShardId, name: &str, shards_metrics: &ShardsMetrics) -> Self {
1634 let shard = shard_id.to_string();
1635 ShardMetrics {
1636 shard_id: *shard_id,
1637 name: name.to_string(),
1638 since: shards_metrics
1639 .since
1640 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1641 upper: shards_metrics
1642 .upper
1643 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1644 latest_rollup_size: shards_metrics
1645 .encoded_rollup_size
1646 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1647 encoded_diff_size: shards_metrics
1648 .encoded_diff_size
1649 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1650 hollow_batch_count: shards_metrics
1651 .hollow_batch_count
1652 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1653 spine_batch_count: shards_metrics
1654 .spine_batch_count
1655 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1656 batch_part_count: shards_metrics
1657 .batch_part_count
1658 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1659 batch_part_version_count: shards_metrics.batch_part_version_count.clone(),
1660 batch_part_version_bytes: shards_metrics.batch_part_version_bytes.clone(),
1661 batch_part_version_map: Mutex::new(BTreeMap::new()),
1662 update_count: shards_metrics
1663 .update_count
1664 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1665 rollup_count: shards_metrics
1666 .rollup_count
1667 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1668 largest_batch_size: shards_metrics
1669 .largest_batch_size
1670 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1671 seqnos_held: shards_metrics
1672 .seqnos_held
1673 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1674 seqnos_since_last_rollup: shards_metrics
1675 .seqnos_since_last_rollup
1676 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1677 gc_seqno_held_parts: shards_metrics
1678 .gc_seqno_held_parts
1679 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1680 gc_live_diffs: shards_metrics
1681 .gc_live_diffs
1682 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1683 gc_finished: shards_metrics
1684 .gc_finished
1685 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1686 compaction_applied: shards_metrics
1687 .compaction_applied
1688 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1689 cmd_succeeded: shards_metrics
1690 .cmd_succeeded
1691 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1692 usage_current_state_batches_bytes: shards_metrics
1693 .usage_current_state_batches_bytes
1694 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1695 usage_current_state_rollups_bytes: shards_metrics
1696 .usage_current_state_rollups_bytes
1697 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1698 usage_referenced_not_current_state_bytes: shards_metrics
1699 .usage_referenced_not_current_state_bytes
1700 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1701 usage_not_leaked_not_referenced_bytes: shards_metrics
1702 .usage_not_leaked_not_referenced_bytes
1703 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1704 usage_leaked_bytes: shards_metrics
1705 .usage_leaked_bytes
1706 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1707 pubsub_push_diff_applied: shards_metrics
1708 .pubsub_push_diff_applied
1709 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1710 pubsub_push_diff_not_applied_stale: shards_metrics
1711 .pubsub_push_diff_not_applied_stale
1712 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1713 pubsub_push_diff_not_applied_out_of_order: shards_metrics
1714 .pubsub_push_diff_not_applied_out_of_order
1715 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1716 stale_version: shards_metrics
1717 .stale_version
1718 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1719 blob_gets: shards_metrics
1720 .blob_gets
1721 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1722 blob_sets: shards_metrics
1723 .blob_sets
1724 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1725 live_writers: shards_metrics
1726 .live_writers
1727 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1728 unconsolidated_snapshot: shards_metrics
1729 .unconsolidated_snapshot
1730 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1731 backpressure_emitted_bytes: Arc::new(
1732 shards_metrics
1733 .backpressure_emitted_bytes
1734 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1735 ),
1736 backpressure_last_backpressured_bytes: Arc::new(
1737 shards_metrics
1738 .backpressure_last_backpressured_bytes
1739 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1740 ),
1741 backpressure_retired_bytes: Arc::new(
1742 shards_metrics
1743 .backpressure_retired_bytes
1744 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1745 ),
1746 rewrite_part_count: shards_metrics
1747 .rewrite_part_count
1748 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1749 inline_part_count: shards_metrics
1750 .inline_part_count
1751 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1752 inline_part_bytes: shards_metrics
1753 .inline_part_bytes
1754 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1755 compact_batches: shards_metrics
1756 .compact_batches
1757 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1758 compacting_batches: shards_metrics
1759 .compacting_batches
1760 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1761 noncompact_batches: shards_metrics
1762 .noncompact_batches
1763 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1764 schema_registry_version_count: shards_metrics
1765 .schema_registry_version_count
1766 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1767 inline_backpressure_count: shards_metrics
1768 .inline_backpressure_count
1769 .get_delete_on_drop_metric(vec![shard, name.to_string()]),
1770 }
1771 }
1772
1773 pub fn set_since<T: Codec64>(&self, since: &Antichain<T>) {
1774 self.since.set(encode_ts_metric(since))
1775 }
1776
1777 pub fn set_upper<T: Codec64>(&self, upper: &Antichain<T>) {
1778 self.upper.set(encode_ts_metric(upper))
1779 }
1780
1781 pub(crate) fn set_batch_part_versions<'a>(
1782 &self,
1783 batch_parts_by_version: impl Iterator<Item = (&'a str, usize)>,
1784 ) {
1785 let mut map = self
1786 .batch_part_version_map
1787 .lock()
1788 .expect("mutex should not be poisoned");
1789 for x in map.values() {
1796 x.batch_part_version_count.set(0);
1797 x.batch_part_version_bytes.set(0);
1798 }
1799
1800 for (key, bytes) in batch_parts_by_version {
1803 if !map.contains_key(key) {
1804 map.insert(
1805 key.to_owned(),
1806 BatchPartVersionMetrics {
1807 batch_part_version_count: self
1808 .batch_part_version_count
1809 .get_delete_on_drop_metric(vec![
1810 self.shard_id.to_string(),
1811 self.name.clone(),
1812 key.to_owned(),
1813 ]),
1814 batch_part_version_bytes: self
1815 .batch_part_version_bytes
1816 .get_delete_on_drop_metric(vec![
1817 self.shard_id.to_string(),
1818 self.name.clone(),
1819 key.to_owned(),
1820 ]),
1821 },
1822 );
1823 }
1824 let value = map.get(key).expect("inserted above");
1825 value.batch_part_version_count.inc();
1826 value.batch_part_version_bytes.add(u64::cast_from(bytes));
1827 }
1828 }
1829}
1830
1831#[derive(Debug)]
1832pub struct BatchPartVersionMetrics {
1833 pub batch_part_version_count: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1834 pub batch_part_version_bytes: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1835}
1836
1837#[derive(Debug)]
1839pub struct UsageAuditMetrics {
1840 pub blob_batch_part_bytes: UIntGauge,
1842 pub blob_batch_part_count: UIntGauge,
1844 pub blob_rollup_bytes: UIntGauge,
1846 pub blob_rollup_count: UIntGauge,
1848 pub blob_bytes: UIntGauge,
1850 pub blob_count: UIntGauge,
1852 pub step_blob_metadata: Counter,
1854 pub step_state: Counter,
1856 pub step_math: Counter,
1858}
1859
1860impl UsageAuditMetrics {
1861 fn new(registry: &MetricsRegistry) -> Self {
1862 let step_timings: CounterVec = registry.register(metric!(
1863 name: "mz_persist_audit_step_seconds",
1864 help: "time spent on individual steps of audit",
1865 var_labels: ["step"],
1866 ));
1867 UsageAuditMetrics {
1868 blob_batch_part_bytes: registry.register(metric!(
1869 name: "mz_persist_audit_blob_batch_part_bytes",
1870 help: "total size of batch parts in blob",
1871 )),
1872 blob_batch_part_count: registry.register(metric!(
1873 name: "mz_persist_audit_blob_batch_part_count",
1874 help: "count of batch parts in blob",
1875 )),
1876 blob_rollup_bytes: registry.register(metric!(
1877 name: "mz_persist_audit_blob_rollup_bytes",
1878 help: "total size of state rollups stored in blob",
1879 )),
1880 blob_rollup_count: registry.register(metric!(
1881 name: "mz_persist_audit_blob_rollup_count",
1882 help: "count of all state rollups in blob",
1883 )),
1884 blob_bytes: registry.register(metric!(
1885 name: "mz_persist_audit_blob_bytes",
1886 help: "total size of blob",
1887 )),
1888 blob_count: registry.register(metric!(
1889 name: "mz_persist_audit_blob_count",
1890 help: "count of all blobs",
1891 )),
1892 step_blob_metadata: step_timings.with_label_values(&["blob_metadata"]),
1893 step_state: step_timings.with_label_values(&["state"]),
1894 step_math: step_timings.with_label_values(&["math"]),
1895 }
1896 }
1897}
1898
1899#[derive(Debug)]
1902pub enum UpdateDelta {
1903 Negative(u64),
1905 NonNegative(u64),
1907}
1908
1909impl UpdateDelta {
1910 pub fn new(new: usize, old: usize) -> Self {
1913 if new < old {
1914 UpdateDelta::Negative(CastFrom::cast_from(old - new))
1915 } else {
1916 UpdateDelta::NonNegative(CastFrom::cast_from(new - old))
1917 }
1918 }
1919}
1920
1921#[derive(Debug, Clone)]
1924pub struct SinkMetrics {
1925 correction_insertions_total: IntCounter,
1927 correction_deletions_total: IntCounter,
1929 correction_capacity_increases_total: IntCounter,
1931 correction_capacity_decreases_total: IntCounter,
1933 correction_max_per_sink_worker_len_updates: raw::UIntGaugeVec,
1935 correction_max_per_sink_worker_capacity_updates: raw::UIntGaugeVec,
1937}
1938
1939impl SinkMetrics {
1940 fn new(registry: &MetricsRegistry) -> Self {
1941 SinkMetrics {
1942 correction_insertions_total: registry.register(metric!(
1943 name: "mz_persist_sink_correction_insertions_total",
1944 help: "The cumulative insertions observed on the correction buffer across workers and persist sinks.",
1945 )),
1946 correction_deletions_total: registry.register(metric!(
1947 name: "mz_persist_sink_correction_deletions_total",
1948 help: "The cumulative deletions observed on the correction buffer across workers and persist sinks.",
1949 )),
1950 correction_capacity_increases_total: registry.register(metric!(
1951 name: "mz_persist_sink_correction_capacity_increases_total",
1952 help: "The cumulative capacity increases observed on the correction buffer across workers and persist sinks.",
1953 )),
1954 correction_capacity_decreases_total: registry.register(metric!(
1955 name: "mz_persist_sink_correction_capacity_decreases_total",
1956 help: "The cumulative capacity decreases observed on the correction buffer across workers and persist sinks.",
1957 )),
1958 correction_max_per_sink_worker_len_updates: registry.register(metric!(
1959 name: "mz_persist_sink_correction_max_per_sink_worker_len_updates",
1960 help: "The maximum length observed for the correction buffer of any single persist sink per worker.",
1961 var_labels: ["worker_id"],
1962 )),
1963 correction_max_per_sink_worker_capacity_updates: registry.register(metric!(
1964 name: "mz_persist_sink_correction_max_per_sink_worker_capacity_updates",
1965 help: "The maximum capacity observed for the correction buffer of any single persist sink per worker.",
1966 var_labels: ["worker_id"],
1967 )),
1968 }
1969 }
1970
1971 pub fn for_worker(&self, worker_id: usize) -> SinkWorkerMetrics {
1976 let worker = worker_id.to_string();
1977 let correction_max_per_sink_worker_len_updates = self
1978 .correction_max_per_sink_worker_len_updates
1979 .with_label_values(&[&worker]);
1980 let correction_max_per_sink_worker_capacity_updates = self
1981 .correction_max_per_sink_worker_capacity_updates
1982 .with_label_values(&[&worker]);
1983 SinkWorkerMetrics {
1984 correction_max_per_sink_worker_len_updates,
1985 correction_max_per_sink_worker_capacity_updates,
1986 }
1987 }
1988
1989 pub fn report_correction_update_deltas(
1995 &self,
1996 correction_len_delta: UpdateDelta,
1997 correction_cap_delta: UpdateDelta,
1998 ) {
1999 match correction_len_delta {
2001 UpdateDelta::NonNegative(delta) => {
2002 if delta > 0 {
2003 self.correction_insertions_total.inc_by(delta)
2004 }
2005 }
2006 UpdateDelta::Negative(delta) => self.correction_deletions_total.inc_by(delta),
2007 }
2008 match correction_cap_delta {
2010 UpdateDelta::NonNegative(delta) => {
2011 if delta > 0 {
2012 self.correction_capacity_increases_total.inc_by(delta)
2013 }
2014 }
2015 UpdateDelta::Negative(delta) => self.correction_capacity_decreases_total.inc_by(delta),
2016 }
2017 }
2018}
2019
2020#[derive(Clone, Debug)]
2022pub struct SinkWorkerMetrics {
2023 correction_max_per_sink_worker_len_updates: UIntGauge,
2024 correction_max_per_sink_worker_capacity_updates: UIntGauge,
2025}
2026
2027impl SinkWorkerMetrics {
2028 pub fn report_correction_update_totals(&self, correction_len: usize, correction_cap: usize) {
2033 let correction_len = CastFrom::cast_from(correction_len);
2035 if correction_len > self.correction_max_per_sink_worker_len_updates.get() {
2036 self.correction_max_per_sink_worker_len_updates
2037 .set(correction_len);
2038 }
2039 let correction_cap = CastFrom::cast_from(correction_cap);
2040 if correction_cap > self.correction_max_per_sink_worker_capacity_updates.get() {
2041 self.correction_max_per_sink_worker_capacity_updates
2042 .set(correction_cap);
2043 }
2044 }
2045}
2046
2047#[derive(Debug)]
2049pub struct AlertsMetrics {
2050 pub(crate) blob_failures: IntCounter,
2051 pub(crate) consensus_failures: IntCounter,
2052}
2053
2054impl AlertsMetrics {
2055 fn new(registry: &MetricsRegistry) -> Self {
2056 AlertsMetrics {
2057 blob_failures: registry.register(metric!(
2058 name: "mz_persist_blob_failures",
2059 help: "count of all blob operation failures",
2060 const_labels: {"honeycomb" => "import"},
2061 )),
2062 consensus_failures: registry.register(metric!(
2063 name: "mz_persist_consensus_failures",
2064 help: "count of determinate consensus operation failures",
2065 const_labels: {"honeycomb" => "import"},
2066 )),
2067 }
2068 }
2069}
2070
2071#[derive(Debug)]
2073pub struct PubSubServerMetrics {
2074 pub(crate) active_connections: UIntGauge,
2075 pub(crate) broadcasted_diff_count: IntCounter,
2076 pub(crate) broadcasted_diff_bytes: IntCounter,
2077 pub(crate) broadcasted_diff_dropped_channel_full: IntCounter,
2078
2079 pub(crate) push_seconds: Counter,
2080 pub(crate) subscribe_seconds: Counter,
2081 pub(crate) unsubscribe_seconds: Counter,
2082 pub(crate) connection_cleanup_seconds: Counter,
2083
2084 pub(crate) push_call_count: IntCounter,
2085 pub(crate) subscribe_call_count: IntCounter,
2086 pub(crate) unsubscribe_call_count: IntCounter,
2087}
2088
2089impl PubSubServerMetrics {
2090 pub(crate) fn new(registry: &MetricsRegistry) -> Self {
2091 let op_timings: CounterVec = registry.register(metric!(
2092 name: "mz_persist_pubsub_server_operation_seconds",
2093 help: "time spent in pubsub server performing each operation",
2094 var_labels: ["op"],
2095 ));
2096 let call_count: IntCounterVec = registry.register(metric!(
2097 name: "mz_persist_pubsub_server_call_count",
2098 help: "count of each pubsub server message received",
2099 var_labels: ["call"],
2100 ));
2101
2102 Self {
2103 active_connections: registry.register(metric!(
2104 name: "mz_persist_pubsub_server_active_connections",
2105 help: "number of active connections to server",
2106 )),
2107 broadcasted_diff_count: registry.register(metric!(
2108 name: "mz_persist_pubsub_server_broadcasted_diff_count",
2109 help: "count of total broadcast diff messages sent",
2110 )),
2111 broadcasted_diff_bytes: registry.register(metric!(
2112 name: "mz_persist_pubsub_server_broadcasted_diff_bytes",
2113 help: "count of total broadcast diff bytes sent",
2114 )),
2115 broadcasted_diff_dropped_channel_full: registry.register(metric!(
2116 name: "mz_persist_pubsub_server_broadcasted_diff_dropped_channel_full",
2117 help: "count of diffs dropped due to full connection channel",
2118 )),
2119
2120 push_seconds: op_timings.with_label_values(&["push"]),
2121 subscribe_seconds: op_timings.with_label_values(&["subscribe"]),
2122 unsubscribe_seconds: op_timings.with_label_values(&["unsubscribe"]),
2123 connection_cleanup_seconds: op_timings.with_label_values(&["cleanup"]),
2124
2125 push_call_count: call_count.with_label_values(&["push"]),
2126 subscribe_call_count: call_count.with_label_values(&["subscribe"]),
2127 unsubscribe_call_count: call_count.with_label_values(&["unsubscribe"]),
2128 }
2129 }
2130}
2131
2132#[derive(Debug)]
2134pub struct PubSubClientMetrics {
2135 pub sender: PubSubClientSenderMetrics,
2136 pub receiver: PubSubClientReceiverMetrics,
2137 pub grpc_connection: PubSubGrpcClientConnectionMetrics,
2138}
2139
2140impl PubSubClientMetrics {
2141 fn new(registry: &MetricsRegistry) -> Self {
2142 PubSubClientMetrics {
2143 sender: PubSubClientSenderMetrics::new(registry),
2144 receiver: PubSubClientReceiverMetrics::new(registry),
2145 grpc_connection: PubSubGrpcClientConnectionMetrics::new(registry),
2146 }
2147 }
2148}
2149
2150#[derive(Debug)]
2151pub struct PubSubGrpcClientConnectionMetrics {
2152 pub(crate) connected: UIntGauge,
2153 pub(crate) connection_established_count: IntCounter,
2154 pub(crate) connect_call_attempt_count: IntCounter,
2155 pub(crate) broadcast_recv_lagged_count: IntCounter,
2156 pub(crate) grpc_error_count: IntCounter,
2157}
2158
2159impl PubSubGrpcClientConnectionMetrics {
2160 fn new(registry: &MetricsRegistry) -> Self {
2161 Self {
2162 connected: registry.register(metric!(
2163 name: "mz_persist_pubsub_client_grpc_connected",
2164 help: "whether the grpc client is currently connected",
2165 )),
2166 connection_established_count: registry.register(metric!(
2167 name: "mz_persist_pubsub_client_grpc_connection_established_count",
2168 help: "count of grpc connection establishments to pubsub server",
2169 )),
2170 connect_call_attempt_count: registry.register(metric!(
2171 name: "mz_persist_pubsub_client_grpc_connect_call_attempt_count",
2172 help: "count of connection call attempts (including retries) to pubsub server",
2173 )),
2174 broadcast_recv_lagged_count: registry.register(metric!(
2175 name: "mz_persist_pubsub_client_grpc_broadcast_recv_lagged_count",
2176 help: "times a message was missed by broadcast receiver due to lag",
2177 )),
2178 grpc_error_count: registry.register(metric!(
2179 name: "mz_persist_pubsub_client_grpc_error_count",
2180 help: "count of grpc errors received",
2181 )),
2182 }
2183 }
2184}
2185
2186#[derive(Clone, Debug)]
2187pub struct PubSubClientReceiverMetrics {
2188 pub(crate) push_received: IntCounter,
2189 pub(crate) unknown_message_received: IntCounter,
2190 pub(crate) approx_diff_latency_seconds: Histogram,
2191
2192 pub(crate) state_pushed_diff_fast_path: IntCounter,
2193 pub(crate) state_pushed_diff_slow_path_succeeded: IntCounter,
2194 pub(crate) state_pushed_diff_slow_path_failed: IntCounter,
2195}
2196
2197impl PubSubClientReceiverMetrics {
2198 fn new(registry: &MetricsRegistry) -> Self {
2199 let call_received: IntCounterVec = registry.register(metric!(
2200 name: "mz_persist_pubsub_client_call_received",
2201 help: "times a pubsub client call was received",
2202 var_labels: ["call"],
2203 ));
2204
2205 Self {
2206 push_received: call_received.with_label_values(&["push"]),
2207 unknown_message_received: call_received.with_label_values(&["unknown"]),
2208 approx_diff_latency_seconds: registry.register(metric!(
2209 name: "mz_persist_pubsub_client_approx_diff_apply_latency_seconds",
2210 help: "histogram of (approximate) latency between sending a diff and applying it",
2211 buckets: prometheus::exponential_buckets(0.001, 2.0, 13).expect("buckets"),
2212 )),
2213
2214 state_pushed_diff_fast_path: registry.register(metric!(
2215 name: "mz_persist_pubsub_client_receiver_state_push_diff_fast_path",
2216 help: "count fast-path state push_diff calls",
2217 )),
2218 state_pushed_diff_slow_path_succeeded: registry.register(metric!(
2219 name: "mz_persist_pubsub_client_receiver_state_push_diff_slow_path_succeeded",
2220 help: "count of successful slow-path state push_diff calls",
2221 )),
2222 state_pushed_diff_slow_path_failed: registry.register(metric!(
2223 name: "mz_persist_pubsub_client_receiver_state_push_diff_slow_path_failed",
2224 help: "count of unsuccessful slow-path state push_diff calls",
2225 )),
2226 }
2227 }
2228}
2229
2230#[derive(Debug)]
2231pub struct PubSubClientSenderMetrics {
2232 pub push: PubSubClientCallMetrics,
2233 pub subscribe: PubSubClientCallMetrics,
2234 pub unsubscribe: PubSubClientCallMetrics,
2235}
2236
2237#[derive(Debug)]
2238pub struct PubSubClientCallMetrics {
2239 pub(crate) succeeded: IntCounter,
2240 pub(crate) bytes_sent: IntCounter,
2241 pub(crate) failed: IntCounter,
2242}
2243
2244impl PubSubClientSenderMetrics {
2245 fn new(registry: &MetricsRegistry) -> Self {
2246 let call_bytes_sent: IntCounterVec = registry.register(metric!(
2247 name: "mz_persist_pubsub_client_call_bytes_sent",
2248 help: "number of bytes sent for a given pubsub client call",
2249 var_labels: ["call"],
2250 ));
2251 let call_succeeded: IntCounterVec = registry.register(metric!(
2252 name: "mz_persist_pubsub_client_call_succeeded",
2253 help: "times a pubsub client call succeeded",
2254 var_labels: ["call"],
2255 ));
2256 let call_failed: IntCounterVec = registry.register(metric!(
2257 name: "mz_persist_pubsub_client_call_failed",
2258 help: "times a pubsub client call failed",
2259 var_labels: ["call"],
2260 ));
2261
2262 Self {
2263 push: PubSubClientCallMetrics {
2264 succeeded: call_succeeded.with_label_values(&["push"]),
2265 failed: call_failed.with_label_values(&["push"]),
2266 bytes_sent: call_bytes_sent.with_label_values(&["push"]),
2267 },
2268 subscribe: PubSubClientCallMetrics {
2269 succeeded: call_succeeded.with_label_values(&["subscribe"]),
2270 failed: call_failed.with_label_values(&["subscribe"]),
2271 bytes_sent: call_bytes_sent.with_label_values(&["subscribe"]),
2272 },
2273 unsubscribe: PubSubClientCallMetrics {
2274 succeeded: call_succeeded.with_label_values(&["unsubscribe"]),
2275 failed: call_failed.with_label_values(&["unsubscribe"]),
2276 bytes_sent: call_bytes_sent.with_label_values(&["unsubscribe"]),
2277 },
2278 }
2279 }
2280}
2281
2282#[derive(Debug)]
2283pub struct LocksMetrics {
2284 pub(crate) applier_read_cacheable: LockMetrics,
2285 pub(crate) applier_read_noncacheable: LockMetrics,
2286 pub(crate) applier_write: LockMetrics,
2287 pub(crate) watch: LockMetrics,
2288}
2289
2290#[derive(Debug, Clone)]
2291pub struct LockMetrics {
2292 pub(crate) acquire_count: IntCounter,
2293 pub(crate) blocking_acquire_count: IntCounter,
2294 pub(crate) blocking_seconds: Counter,
2295}
2296
2297#[derive(Debug)]
2298pub struct WatchMetrics {
2299 pub(crate) wait_woken_via_watch: IntCounter,
2300 pub(crate) wait_woken_via_sleep: IntCounter,
2301 pub(crate) wait_resolved_via_watch: IntCounter,
2302 pub(crate) wait_resolved_via_sleep: IntCounter,
2303 pub(crate) notify_sent: IntCounter,
2304 pub(crate) notify_upper_sent: IntCounter,
2305 pub(crate) notify_noop: IntCounter,
2306 pub(crate) notify_recv: IntCounter,
2307 pub(crate) notify_lagged: IntCounter,
2308 pub(crate) notify_wait_started: IntCounter,
2309 pub(crate) notify_wait_finished: IntCounter,
2310}
2311
2312impl WatchMetrics {
2313 fn new(registry: &MetricsRegistry) -> Self {
2314 WatchMetrics {
2315 wait_woken_via_watch: registry.register(metric!(
2316 name: "mz_persist_wait_woken_via_watch",
2317 help: "count of wait-for-uppers wakes via watch notify",
2318 )),
2319 wait_woken_via_sleep: registry.register(metric!(
2320 name: "mz_persist_wait_woken_via_sleep",
2321 help: "count of wait-for-uppers wakes via sleep",
2322 )),
2323 wait_resolved_via_watch: registry.register(metric!(
2324 name: "mz_persist_wait_resolved_via_watch",
2325 help: "count of wait-for-uppers resolved via watch notify",
2326 )),
2327 wait_resolved_via_sleep: registry.register(metric!(
2328 name: "mz_persist_wait_resolved_via_sleep",
2329 help: "count of wait-for-uppers resolved via sleep",
2330 )),
2331 notify_sent: registry.register(metric!(
2332 name: "mz_persist_watch_notify_sent",
2333 help: "count of watch notifications sent to a non-empty broadcast channel",
2334 )),
2335 notify_upper_sent: registry.register(metric!(
2336 name: "mz_persist_watch_notify_upper_sent",
2337 help: "count of strict shard upper advances signaled to upper waiters",
2338 )),
2339 notify_noop: registry.register(metric!(
2340 name: "mz_persist_watch_notify_noop",
2341 help: "count of watch notifications sent to an broadcast channel",
2342 )),
2343 notify_recv: registry.register(metric!(
2344 name: "mz_persist_watch_notify_recv",
2345 help: "count of watch notifications received from the broadcast channel",
2346 )),
2347 notify_lagged: registry.register(metric!(
2348 name: "mz_persist_watch_notify_lagged",
2349 help: "count of lagged events in the watch notification broadcast channel",
2350 )),
2351 notify_wait_started: registry.register(metric!(
2352 name: "mz_persist_watch_notify_wait_started",
2353 help: "count of watch wait calls started",
2354 )),
2355 notify_wait_finished: registry.register(metric!(
2356 name: "mz_persist_watch_notify_wait_finished",
2357 help: "count of watch wait calls resolved",
2358 )),
2359 }
2360 }
2361}
2362
2363#[derive(Debug)]
2364pub struct PushdownMetrics {
2365 pub(crate) parts_filtered_count: IntCounter,
2366 pub(crate) parts_filtered_bytes: IntCounter,
2367 pub(crate) parts_fetched_count: IntCounter,
2368 pub(crate) parts_fetched_bytes: IntCounter,
2369 pub(crate) parts_audited_count: IntCounter,
2370 pub(crate) parts_audited_bytes: IntCounter,
2371 pub(crate) parts_inline_count: IntCounter,
2372 pub(crate) parts_inline_bytes: IntCounter,
2373 pub(crate) parts_faked_count: IntCounter,
2374 pub(crate) parts_faked_bytes: IntCounter,
2375 pub(crate) parts_stats_trimmed_count: IntCounter,
2376 pub(crate) parts_stats_trimmed_bytes: IntCounter,
2377 pub(crate) parts_projection_trimmed_bytes: IntCounter,
2378 pub part_stats: PartStatsMetrics,
2379}
2380
2381impl PushdownMetrics {
2382 fn new(registry: &MetricsRegistry) -> Self {
2383 PushdownMetrics {
2384 parts_filtered_count: registry.register(metric!(
2385 name: "mz_persist_pushdown_parts_filtered_count",
2386 help: "count of parts filtered by pushdown",
2387 )),
2388 parts_filtered_bytes: registry.register(metric!(
2389 name: "mz_persist_pushdown_parts_filtered_bytes",
2390 help: "total size of parts filtered by pushdown in bytes",
2391 )),
2392 parts_fetched_count: registry.register(metric!(
2393 name: "mz_persist_pushdown_parts_fetched_count",
2394 help: "count of parts not filtered by pushdown",
2395 )),
2396 parts_fetched_bytes: registry.register(metric!(
2397 name: "mz_persist_pushdown_parts_fetched_bytes",
2398 help: "total size of parts not filtered by pushdown in bytes",
2399 )),
2400 parts_audited_count: registry.register(metric!(
2401 name: "mz_persist_pushdown_parts_audited_count",
2402 help: "count of parts fetched only for pushdown audit",
2403 )),
2404 parts_audited_bytes: registry.register(metric!(
2405 name: "mz_persist_pushdown_parts_audited_bytes",
2406 help: "total size of parts fetched only for pushdown audit",
2407 )),
2408 parts_inline_count: registry.register(metric!(
2409 name: "mz_persist_pushdown_parts_inline_count",
2410 help: "count of parts not fetched because they were inline",
2411 )),
2412 parts_inline_bytes: registry.register(metric!(
2413 name: "mz_persist_pushdown_parts_inline_bytes",
2414 help: "total size of parts not fetched because they were inline",
2415 )),
2416 parts_faked_count: registry.register(metric!(
2417 name: "mz_persist_pushdown_parts_faked_count",
2418 help: "count of parts faked because of aggressive projection pushdown",
2419 )),
2420 parts_faked_bytes: registry.register(metric!(
2421 name: "mz_persist_pushdown_parts_faked_bytes",
2422 help: "total size of parts replaced with fakes by aggressive projection pushdown",
2423 )),
2424 parts_stats_trimmed_count: registry.register(metric!(
2425 name: "mz_persist_pushdown_parts_stats_trimmed_count",
2426 help: "count of trimmed part stats",
2427 )),
2428 parts_stats_trimmed_bytes: registry.register(metric!(
2429 name: "mz_persist_pushdown_parts_stats_trimmed_bytes",
2430 help: "total bytes trimmed from part stats",
2431 )),
2432 parts_projection_trimmed_bytes: registry.register(metric!(
2433 name: "mz_persist_pushdown_parts_projection_trimmed_bytes",
2434 help: "total bytes trimmed from columnar data because of projection pushdown",
2435 )),
2436 part_stats: PartStatsMetrics::new(registry),
2437 }
2438 }
2439}
2440
2441#[derive(Debug)]
2442pub struct ConsolidationMetrics {
2443 pub(crate) parts_fetched: IntCounter,
2444 pub(crate) parts_skipped: IntCounter,
2445 pub(crate) parts_wasted: IntCounter,
2446 pub(crate) wrong_sort: IntCounter,
2447}
2448
2449impl ConsolidationMetrics {
2450 fn new(registry: &MetricsRegistry) -> Self {
2451 ConsolidationMetrics {
2452 parts_fetched: registry.register(metric!(
2453 name: "mz_persist_consolidation_parts_fetched_count",
2454 help: "count of parts that were fetched and used during consolidation",
2455 )),
2456 parts_skipped: registry.register(metric!(
2457 name: "mz_persist_consolidation_parts_skipped_count",
2458 help: "count of parts that were never needed during consolidation",
2459 )),
2460 parts_wasted: registry.register(metric!(
2461 name: "mz_persist_consolidation_parts_wasted_count",
2462 help: "count of parts that were fetched but not needed during consolidation",
2463 )),
2464 wrong_sort: registry.register(metric!(
2465 name: "mz_persist_consolidation_wrong_sort_count",
2466 help: "count of runs that were sorted using the wrong ordering for the current consolidation",
2467 )),
2468 }
2469 }
2470}
2471
2472#[derive(Debug)]
2473pub struct BlobMemCache {
2474 pub(crate) size_blobs: UIntGauge,
2475 pub(crate) size_bytes: UIntGauge,
2476 pub(crate) hits_blobs: IntCounter,
2477 pub(crate) hits_bytes: IntCounter,
2478 pub(crate) evictions: IntCounter,
2479}
2480
2481impl BlobMemCache {
2482 fn new(registry: &MetricsRegistry) -> Self {
2483 BlobMemCache {
2484 size_blobs: registry.register(metric!(
2485 name: "mz_persist_blob_cache_size_blobs",
2486 help: "count of blobs in the cache",
2487 const_labels: {"cache" => "mem"},
2488 )),
2489 size_bytes: registry.register(metric!(
2490 name: "mz_persist_blob_cache_size_bytes",
2491 help: "total size of blobs in the cache",
2492 const_labels: {"cache" => "mem"},
2493 )),
2494 hits_blobs: registry.register(metric!(
2495 name: "mz_persist_blob_cache_hits_blobs",
2496 help: "count of blobs served via cache instead of s3",
2497 const_labels: {"cache" => "mem"},
2498 )),
2499 hits_bytes: registry.register(metric!(
2500 name: "mz_persist_blob_cache_hits_bytes",
2501 help: "total size of blobs served via cache instead of s3",
2502 const_labels: {"cache" => "mem"},
2503 )),
2504 evictions: registry.register(metric!(
2505 name: "mz_persist_blob_cache_evictions",
2506 help: "count of capacity-based cache evictions",
2507 const_labels: {"cache" => "mem"},
2508 )),
2509 }
2510 }
2511}
2512
2513#[derive(Debug)]
2514pub struct SemaphoreMetrics {
2515 cfg: PersistConfig,
2516 registry: MetricsRegistry,
2517 fetch: OnceCell<MetricsSemaphore>,
2518}
2519
2520impl SemaphoreMetrics {
2521 fn new(cfg: PersistConfig, registry: MetricsRegistry) -> Self {
2522 SemaphoreMetrics {
2523 cfg,
2524 registry,
2525 fetch: OnceCell::new(),
2526 }
2527 }
2528
2529 async fn fetch(&self) -> &MetricsSemaphore {
2533 if let Some(x) = self.fetch.get() {
2534 return x;
2536 }
2537 let cfg = self.cfg.clone();
2538 let registry = self.registry.clone();
2539 let init = async move {
2540 let total_permits = match cfg.announce_memory_limit {
2541 Some(mem) if cfg.is_cc_active => {
2544 info!("fetch semaphore awaiting first dyncfg values");
2547 let () = cfg.configs_synced_once().await;
2548 let total_permits = usize::cast_lossy(
2549 f64::cast_lossy(mem) * FETCH_SEMAPHORE_PERMIT_ADJUSTMENT.get(&cfg),
2550 );
2551 info!("fetch_semaphore got first dyncfg values");
2552 total_permits
2553 }
2554 Some(_) | None => Semaphore::MAX_PERMITS,
2555 };
2556 MetricsSemaphore::new(®istry, "fetch", total_permits)
2557 };
2558 self.fetch.get_or_init(|| init).await
2559 }
2560
2561 pub(crate) async fn acquire_fetch_permits(&self, encoded_size_bytes: usize) -> MetricsPermits {
2562 let requested_permits = f64::cast_lossy(encoded_size_bytes);
2565 let requested_permits = requested_permits * FETCH_SEMAPHORE_COST_ADJUSTMENT.get(&self.cfg);
2566 let requested_permits = usize::cast_lossy(requested_permits);
2567 self.fetch().await.acquire_permits(requested_permits).await
2568 }
2569}
2570
2571#[derive(Debug)]
2572pub struct MetricsSemaphore {
2573 name: &'static str,
2574 semaphore: Arc<Semaphore>,
2575 total_permits: usize,
2576 acquire_count: IntCounter,
2577 blocking_count: IntCounter,
2578 blocking_seconds: Counter,
2579 acquired_permits: IntCounter,
2580 released_permits: IntCounter,
2581 _available_permits: ComputedUIntGauge,
2582}
2583
2584impl MetricsSemaphore {
2585 pub fn new(registry: &MetricsRegistry, name: &'static str, total_permits: usize) -> Self {
2586 let total_permits = std::cmp::min(total_permits, Semaphore::MAX_PERMITS);
2587 let semaphore = Arc::new(Semaphore::new(total_permits));
2590 MetricsSemaphore {
2591 name,
2592 total_permits,
2593 acquire_count: registry.register(metric!(
2594 name: "mz_persist_semaphore_acquire_count",
2595 help: "count of acquire calls (not acquired permits count)",
2596 const_labels: {"name" => name},
2597 )),
2598 blocking_count: registry.register(metric!(
2599 name: "mz_persist_semaphore_blocking_count",
2600 help: "count of acquire calls that had to block",
2601 const_labels: {"name" => name},
2602 )),
2603 blocking_seconds: registry.register(metric!(
2604 name: "mz_persist_semaphore_blocking_seconds",
2605 help: "total time spent blocking on permit acquisition",
2606 const_labels: {"name" => name},
2607 )),
2608 acquired_permits: registry.register(metric!(
2609 name: "mz_persist_semaphore_acquired_permits",
2610 help: "total sum of acquired permits",
2611 const_labels: {"name" => name},
2612 )),
2613 released_permits: registry.register(metric!(
2614 name: "mz_persist_semaphore_released_permits",
2615 help: "total sum of released permits",
2616 const_labels: {"name" => name},
2617 )),
2618 _available_permits: registry.register_computed_gauge(
2619 metric!(
2620 name: "mz_persist_semaphore_available_permits",
2621 help: "currently available permits according to the semaphore",
2622 ),
2623 {
2624 let semaphore = Arc::clone(&semaphore);
2625 move || u64::cast_from(semaphore.available_permits())
2626 },
2627 ),
2628 semaphore,
2629 }
2630 }
2631
2632 pub async fn acquire_permits(&self, requested_permits: usize) -> MetricsPermits {
2633 let total_permits = u32::try_from(self.total_permits).unwrap_or(u32::MAX);
2636 let requested_permits = u32::try_from(requested_permits).unwrap_or(u32::MAX);
2637 let requested_permits = std::cmp::min(requested_permits, total_permits);
2638 let wrap = |_permit| {
2639 self.acquired_permits.inc_by(u64::from(requested_permits));
2640 MetricsPermits {
2641 _permit,
2642 released_metric: self.released_permits.clone(),
2643 count: requested_permits,
2644 }
2645 };
2646
2647 self.acquire_count.inc();
2649 match Arc::clone(&self.semaphore).try_acquire_many_owned(requested_permits) {
2650 Ok(x) => return wrap(x),
2651 Err(_) => {}
2652 };
2653
2654 self.blocking_count.inc();
2656 let start = Instant::now();
2657 let ret = Arc::clone(&self.semaphore)
2658 .acquire_many_owned(requested_permits)
2659 .instrument(info_span!("acquire_permits"))
2660 .await;
2661 let elapsed = start.elapsed();
2662 self.blocking_seconds.inc_by(elapsed.as_secs_f64());
2663 debug!(
2664 "acquisition of {} {} permits blocked for {:?}",
2665 self.name, requested_permits, elapsed
2666 );
2667 wrap(ret.expect("semaphore is never closed"))
2668 }
2669}
2670
2671#[derive(Debug)]
2672pub struct MetricsPermits {
2673 _permit: OwnedSemaphorePermit,
2674 released_metric: IntCounter,
2675 count: u32,
2676}
2677
2678impl Drop for MetricsPermits {
2679 fn drop(&mut self) {
2680 self.released_metric.inc_by(u64::from(self.count))
2681 }
2682}
2683
2684#[derive(Debug)]
2685pub struct ExternalOpMetrics {
2686 started: IntCounter,
2687 succeeded: IntCounter,
2688 failed: IntCounter,
2689 bytes: IntCounter,
2690 seconds: Counter,
2691 seconds_histogram: Option<Histogram>,
2692 alerts_metrics: Arc<AlertsMetrics>,
2693}
2694
2695impl ExternalOpMetrics {
2696 async fn run_op<R, F, OpFn, ErrFn>(
2697 &self,
2698 op_fn: OpFn,
2699 on_err_fn: ErrFn,
2700 ) -> Result<R, ExternalError>
2701 where
2702 F: std::future::Future<Output = Result<R, ExternalError>>,
2703 OpFn: FnOnce() -> F,
2704 ErrFn: FnOnce(&AlertsMetrics, &ExternalError),
2705 {
2706 self.started.inc();
2707 let start = Instant::now();
2708 let res = op_fn().await;
2709 let elapsed_seconds = start.elapsed().as_secs_f64();
2710 self.seconds.inc_by(elapsed_seconds);
2711 if let Some(h) = &self.seconds_histogram {
2712 h.observe(elapsed_seconds);
2713 }
2714 match res.as_ref() {
2715 Ok(_) => self.succeeded.inc(),
2716 Err(err) => {
2717 self.failed.inc();
2718 on_err_fn(&self.alerts_metrics, err);
2719 }
2720 };
2721 res
2722 }
2723
2724 fn run_stream<'a, R: 'a, S, OpFn, ErrFn>(
2725 &'a self,
2726 op_fn: OpFn,
2727 mut on_err_fn: ErrFn,
2728 ) -> impl futures::Stream<Item = Result<R, ExternalError>> + 'a
2729 where
2730 S: futures::Stream<Item = Result<R, ExternalError>> + Unpin + 'a,
2731 OpFn: FnOnce() -> S,
2732 ErrFn: FnMut(&AlertsMetrics, &ExternalError) + 'a,
2733 {
2734 self.started.inc();
2735 let start = Instant::now();
2736 let mut stream = op_fn();
2737 stream! {
2738 let mut succeeded = true;
2739 while let Some(res) = stream.next().await {
2740 if let Err(err) = res.as_ref() {
2741 on_err_fn(&self.alerts_metrics, err);
2742 succeeded = false;
2743 }
2744 yield res;
2745 }
2746 if succeeded {
2747 self.succeeded.inc()
2748 } else {
2749 self.failed.inc()
2750 }
2751 let elapsed_seconds = start.elapsed().as_secs_f64();
2752 self.seconds.inc_by(elapsed_seconds);
2753 if let Some(h) = &self.seconds_histogram {
2754 h.observe(elapsed_seconds);
2755 }
2756 }
2757 }
2758}
2759
2760#[derive(Debug)]
2761pub struct BlobMetrics {
2762 set: ExternalOpMetrics,
2763 get: ExternalOpMetrics,
2764 list_keys: ExternalOpMetrics,
2765 delete: ExternalOpMetrics,
2766 restore: ExternalOpMetrics,
2767 delete_noop: IntCounter,
2768 blob_sizes: Histogram,
2769 pub rtt_latency: Gauge,
2770}
2771
2772#[derive(Debug)]
2773pub struct MetricsBlob {
2774 blob: Arc<dyn Blob>,
2775 metrics: Arc<Metrics>,
2776}
2777
2778impl MetricsBlob {
2779 pub fn new(blob: Arc<dyn Blob>, metrics: Arc<Metrics>) -> Self {
2780 MetricsBlob { blob, metrics }
2781 }
2782
2783 fn on_err(alerts_metrics: &AlertsMetrics, _err: &ExternalError) {
2784 alerts_metrics.blob_failures.inc()
2785 }
2786}
2787
2788#[async_trait]
2789impl Blob for MetricsBlob {
2790 #[instrument(name = "blob::get", fields(shard=blob_key_shard_id(key)))]
2791 async fn get(&self, key: &str) -> Result<Option<SegmentedBytes>, ExternalError> {
2792 let res = self
2793 .metrics
2794 .blob
2795 .get
2796 .run_op(|| self.blob.get(key), Self::on_err)
2797 .await;
2798 if let Ok(Some(value)) = res.as_ref() {
2799 self.metrics
2800 .blob
2801 .get
2802 .bytes
2803 .inc_by(u64::cast_from(value.len()));
2804 }
2805 res
2806 }
2807
2808 #[instrument(name = "blob::list_keys_and_metadata", fields(shard=blob_key_shard_id(key_prefix)))]
2809 async fn list_keys_and_metadata(
2810 &self,
2811 key_prefix: &str,
2812 f: &mut (dyn FnMut(BlobMetadata) + Send + Sync),
2813 ) -> Result<(), ExternalError> {
2814 let mut byte_total = 0;
2815 let mut instrumented = |blob_metadata: BlobMetadata| {
2816 byte_total += blob_metadata.key.len();
2819 f(blob_metadata)
2820 };
2821
2822 let res = self
2823 .metrics
2824 .blob
2825 .list_keys
2826 .run_op(
2827 || {
2828 self.blob
2829 .list_keys_and_metadata(key_prefix, &mut instrumented)
2830 },
2831 Self::on_err,
2832 )
2833 .await;
2834
2835 self.metrics
2836 .blob
2837 .list_keys
2838 .bytes
2839 .inc_by(u64::cast_from(byte_total));
2840
2841 res
2842 }
2843
2844 #[instrument(name = "blob::set", fields(shard=blob_key_shard_id(key),size_bytes=value.len()))]
2845 async fn set(&self, key: &str, value: Bytes) -> Result<(), ExternalError> {
2846 let bytes = value.len();
2847 let res = self
2848 .metrics
2849 .blob
2850 .set
2851 .run_op(|| self.blob.set(key, value), Self::on_err)
2852 .await;
2853 if res.is_ok() {
2854 self.metrics.blob.set.bytes.inc_by(u64::cast_from(bytes));
2855 self.metrics.blob.blob_sizes.observe(f64::cast_lossy(bytes));
2856 }
2857 res
2858 }
2859
2860 #[instrument(name = "blob::delete", fields(shard=blob_key_shard_id(key)))]
2861 async fn delete(&self, key: &str) -> Result<Option<usize>, ExternalError> {
2862 let bytes = self
2863 .metrics
2864 .blob
2865 .delete
2866 .run_op(|| self.blob.delete(key), Self::on_err)
2867 .await?;
2868 if let Some(bytes) = bytes {
2869 self.metrics.blob.delete.bytes.inc_by(u64::cast_from(bytes));
2870 } else {
2871 self.metrics.blob.delete_noop.inc();
2872 }
2873 Ok(bytes)
2874 }
2875
2876 async fn restore(&self, key: &str) -> Result<(), ExternalError> {
2877 self.metrics
2878 .blob
2879 .restore
2880 .run_op(|| self.blob.restore(key), Self::on_err)
2881 .await
2882 }
2883}
2884
2885#[derive(Debug)]
2886pub struct ConsensusMetrics {
2887 list_keys: ExternalOpMetrics,
2888 head: ExternalOpMetrics,
2889 compare_and_set: ExternalOpMetrics,
2890 scan: ExternalOpMetrics,
2891 truncate: ExternalOpMetrics,
2892 truncated_count: IntCounter,
2893 pub rtt_latency: Gauge,
2894}
2895
2896#[derive(Debug)]
2897pub struct MetricsConsensus {
2898 consensus: Arc<dyn Consensus>,
2899 metrics: Arc<Metrics>,
2900}
2901
2902impl MetricsConsensus {
2903 pub fn new(consensus: Arc<dyn Consensus>, metrics: Arc<Metrics>) -> Self {
2904 MetricsConsensus { consensus, metrics }
2905 }
2906
2907 fn on_err(alerts_metrics: &AlertsMetrics, err: &ExternalError) {
2908 if let ExternalError::Indeterminate(_) = err {
2912 alerts_metrics.consensus_failures.inc()
2913 }
2914 }
2915}
2916
2917#[async_trait]
2918impl Consensus for MetricsConsensus {
2919 fn list_keys(&self) -> ResultStream<'_, String> {
2920 Box::pin(
2921 self.metrics
2922 .consensus
2923 .list_keys
2924 .run_stream(|| self.consensus.list_keys(), Self::on_err),
2925 )
2926 }
2927
2928 #[instrument(name = "consensus::head", fields(shard=key))]
2929 async fn head(&self, key: &str) -> Result<Option<VersionedData>, ExternalError> {
2930 let res = self
2931 .metrics
2932 .consensus
2933 .head
2934 .run_op(|| self.consensus.head(key), Self::on_err)
2935 .await;
2936 if let Ok(Some(data)) = res.as_ref() {
2937 self.metrics
2938 .consensus
2939 .head
2940 .bytes
2941 .inc_by(u64::cast_from(data.data.len()));
2942 }
2943 res
2944 }
2945
2946 #[instrument(name = "consensus::compare_and_set", fields(shard=key,size_bytes=new.data.len()))]
2947 async fn compare_and_set(
2948 &self,
2949 key: &str,
2950 new: VersionedData,
2951 ) -> Result<CaSResult, ExternalError> {
2952 let bytes = new.data.len();
2953 let res = self
2954 .metrics
2955 .consensus
2956 .compare_and_set
2957 .run_op(|| self.consensus.compare_and_set(key, new), Self::on_err)
2958 .await;
2959 match res.as_ref() {
2960 Ok(CaSResult::Committed) => self
2961 .metrics
2962 .consensus
2963 .compare_and_set
2964 .bytes
2965 .inc_by(u64::cast_from(bytes)),
2966 Ok(CaSResult::ExpectationMismatch) | Err(_) => {}
2967 }
2968 res
2969 }
2970
2971 #[instrument(name = "consensus::scan", fields(shard=key))]
2972 async fn scan(
2973 &self,
2974 key: &str,
2975 from: SeqNo,
2976 limit: usize,
2977 ) -> Result<Vec<VersionedData>, ExternalError> {
2978 let res = self
2979 .metrics
2980 .consensus
2981 .scan
2982 .run_op(|| self.consensus.scan(key, from, limit), Self::on_err)
2983 .await;
2984 if let Ok(dataz) = res.as_ref() {
2985 let bytes: usize = dataz.iter().map(|x| x.data.len()).sum();
2986 self.metrics
2987 .consensus
2988 .scan
2989 .bytes
2990 .inc_by(u64::cast_from(bytes));
2991 }
2992 res
2993 }
2994
2995 #[instrument(name = "consensus::truncate", fields(shard=key))]
2996 async fn truncate(&self, key: &str, seqno: SeqNo) -> Result<Option<usize>, ExternalError> {
2997 let metrics = &self.metrics.consensus;
2998 let deleted = metrics
2999 .truncate
3000 .run_op(|| self.consensus.truncate(key, seqno), Self::on_err)
3001 .await?;
3002 if let Some(deleted) = deleted {
3003 metrics.truncated_count.inc_by(u64::cast_from(deleted));
3004 }
3005 Ok(deleted)
3006 }
3007}
3008
3009#[derive(Debug, Clone)]
3012pub struct TaskMetrics {
3013 f64_gauges: Vec<(Gauge, fn(&tokio_metrics::TaskMetrics) -> f64)>,
3014 u64_gauges: Vec<(
3015 GenericGauge<AtomicU64>,
3016 fn(&tokio_metrics::TaskMetrics) -> u64,
3017 )>,
3018 monitor: TaskMonitor,
3019}
3020
3021impl TaskMetrics {
3022 pub fn new(name: &str) -> Self {
3023 let monitor = TaskMonitor::new();
3024 Self {
3025 f64_gauges: vec![
3026 (
3027 Gauge::make_collector(metric!(
3028 name: "mz_persist_task_total_idle_duration",
3029 help: "Seconds of time spent idling, ie. waiting for a task to be woken up.",
3030 const_labels: {"name" => name}
3031 )),
3032 |m| m.total_idle_duration.as_secs_f64(),
3033 ),
3034 (
3035 Gauge::make_collector(metric!(
3036 name: "mz_persist_task_total_scheduled_duration",
3037 help: "Seconds of time spent scheduled, ie. ready to poll but not yet polled.",
3038 const_labels: {"name" => name}
3039 )),
3040 |m| m.total_scheduled_duration.as_secs_f64(),
3041 ),
3042 ],
3043 u64_gauges: vec![
3044 (
3045 MakeCollector::make_collector(metric!(
3046 name: "mz_persist_task_total_scheduled_count",
3047 help: "The total number of task schedules. Useful for computing the average scheduled time.",
3048 const_labels: {"name" => name}
3049 )),
3050 |m| m.total_scheduled_count,
3051 ),
3052 (
3053 MakeCollector::make_collector(metric!(
3054 name: "mz_persist_task_total_idled_count",
3055 help: "The total number of task idles. Useful for computing the average idle time.",
3056 const_labels: {"name" => name}
3057 ,
3058 )),
3059 |m| m.total_idled_count,
3060 ),
3061 ],
3062 monitor,
3063 }
3064 }
3065
3066 pub fn instrument_task<F>(&self, task: F) -> tokio_metrics::Instrumented<F> {
3069 TaskMonitor::instrument(&self.monitor, task)
3070 }
3071}
3072
3073impl Collector for TaskMetrics {
3074 fn desc(&self) -> Vec<&Desc> {
3075 let mut descs = Vec::with_capacity(self.f64_gauges.len() + self.u64_gauges.len());
3076 for (g, _) in &self.f64_gauges {
3077 descs.extend(g.desc());
3078 }
3079 for (g, _) in &self.u64_gauges {
3080 descs.extend(g.desc());
3081 }
3082 descs
3083 }
3084
3085 fn collect(&self) -> Vec<MetricFamily> {
3086 let mut families = Vec::with_capacity(self.f64_gauges.len() + self.u64_gauges.len());
3087 let metrics = self.monitor.cumulative();
3088 for (g, metrics_fn) in &self.f64_gauges {
3089 g.set(metrics_fn(&metrics));
3090 families.extend(g.collect());
3091 }
3092 for (g, metrics_fn) in &self.u64_gauges {
3093 g.set(metrics_fn(&metrics));
3094 families.extend(g.collect());
3095 }
3096 families
3097 }
3098}
3099
3100#[derive(Debug)]
3101pub struct TasksMetrics {
3102 pub heartbeat_read: TaskMetrics,
3103}
3104
3105impl TasksMetrics {
3106 fn new(registry: &MetricsRegistry) -> Self {
3107 let heartbeat_read = TaskMetrics::new("heartbeat_read");
3108 registry.register_collector(heartbeat_read.clone());
3109 TasksMetrics { heartbeat_read }
3110 }
3111}
3112
3113#[derive(Debug)]
3114pub struct SchemaMetrics {
3115 pub(crate) cache_fetch_state_count: IntCounter,
3116 pub(crate) cache_schema: SchemaCacheMetrics,
3117 pub(crate) cache_migration: SchemaCacheMetrics,
3118 pub(crate) migration_count_same: IntCounter,
3119 pub(crate) migration_count_codec: IntCounter,
3120 pub(crate) migration_count_either: IntCounter,
3121 pub(crate) migration_len_legacy_codec: IntCounter,
3122 pub(crate) migration_len_either_codec: IntCounter,
3123 pub(crate) migration_len_either_arrow: IntCounter,
3124 pub(crate) migration_new_count: IntCounter,
3125 pub(crate) migration_new_seconds: Counter,
3126 pub(crate) migration_migrate_seconds: Counter,
3127}
3128
3129impl SchemaMetrics {
3130 fn new(registry: &MetricsRegistry) -> Self {
3131 let cached: IntCounterVec = registry.register(metric!(
3132 name: "mz_persist_schema_cache_cached_count",
3133 help: "count of schema cache entries served from cache",
3134 var_labels: ["op"],
3135 ));
3136 let computed: IntCounterVec = registry.register(metric!(
3137 name: "mz_persist_schema_cache_computed_count",
3138 help: "count of schema cache entries computed",
3139 var_labels: ["op"],
3140 ));
3141 let unavailable: IntCounterVec = registry.register(metric!(
3142 name: "mz_persist_schema_cache_unavailable_count",
3143 help: "count of schema cache entries unavailable at current state",
3144 var_labels: ["op"],
3145 ));
3146 let added: IntCounterVec = registry.register(metric!(
3147 name: "mz_persist_schema_cache_added_count",
3148 help: "count of schema cache entries added",
3149 var_labels: ["op"],
3150 ));
3151 let dropped: IntCounterVec = registry.register(metric!(
3152 name: "mz_persist_schema_cache_dropped_count",
3153 help: "count of schema cache entries dropped",
3154 var_labels: ["op"],
3155 ));
3156 let cache = |name| SchemaCacheMetrics {
3157 cached_count: cached.with_label_values(&[name]),
3158 computed_count: computed.with_label_values(&[name]),
3159 unavailable_count: unavailable.with_label_values(&[name]),
3160 added_count: added.with_label_values(&[name]),
3161 dropped_count: dropped.with_label_values(&[name]),
3162 };
3163 let migration_count: IntCounterVec = registry.register(metric!(
3164 name: "mz_persist_schema_migration_count",
3165 help: "count of fetch part migrations",
3166 var_labels: ["op"],
3167 ));
3168 let migration_len: IntCounterVec = registry.register(metric!(
3169 name: "mz_persist_schema_migration_len",
3170 help: "count of migrated update records",
3171 var_labels: ["op"],
3172 ));
3173 SchemaMetrics {
3174 cache_fetch_state_count: registry.register(metric!(
3175 name: "mz_persist_schema_cache_fetch_state_count",
3176 help: "count of state fetches by the schema cache",
3177 )),
3178 cache_schema: cache("schema"),
3179 cache_migration: cache("migration"),
3180 migration_count_same: migration_count.with_label_values(&["same"]),
3181 migration_count_codec: migration_count.with_label_values(&["codec"]),
3182 migration_count_either: migration_count.with_label_values(&["either"]),
3183 migration_len_legacy_codec: migration_len.with_label_values(&["legacy_codec"]),
3184 migration_len_either_codec: migration_len.with_label_values(&["either_codec"]),
3185 migration_len_either_arrow: migration_len.with_label_values(&["either_arrow"]),
3186 migration_new_count: registry.register(metric!(
3187 name: "mz_persist_schema_migration_new_count",
3188 help: "count of migrations constructed",
3189 )),
3190 migration_new_seconds: registry.register(metric!(
3191 name: "mz_persist_schema_migration_new_seconds",
3192 help: "seconds spent constructing migration logic",
3193 )),
3194 migration_migrate_seconds: registry.register(metric!(
3195 name: "mz_persist_schema_migration_migrate_seconds",
3196 help: "seconds spent applying migration logic",
3197 )),
3198 }
3199 }
3200}
3201
3202#[derive(Debug, Clone)]
3203pub struct SchemaCacheMetrics {
3204 pub(crate) cached_count: IntCounter,
3205 pub(crate) computed_count: IntCounter,
3206 pub(crate) unavailable_count: IntCounter,
3207 pub(crate) added_count: IntCounter,
3208 pub(crate) dropped_count: IntCounter,
3209}
3210
3211#[derive(Debug)]
3212pub struct InlineMetrics {
3213 pub(crate) part_commit_count: IntCounter,
3214 pub(crate) part_commit_bytes: IntCounter,
3215 pub(crate) backpressure: BatchWriteMetrics,
3216}
3217
3218impl InlineMetrics {
3219 fn new(registry: &MetricsRegistry) -> Self {
3220 InlineMetrics {
3221 part_commit_count: registry.register(metric!(
3222 name: "mz_persist_inline_part_commit_count",
3223 help: "count of inline parts committed to state",
3224 )),
3225 part_commit_bytes: registry.register(metric!(
3226 name: "mz_persist_inline_part_commit_bytes",
3227 help: "total size of of inline parts committed to state",
3228 )),
3229 backpressure: BatchWriteMetrics::new(registry, "inline_backpressure"),
3230 }
3231 }
3232}
3233
3234fn blob_key_shard_id(key: &str) -> Option<String> {
3235 let (shard_id, _) = BlobKey::parse_ids(key).ok()?;
3236 Some(shard_id.to_string())
3237}
3238
3239pub fn encode_ts_metric<T: Codec64>(ts: &Antichain<T>) -> i64 {
3241 match ts.elements().first() {
3251 Some(ts) => i64::from_le_bytes(Codec64::encode(ts)),
3252 None => i64::MAX,
3253 }
3254}