1use std::collections::{HashMap, HashSet};
16use std::sync::atomic::AtomicU64;
17use std::sync::{Arc, LazyLock};
18use std::time::Duration;
19
20use prometheus::core::{AtomicF64, GenericGaugeVec};
21use prometheus::{
22 GaugeVec, Histogram, HistogramVec, IntCounterVec, IntGauge, IntGaugeVec, Registry,
23 exponential_buckets, histogram_opts, register_gauge_vec_with_registry,
24 register_histogram_vec_with_registry, register_histogram_with_registry,
25 register_int_counter_vec_with_registry, register_int_gauge_vec_with_registry,
26 register_int_gauge_with_registry,
27};
28use risingwave_common::catalog::{FragmentTypeFlag, TableId};
29use risingwave_common::metrics::{
30 LabelGuardedHistogramVec, LabelGuardedIntCounterVec, LabelGuardedIntGaugeVec,
31 LabelGuardedUintGaugeVec,
32};
33use risingwave_common::monitor::GLOBAL_METRICS_REGISTRY;
34use risingwave_common::system_param::reader::SystemParamsRead;
35use risingwave_common::util::stream_graph_visitor::{
36 visit_stream_node_source_backfill, visit_stream_node_stream_scan,
37};
38use risingwave_common::{
39 register_guarded_histogram_vec_with_registry, register_guarded_int_counter_vec_with_registry,
40 register_guarded_int_gauge_vec_with_registry, register_guarded_uint_gauge_vec_with_registry,
41};
42use risingwave_connector::source::monitor::EnumeratorMetrics as SourceEnumeratorMetrics;
43use risingwave_meta_model::table::TableType;
44use risingwave_meta_model::{ObjectId, WorkerId};
45use risingwave_object_store::object::object_metrics::{
46 GLOBAL_OBJECT_STORE_METRICS, ObjectStoreMetrics,
47};
48use risingwave_pb::common::WorkerType;
49use risingwave_pb::meta::FragmentDistribution;
50use thiserror_ext::AsReport;
51use tokio::sync::oneshot::Sender;
52use tokio::task::JoinHandle;
53
54use crate::barrier::BarrierManagerRef;
55use crate::controller::catalog::CatalogControllerRef;
56use crate::controller::cluster::ClusterControllerRef;
57use crate::controller::system_param::SystemParamsControllerRef;
58use crate::controller::utils::PartialFragmentStateTables;
59use crate::hummock::HummockManagerRef;
60use crate::manager::MetadataManager;
61use crate::rpc::ElectionClientRef;
62
63struct BackfillFragmentInfo {
64 job_id: u32,
65 fragment_id: u32,
66 backfill_state_table_id: u32,
67 backfill_target_relation_id: u32,
68 backfill_type: &'static str,
69 backfill_epoch: u64,
70}
71
72#[derive(Clone)]
73pub struct MetaMetrics {
74 pub worker_num: IntGaugeVec,
77 pub meta_type: IntGaugeVec,
79
80 pub grpc_latency: HistogramVec,
83
84 pub barrier_latency: LabelGuardedHistogramVec,
88 pub barrier_wait_commit_latency: Histogram,
90 pub all_barrier_nums: LabelGuardedIntGaugeVec,
93 pub in_flight_barrier_nums: LabelGuardedIntGaugeVec,
95 pub last_committed_barrier_time: LabelGuardedIntGaugeVec,
97 pub barrier_interval_by_database: GaugeVec,
99
100 pub snapshot_backfill_barrier_latency: LabelGuardedHistogramVec, pub snapshot_backfill_lag: LabelGuardedIntGaugeVec, pub snapshot_backfill_inflight_barrier_num: LabelGuardedIntGaugeVec, pub recovery_failure_cnt: IntCounterVec,
110 pub recovery_latency: HistogramVec,
111
112 pub max_committed_epoch: IntGauge,
115 pub min_committed_epoch: IntGauge,
117 pub level_sst_num: IntGaugeVec,
119 pub level_compact_cnt: IntGaugeVec,
121 pub compact_frequency: IntCounterVec,
123 pub level_file_size: IntGaugeVec,
125 pub version_size: IntGauge,
127 pub current_version_id: IntGauge,
129 pub checkpoint_version_id: IntGauge,
131 pub min_pinned_version_id: IntGauge,
133 pub min_safepoint_version_id: IntGauge,
135 pub write_stop_compaction_groups: IntGaugeVec,
137 pub full_gc_trigger_count: IntGauge,
139 pub full_gc_candidate_object_count: Histogram,
141 pub full_gc_selected_object_count: Histogram,
143 pub version_stats: IntGaugeVec,
145 pub materialized_view_stats: IntGaugeVec,
147 pub stale_object_count: IntGauge,
149 pub stale_object_size: IntGauge,
151 pub old_version_object_count: IntGauge,
153 pub old_version_object_size: IntGauge,
155 pub time_travel_object_count: IntGauge,
157 pub current_version_object_count: IntGauge,
159 pub current_version_object_size: IntGauge,
161 pub total_object_count: IntGauge,
163 pub total_object_size: IntGauge,
165 pub table_change_log_object_count: IntGaugeVec,
167 pub table_change_log_object_size: IntGaugeVec,
169 pub table_change_log_min_epoch: IntGaugeVec,
171 pub table_change_log_get_latency: Histogram,
173 pub delta_log_count: IntGauge,
175 pub version_checkpoint_latency: Histogram,
177 pub hummock_manager_lock_time: HistogramVec,
179 pub hummock_manager_real_process_time: HistogramVec,
181 pub compact_skip_frequency: IntCounterVec,
183 pub compact_pending_bytes: IntGaugeVec,
185 pub compact_level_compression_ratio: GenericGaugeVec<AtomicF64>,
187 pub level_compact_task_cnt: IntGaugeVec,
189 pub time_after_last_observation: Arc<AtomicU64>,
190 pub l0_compact_level_count: HistogramVec,
191 pub compact_task_size: HistogramVec,
192 pub compact_task_file_count: HistogramVec,
193 pub compact_task_batch_count: HistogramVec,
194 pub split_compaction_group_count: IntCounterVec,
195 pub state_table_count: IntGaugeVec,
196 pub branched_sst_count: IntGaugeVec,
197 pub compact_task_trivial_move_sst_count: HistogramVec,
198
199 pub compaction_event_consumed_latency: Histogram,
200 pub compaction_event_loop_iteration_latency: Histogram,
201 pub time_travel_vacuum_metadata_latency: Histogram,
202 pub time_travel_write_metadata_latency: Histogram,
203
204 pub object_store_metric: Arc<ObjectStoreMetrics>,
207
208 pub source_is_up: LabelGuardedIntGaugeVec,
211 pub source_worker_tick_duration_seconds: LabelGuardedHistogramVec,
213 pub source_enumerator_monitor_error_count: LabelGuardedIntCounterVec,
215 pub source_enumerator_metrics: Arc<SourceEnumeratorMetrics>,
216
217 pub actor_info: IntGaugeVec,
220 pub table_info: IntGaugeVec,
222 pub sink_info: IntGaugeVec,
224 pub relation_info: IntGaugeVec,
226 pub database_info: IntGaugeVec,
228 pub backfill_fragment_progress: IntGaugeVec,
230 pub streaming_table_change_log_retention_seconds: IntGaugeVec,
232
233 pub system_param_info: IntGaugeVec,
237
238 pub table_write_throughput: IntCounterVec,
240
241 pub merge_compaction_group_count: IntCounterVec,
243
244 pub auto_schema_change_failure_cnt: LabelGuardedIntCounterVec,
246 pub auto_schema_change_success_cnt: LabelGuardedIntCounterVec,
247 pub auto_schema_change_latency: LabelGuardedHistogramVec,
248
249 pub time_travel_version_replay_latency: Histogram,
250
251 pub compaction_group_count: IntGauge,
252 pub compaction_group_size: IntGaugeVec,
253 pub compaction_group_file_count: IntGaugeVec,
254 pub compaction_group_throughput: IntGaugeVec,
255
256 pub refresh_job_duration: LabelGuardedUintGaugeVec,
258 pub refresh_job_finish_cnt: LabelGuardedIntCounterVec,
259 pub refresh_cron_job_trigger_cnt: LabelGuardedIntCounterVec,
260 pub refresh_cron_job_miss_cnt: LabelGuardedIntCounterVec,
261}
262
263pub static GLOBAL_META_METRICS: LazyLock<MetaMetrics> =
264 LazyLock::new(|| MetaMetrics::new(&GLOBAL_METRICS_REGISTRY));
265
266fn latency_buckets(max: f64, count: usize) -> Vec<f64> {
267 const MIN: f64 = 0.1;
268
269 assert!(count > 1);
270 let factor = (max / MIN).powf(1.0 / (count - 1) as f64);
271 let mut buckets = exponential_buckets(MIN, factor, count).unwrap();
272 *buckets.last_mut().unwrap() = max;
273 buckets
274}
275
276impl MetaMetrics {
277 fn new(registry: &Registry) -> Self {
278 let opts = histogram_opts!(
279 "meta_grpc_duration_seconds",
280 "gRPC latency of meta services",
281 exponential_buckets(0.0001, 2.0, 20).unwrap() );
283 let grpc_latency =
284 register_histogram_vec_with_registry!(opts, &["path"], registry).unwrap();
285
286 let opts = histogram_opts!(
287 "meta_barrier_duration_seconds",
288 "barrier latency",
289 latency_buckets(600.0, 20)
290 );
291 let barrier_latency =
292 register_guarded_histogram_vec_with_registry!(opts, &["database_id"], registry)
293 .unwrap();
294
295 let opts = histogram_opts!(
296 "meta_barrier_wait_commit_duration_seconds",
297 "barrier_wait_commit_latency",
298 latency_buckets(10.0, 10)
299 );
300 let barrier_wait_commit_latency =
301 register_histogram_with_registry!(opts, registry).unwrap();
302
303 let barrier_interval_by_database = register_gauge_vec_with_registry!(
304 "meta_barrier_interval_by_database",
305 "barrier interval of each database",
306 &["database_id"],
307 registry
308 )
309 .unwrap();
310
311 let all_barrier_nums = register_guarded_int_gauge_vec_with_registry!(
312 "all_barrier_nums",
313 "num of of all_barrier",
314 &["database_id"],
315 registry
316 )
317 .unwrap();
318 let in_flight_barrier_nums = register_guarded_int_gauge_vec_with_registry!(
319 "in_flight_barrier_nums",
320 "num of of in_flight_barrier",
321 &["database_id"],
322 registry
323 )
324 .unwrap();
325 let last_committed_barrier_time = register_guarded_int_gauge_vec_with_registry!(
326 "last_committed_barrier_time",
327 "The timestamp (UNIX epoch seconds) of the last committed barrier's epoch time.",
328 &["database_id"],
329 registry
330 )
331 .unwrap();
332
333 let opts = histogram_opts!(
335 "meta_snapshot_backfill_barrier_duration_seconds",
336 "snapshot backfill barrier latency",
337 latency_buckets(600.0, 20)
338 );
339 let snapshot_backfill_barrier_latency = register_guarded_histogram_vec_with_registry!(
340 opts,
341 &["table_id", "barrier_type"],
342 registry
343 )
344 .unwrap();
345
346 let snapshot_backfill_lag = register_guarded_int_gauge_vec_with_registry!(
347 "meta_snapshot_backfill_upstream_lag",
348 "snapshot backfill upstream_lag",
349 &["table_id"],
350 registry
351 )
352 .unwrap();
353 let snapshot_backfill_inflight_barrier_num = register_guarded_int_gauge_vec_with_registry!(
354 "meta_snapshot_backfill_inflight_barrier_num",
355 "snapshot backfill inflight_barrier_num",
356 &["table_id"],
357 registry
358 )
359 .unwrap();
360
361 let max_committed_epoch = register_int_gauge_with_registry!(
362 "storage_max_committed_epoch",
363 "max committed epoch",
364 registry
365 )
366 .unwrap();
367
368 let min_committed_epoch = register_int_gauge_with_registry!(
369 "storage_min_committed_epoch",
370 "min committed epoch",
371 registry
372 )
373 .unwrap();
374
375 let level_sst_num = register_int_gauge_vec_with_registry!(
376 "storage_level_sst_num",
377 "num of SSTs in each level",
378 &["level_index"],
379 registry
380 )
381 .unwrap();
382
383 let level_compact_cnt = register_int_gauge_vec_with_registry!(
384 "storage_level_compact_cnt",
385 "num of SSTs to be merged to next level in each level",
386 &["level_index"],
387 registry
388 )
389 .unwrap();
390
391 let compact_frequency = register_int_counter_vec_with_registry!(
392 "storage_level_compact_frequency",
393 "The number of compactions from one level to another level that have completed or failed.",
394 &["compactor", "group", "task_type", "result"],
395 registry
396 )
397 .unwrap();
398 let compact_skip_frequency = register_int_counter_vec_with_registry!(
399 "storage_skip_compact_frequency",
400 "The number of compactions from one level to another level that have been skipped.",
401 &["level", "type"],
402 registry
403 )
404 .unwrap();
405
406 let version_size =
407 register_int_gauge_with_registry!("storage_version_size", "version size", registry)
408 .unwrap();
409
410 let current_version_id = register_int_gauge_with_registry!(
411 "storage_current_version_id",
412 "current version id",
413 registry
414 )
415 .unwrap();
416
417 let checkpoint_version_id = register_int_gauge_with_registry!(
418 "storage_checkpoint_version_id",
419 "checkpoint version id",
420 registry
421 )
422 .unwrap();
423
424 let min_pinned_version_id = register_int_gauge_with_registry!(
425 "storage_min_pinned_version_id",
426 "min pinned version id",
427 registry
428 )
429 .unwrap();
430
431 let write_stop_compaction_groups = register_int_gauge_vec_with_registry!(
432 "storage_write_stop_compaction_groups",
433 "compaction groups of write stop state",
434 &["compaction_group_id"],
435 registry
436 )
437 .unwrap();
438
439 let full_gc_trigger_count = register_int_gauge_with_registry!(
440 "storage_full_gc_trigger_count",
441 "the number of attempts to trigger full GC",
442 registry
443 )
444 .unwrap();
445
446 let opts = histogram_opts!(
447 "storage_full_gc_candidate_object_count",
448 "the number of candidate object to delete after scanning object store",
449 exponential_buckets(1.0, 10.0, 6).unwrap()
450 );
451 let full_gc_candidate_object_count =
452 register_histogram_with_registry!(opts, registry).unwrap();
453
454 let opts = histogram_opts!(
455 "storage_full_gc_selected_object_count",
456 "the number of object to delete after filtering by meta node",
457 exponential_buckets(1.0, 10.0, 6).unwrap()
458 );
459 let full_gc_selected_object_count =
460 register_histogram_with_registry!(opts, registry).unwrap();
461
462 let min_safepoint_version_id = register_int_gauge_with_registry!(
463 "storage_min_safepoint_version_id",
464 "min safepoint version id",
465 registry
466 )
467 .unwrap();
468
469 let level_file_size = register_int_gauge_vec_with_registry!(
470 "storage_level_total_file_size",
471 "KBs total file bytes in each level",
472 &["level_index"],
473 registry
474 )
475 .unwrap();
476
477 let version_stats = register_int_gauge_vec_with_registry!(
478 "storage_version_stats",
479 "per table stats in current hummock version",
480 &["table_id", "metric"],
481 registry
482 )
483 .unwrap();
484
485 let materialized_view_stats = register_int_gauge_vec_with_registry!(
486 "storage_materialized_view_stats",
487 "per materialized view stats in current hummock version",
488 &["table_id", "metric"],
489 registry
490 )
491 .unwrap();
492
493 let stale_object_count = register_int_gauge_with_registry!(
494 "storage_stale_object_count",
495 "total number of objects that is no longer referenced by versions.",
496 registry
497 )
498 .unwrap();
499
500 let stale_object_size = register_int_gauge_with_registry!(
501 "storage_stale_object_size",
502 "total size of objects that is no longer referenced by versions.",
503 registry
504 )
505 .unwrap();
506
507 let old_version_object_count = register_int_gauge_with_registry!(
508 "storage_old_version_object_count",
509 "total number of objects that is still referenced by non-current versions",
510 registry
511 )
512 .unwrap();
513
514 let old_version_object_size = register_int_gauge_with_registry!(
515 "storage_old_version_object_size",
516 "total size of objects that is still referenced by non-current versions",
517 registry
518 )
519 .unwrap();
520
521 let current_version_object_count = register_int_gauge_with_registry!(
522 "storage_current_version_object_count",
523 "total number of objects that is referenced by current version",
524 registry
525 )
526 .unwrap();
527
528 let current_version_object_size = register_int_gauge_with_registry!(
529 "storage_current_version_object_size",
530 "total size of objects that is referenced by current version",
531 registry
532 )
533 .unwrap();
534
535 let total_object_count = register_int_gauge_with_registry!(
536 "storage_total_object_count",
537 "Total number of objects that includes dangling objects. Note that the metric is updated right before full GC. So subsequent full GC may reduce the actual value significantly, without updating the metric.",
538 registry
539 ).unwrap();
540
541 let total_object_size = register_int_gauge_with_registry!(
542 "storage_total_object_size",
543 "Total size of objects that includes dangling objects. Note that the metric is updated right before full GC. So subsequent full GC may reduce the actual value significantly, without updating the metric.",
544 registry
545 ).unwrap();
546
547 let table_change_log_object_count = register_int_gauge_vec_with_registry!(
548 "storage_table_change_log_object_count",
549 "per table change log object count",
550 &["table_id"],
551 registry
552 )
553 .unwrap();
554
555 let table_change_log_object_size = register_int_gauge_vec_with_registry!(
556 "storage_table_change_log_object_size",
557 "per table change log object size",
558 &["table_id"],
559 registry
560 )
561 .unwrap();
562
563 let table_change_log_min_epoch = register_int_gauge_vec_with_registry!(
564 "storage_table_change_log_min_epoch",
565 "min epoch currently retained in table change log",
566 &["table_id"],
567 registry
568 )
569 .unwrap();
570
571 let opts = histogram_opts!(
572 "storage_table_change_log_get_latency",
573 "latency of serving table change log requests",
574 exponential_buckets(0.001, 5.0, 7).unwrap()
575 );
576 let table_change_log_get_latency =
577 register_histogram_with_registry!(opts, registry).unwrap();
578
579 let time_travel_object_count = register_int_gauge_with_registry!(
580 "storage_time_travel_object_count",
581 "total number of objects that is referenced by time travel.",
582 registry
583 )
584 .unwrap();
585
586 let delta_log_count = register_int_gauge_with_registry!(
587 "storage_delta_log_count",
588 "total number of hummock version delta log",
589 registry
590 )
591 .unwrap();
592
593 let opts = histogram_opts!(
594 "storage_version_checkpoint_latency",
595 "hummock version checkpoint latency",
596 exponential_buckets(0.1, 1.5, 20).unwrap()
597 );
598 let version_checkpoint_latency = register_histogram_with_registry!(opts, registry).unwrap();
599
600 let opts = histogram_opts!(
601 "hummock_manager_lock_time",
602 "latency for hummock manager to acquire the rwlock",
603 exponential_buckets(0.02, 2.5, 10).unwrap() );
605 let hummock_manager_lock_time =
606 register_histogram_vec_with_registry!(opts, &["lock_name", "lock_type"], registry)
607 .unwrap();
608
609 let opts = histogram_opts!(
610 "meta_hummock_manager_real_process_time",
611 "latency for hummock manager to really process the request",
612 exponential_buckets(0.02, 2.5, 10).unwrap() );
614 let hummock_manager_real_process_time =
615 register_histogram_vec_with_registry!(opts, &["method", "lock_name"], registry)
616 .unwrap();
617
618 let worker_num = register_int_gauge_vec_with_registry!(
619 "worker_num",
620 "number of nodes in the cluster",
621 &["worker_type"],
622 registry,
623 )
624 .unwrap();
625
626 let meta_type = register_int_gauge_vec_with_registry!(
627 "meta_num",
628 "role of meta nodes in the cluster",
629 &["worker_addr", "role"],
630 registry,
631 )
632 .unwrap();
633
634 let compact_pending_bytes = register_int_gauge_vec_with_registry!(
635 "storage_compact_pending_bytes",
636 "bytes of lsm tree needed to reach balance",
637 &["group"],
638 registry
639 )
640 .unwrap();
641
642 let compact_level_compression_ratio = register_gauge_vec_with_registry!(
643 "storage_compact_level_compression_ratio",
644 "compression ratio of each level of the lsm tree",
645 &["group", "level", "algorithm"],
646 registry
647 )
648 .unwrap();
649
650 let level_compact_task_cnt = register_int_gauge_vec_with_registry!(
651 "storage_level_compact_task_cnt",
652 "num of compact_task organized by group and level",
653 &["task"],
654 registry
655 )
656 .unwrap();
657
658 let time_travel_vacuum_metadata_latency = register_histogram_with_registry!(
659 histogram_opts!(
660 "storage_time_travel_vacuum_metadata_latency",
661 "Latency of vacuuming metadata for time travel",
662 exponential_buckets(0.1, 1.5, 20).unwrap()
663 ),
664 registry
665 )
666 .unwrap();
667 let time_travel_write_metadata_latency = register_histogram_with_registry!(
668 histogram_opts!(
669 "storage_time_travel_write_metadata_latency",
670 "Latency of writing metadata for time travel",
671 exponential_buckets(0.1, 1.5, 20).unwrap()
672 ),
673 registry
674 )
675 .unwrap();
676
677 let object_store_metric = Arc::new(GLOBAL_OBJECT_STORE_METRICS.clone());
678
679 let recovery_failure_cnt = register_int_counter_vec_with_registry!(
680 "recovery_failure_cnt",
681 "Number of failed recovery attempts",
682 &["recovery_type"],
683 registry
684 )
685 .unwrap();
686 let opts = histogram_opts!(
687 "recovery_latency",
688 "Latency of the recovery process",
689 exponential_buckets(0.1, 1.5, 20).unwrap() );
691 let recovery_latency =
692 register_histogram_vec_with_registry!(opts, &["recovery_type"], registry).unwrap();
693
694 let auto_schema_change_failure_cnt = register_guarded_int_counter_vec_with_registry!(
695 "auto_schema_change_failure_cnt",
696 "Number of failed auto schema change",
697 &["table_id", "table_name"],
698 registry
699 )
700 .unwrap();
701
702 let auto_schema_change_success_cnt = register_guarded_int_counter_vec_with_registry!(
703 "auto_schema_change_success_cnt",
704 "Number of success auto schema change",
705 &["table_id", "table_name"],
706 registry
707 )
708 .unwrap();
709
710 let opts = histogram_opts!(
711 "auto_schema_change_latency",
712 "Latency of the auto schema change process",
713 exponential_buckets(0.1, 1.5, 20).unwrap() );
715 let auto_schema_change_latency = register_guarded_histogram_vec_with_registry!(
716 opts,
717 &["table_id", "table_name"],
718 registry
719 )
720 .unwrap();
721
722 let source_is_up = register_guarded_int_gauge_vec_with_registry!(
723 "source_status_is_up",
724 "source is up or not",
725 &["source_id", "source_name"],
726 registry
727 )
728 .unwrap();
729 let opts = histogram_opts!(
730 "source_worker_tick_duration_seconds",
731 "Duration of a source worker tick (list_splits + on_tick) in seconds",
732 exponential_buckets(0.1, 1.5, 20).unwrap() );
734 let source_worker_tick_duration_seconds = register_guarded_histogram_vec_with_registry!(
735 opts,
736 &["source_id", "source_name"],
737 registry
738 )
739 .unwrap();
740 let source_enumerator_monitor_error_count =
741 register_guarded_int_counter_vec_with_registry!(
742 "source_enumerator_monitor_error_count",
743 "Number of source enumerator on_tick monitor round-trip failures",
744 &["source_id", "source_name"],
745 registry
746 )
747 .unwrap();
748 let source_enumerator_metrics = Arc::new(SourceEnumeratorMetrics::default());
749
750 let actor_info = register_int_gauge_vec_with_registry!(
751 "actor_info",
752 "Mapping from actor id to (fragment id, compute node)",
753 &["actor_id", "fragment_id", "compute_node"],
754 registry
755 )
756 .unwrap();
757
758 let table_info = register_int_gauge_vec_with_registry!(
759 "table_info",
760 "Mapping from table id to (actor id, table name)",
761 &[
762 "materialized_view_id",
763 "table_id",
764 "fragment_id",
765 "table_name",
766 "table_type",
767 "compaction_group_id"
768 ],
769 registry
770 )
771 .unwrap();
772
773 let sink_info = register_int_gauge_vec_with_registry!(
774 "sink_info",
775 "Mapping from actor id to (actor id, sink name)",
776 &["actor_id", "sink_id", "sink_name",],
777 registry
778 )
779 .unwrap();
780
781 let relation_info = register_int_gauge_vec_with_registry!(
782 "relation_info",
783 "Information of the database relation (table/source/sink/materialized view/index/internal)",
784 &["id", "database", "schema", "name", "resource_group", "type"],
785 registry
786 )
787 .unwrap();
788
789 let streaming_table_change_log_retention_seconds = register_int_gauge_vec_with_registry!(
790 "streaming_table_change_log_retention_seconds",
791 "Max subscription retention configured for the table change log in seconds",
792 &["table_id"],
793 registry
794 )
795 .unwrap();
796
797 let database_info = register_int_gauge_vec_with_registry!(
798 "database_info",
799 "Mapping from database id to database name",
800 &["database_id", "database_name"],
801 registry
802 )
803 .unwrap();
804
805 let backfill_fragment_progress = register_int_gauge_vec_with_registry!(
806 "backfill_fragment_progress",
807 "Backfill progress per fragment",
808 &[
809 "job_id",
810 "fragment_id",
811 "backfill_state_table_id",
812 "backfill_target_relation_id",
813 "backfill_target_relation_name",
814 "backfill_target_relation_type",
815 "backfill_type",
816 "backfill_epoch",
817 "upstream_type",
818 "backfill_progress",
819 ],
820 registry
821 )
822 .unwrap();
823
824 let l0_compact_level_count = register_histogram_vec_with_registry!(
825 "storage_l0_compact_level_count",
826 "level_count of l0 compact task",
827 &["group", "type"],
828 registry
829 )
830 .unwrap();
831
832 let system_param_info = register_int_gauge_vec_with_registry!(
834 "system_param_info",
835 "Information of system parameters",
836 &["name", "value"],
837 registry
838 )
839 .unwrap();
840
841 let opts = histogram_opts!(
842 "storage_compact_task_size",
843 "Total size of compact that have been issued to state store",
844 exponential_buckets(1048576.0, 2.0, 16).unwrap()
845 );
846
847 let compact_task_size =
848 register_histogram_vec_with_registry!(opts, &["group", "type"], registry).unwrap();
849
850 let compact_task_file_count = register_histogram_vec_with_registry!(
851 "storage_compact_task_file_count",
852 "file count of compact task",
853 &["group", "type"],
854 registry
855 )
856 .unwrap();
857 let opts = histogram_opts!(
858 "storage_compact_task_batch_count",
859 "count of compact task batch",
860 exponential_buckets(1.0, 2.0, 8).unwrap()
861 );
862 let compact_task_batch_count =
863 register_histogram_vec_with_registry!(opts, &["type"], registry).unwrap();
864
865 let table_write_throughput = register_int_counter_vec_with_registry!(
866 "storage_commit_write_throughput",
867 "The number of compactions from one level to another level that have been skipped.",
868 &["table_id"],
869 registry
870 )
871 .unwrap();
872
873 let split_compaction_group_count = register_int_counter_vec_with_registry!(
874 "storage_split_compaction_group_count",
875 "Count of trigger split compaction group",
876 &["group"],
877 registry
878 )
879 .unwrap();
880
881 let state_table_count = register_int_gauge_vec_with_registry!(
882 "storage_state_table_count",
883 "Count of stable table per compaction group",
884 &["group"],
885 registry
886 )
887 .unwrap();
888
889 let branched_sst_count = register_int_gauge_vec_with_registry!(
890 "storage_branched_sst_count",
891 "Count of branched sst per compaction group",
892 &["group"],
893 registry
894 )
895 .unwrap();
896
897 let opts = histogram_opts!(
898 "storage_compaction_event_consumed_latency",
899 "The latency(ms) of each event being consumed",
900 exponential_buckets(1.0, 1.5, 30).unwrap() );
902 let compaction_event_consumed_latency =
903 register_histogram_with_registry!(opts, registry).unwrap();
904
905 let opts = histogram_opts!(
906 "storage_compaction_event_loop_iteration_latency",
907 "The latency(ms) of each iteration of the compaction event loop",
908 exponential_buckets(1.0, 1.5, 30).unwrap() );
910 let compaction_event_loop_iteration_latency =
911 register_histogram_with_registry!(opts, registry).unwrap();
912
913 let merge_compaction_group_count = register_int_counter_vec_with_registry!(
914 "storage_merge_compaction_group_count",
915 "Count of trigger merge compaction group",
916 &["group"],
917 registry
918 )
919 .unwrap();
920
921 let opts = histogram_opts!(
922 "storage_time_travel_version_replay_latency",
923 "The latency(ms) of replaying a hummock version for time travel",
924 exponential_buckets(0.01, 10.0, 6).unwrap()
925 );
926 let time_travel_version_replay_latency =
927 register_histogram_with_registry!(opts, registry).unwrap();
928
929 let compaction_group_count = register_int_gauge_with_registry!(
930 "storage_compaction_group_count",
931 "The number of compaction groups",
932 registry,
933 )
934 .unwrap();
935
936 let compaction_group_size = register_int_gauge_vec_with_registry!(
937 "storage_compaction_group_size",
938 "The size of compaction group",
939 &["group"],
940 registry
941 )
942 .unwrap();
943
944 let compaction_group_file_count = register_int_gauge_vec_with_registry!(
945 "storage_compaction_group_file_count",
946 "The file count of compaction group",
947 &["group"],
948 registry
949 )
950 .unwrap();
951
952 let compaction_group_throughput = register_int_gauge_vec_with_registry!(
953 "storage_compaction_group_throughput",
954 "The throughput of compaction group",
955 &["group"],
956 registry
957 )
958 .unwrap();
959
960 let opts = histogram_opts!(
961 "storage_compact_task_trivial_move_sst_count",
962 "sst count of compact trivial-move task",
963 exponential_buckets(1.0, 2.0, 8).unwrap()
964 );
965 let compact_task_trivial_move_sst_count =
966 register_histogram_vec_with_registry!(opts, &["group"], registry).unwrap();
967
968 let refresh_job_duration = register_guarded_uint_gauge_vec_with_registry!(
969 "meta_refresh_job_duration",
970 "The duration of refresh job",
971 &["table_id", "status"],
972 registry
973 )
974 .unwrap();
975 let refresh_job_finish_cnt = register_guarded_int_counter_vec_with_registry!(
976 "meta_refresh_job_finish_cnt",
977 "The number of finished refresh jobs",
978 &["table_id", "status"],
979 registry
980 )
981 .unwrap();
982 let refresh_cron_job_trigger_cnt = register_guarded_int_counter_vec_with_registry!(
983 "meta_refresh_cron_job_trigger_cnt",
984 "The number of cron refresh jobs triggered",
985 &["table_id"],
986 registry
987 )
988 .unwrap();
989 let refresh_cron_job_miss_cnt = register_guarded_int_counter_vec_with_registry!(
990 "meta_refresh_cron_job_miss_cnt",
991 "The number of cron refresh jobs missed",
992 &["table_id"],
993 registry
994 )
995 .unwrap();
996
997 Self {
998 grpc_latency,
999 barrier_latency,
1000 barrier_wait_commit_latency,
1001 all_barrier_nums,
1002 in_flight_barrier_nums,
1003 last_committed_barrier_time,
1004 barrier_interval_by_database,
1005 snapshot_backfill_barrier_latency,
1006 snapshot_backfill_lag,
1007 snapshot_backfill_inflight_barrier_num,
1008 recovery_failure_cnt,
1009 recovery_latency,
1010
1011 max_committed_epoch,
1012 min_committed_epoch,
1013 level_sst_num,
1014 level_compact_cnt,
1015 compact_frequency,
1016 compact_skip_frequency,
1017 level_file_size,
1018 version_size,
1019 version_stats,
1020 materialized_view_stats,
1021 stale_object_count,
1022 stale_object_size,
1023 old_version_object_count,
1024 old_version_object_size,
1025 time_travel_object_count,
1026 current_version_object_count,
1027 current_version_object_size,
1028 total_object_count,
1029 total_object_size,
1030 table_change_log_object_count,
1031 table_change_log_object_size,
1032 table_change_log_min_epoch,
1033 table_change_log_get_latency,
1034 delta_log_count,
1035 version_checkpoint_latency,
1036 current_version_id,
1037 checkpoint_version_id,
1038 min_pinned_version_id,
1039 min_safepoint_version_id,
1040 write_stop_compaction_groups,
1041 full_gc_trigger_count,
1042 full_gc_candidate_object_count,
1043 full_gc_selected_object_count,
1044 hummock_manager_lock_time,
1045 hummock_manager_real_process_time,
1046 time_after_last_observation: Arc::new(AtomicU64::new(0)),
1047 worker_num,
1048 meta_type,
1049 compact_pending_bytes,
1050 compact_level_compression_ratio,
1051 level_compact_task_cnt,
1052 object_store_metric,
1053 source_is_up,
1054 source_worker_tick_duration_seconds,
1055 source_enumerator_monitor_error_count,
1056 source_enumerator_metrics,
1057 actor_info,
1058 table_info,
1059 sink_info,
1060 relation_info,
1061 database_info,
1062 backfill_fragment_progress,
1063 streaming_table_change_log_retention_seconds,
1064 system_param_info,
1065 l0_compact_level_count,
1066 compact_task_size,
1067 compact_task_file_count,
1068 compact_task_batch_count,
1069 compact_task_trivial_move_sst_count,
1070 table_write_throughput,
1071 split_compaction_group_count,
1072 state_table_count,
1073 branched_sst_count,
1074 compaction_event_consumed_latency,
1075 compaction_event_loop_iteration_latency,
1076 auto_schema_change_failure_cnt,
1077 auto_schema_change_success_cnt,
1078 auto_schema_change_latency,
1079 merge_compaction_group_count,
1080 time_travel_version_replay_latency,
1081 compaction_group_count,
1082 compaction_group_size,
1083 compaction_group_file_count,
1084 compaction_group_throughput,
1085 refresh_job_duration,
1086 refresh_job_finish_cnt,
1087 refresh_cron_job_trigger_cnt,
1088 refresh_cron_job_miss_cnt,
1089 time_travel_vacuum_metadata_latency,
1090 time_travel_write_metadata_latency,
1091 }
1092 }
1093
1094 #[cfg(test)]
1095 pub fn for_test(registry: &Registry) -> Self {
1096 Self::new(registry)
1097 }
1098}
1099impl Default for MetaMetrics {
1100 fn default() -> Self {
1101 GLOBAL_META_METRICS.clone()
1102 }
1103}
1104
1105pub async fn refresh_system_param_info_metrics(
1107 system_params_controller: &SystemParamsControllerRef,
1108 meta_metrics: Arc<MetaMetrics>,
1109) {
1110 let params_info = system_params_controller.get_params().await.get_all();
1111
1112 meta_metrics.system_param_info.reset();
1113 for info in params_info {
1114 meta_metrics
1115 .system_param_info
1116 .with_label_values(&[info.name, &info.value])
1117 .set(1);
1118 }
1119}
1120
1121pub fn start_worker_info_monitor(
1122 metadata_manager: MetadataManager,
1123 election_client: ElectionClientRef,
1124 interval: Duration,
1125 meta_metrics: Arc<MetaMetrics>,
1126) -> (JoinHandle<()>, Sender<()>) {
1127 let (shutdown_tx, mut shutdown_rx) = tokio::sync::oneshot::channel();
1128 let join_handle = tokio::spawn(async move {
1129 let mut monitor_interval = tokio::time::interval(interval);
1130 monitor_interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
1131 loop {
1132 tokio::select! {
1133 _ = monitor_interval.tick() => {},
1135 _ = &mut shutdown_rx => {
1137 tracing::info!("Worker number monitor is stopped");
1138 return;
1139 }
1140 }
1141
1142 let node_map = match metadata_manager.count_worker_node().await {
1143 Ok(node_map) => node_map,
1144 Err(err) => {
1145 tracing::warn!(error = %err.as_report(), "fail to count worker node");
1146 continue;
1147 }
1148 };
1149
1150 meta_metrics.worker_num.reset();
1152 meta_metrics.meta_type.reset();
1153
1154 for (worker_type, worker_num) in node_map {
1155 meta_metrics
1156 .worker_num
1157 .with_label_values(&[(worker_type.as_str_name())])
1158 .set(worker_num as i64);
1159 }
1160 if let Ok(meta_members) = election_client.get_members().await {
1161 meta_metrics
1162 .worker_num
1163 .with_label_values(&[WorkerType::Meta.as_str_name()])
1164 .set(meta_members.len() as i64);
1165 meta_members.into_iter().for_each(|m| {
1166 let role = if m.is_leader { "leader" } else { "follower" };
1167 meta_metrics
1168 .meta_type
1169 .with_label_values(&[m.id.as_str(), role])
1170 .set(1);
1171 });
1172 }
1173 }
1174 });
1175
1176 (join_handle, shutdown_tx)
1177}
1178
1179pub async fn refresh_fragment_info_metrics(
1180 catalog_controller: &CatalogControllerRef,
1181 cluster_controller: &ClusterControllerRef,
1182 hummock_manager: &HummockManagerRef,
1183 meta_metrics: Arc<MetaMetrics>,
1184) {
1185 let worker_nodes = match cluster_controller
1186 .list_workers(Some(WorkerType::ComputeNode.into()), None)
1187 .await
1188 {
1189 Ok(worker_nodes) => worker_nodes,
1190 Err(err) => {
1191 tracing::warn!(error=%err.as_report(), "fail to list worker node");
1192 return;
1193 }
1194 };
1195 let actor_locations = match catalog_controller.list_actor_locations() {
1196 Ok(actor_locations) => actor_locations,
1197 Err(err) => {
1198 tracing::warn!(error=%err.as_report(), "fail to get actor locations");
1199 return;
1200 }
1201 };
1202 let sink_actor_mapping = match catalog_controller.list_sink_actor_mapping().await {
1203 Ok(sink_actor_mapping) => sink_actor_mapping,
1204 Err(err) => {
1205 tracing::warn!(error=%err.as_report(), "fail to get sink actor mapping");
1206 return;
1207 }
1208 };
1209 let fragment_state_tables = match catalog_controller.list_fragment_state_tables().await {
1210 Ok(fragment_state_tables) => fragment_state_tables,
1211 Err(err) => {
1212 tracing::warn!(error=%err.as_report(), "fail to get fragment state tables");
1213 return;
1214 }
1215 };
1216 let table_name_and_type_mapping = match catalog_controller.get_table_name_type_mapping().await {
1217 Ok(mapping) => mapping,
1218 Err(err) => {
1219 tracing::warn!(error=%err.as_report(), "fail to get table name mapping");
1220 return;
1221 }
1222 };
1223
1224 let worker_addr_mapping: HashMap<WorkerId, String> = worker_nodes
1225 .into_iter()
1226 .map(|worker_node| {
1227 let addr = match worker_node.host {
1228 Some(host) => format!("{}:{}", host.host, host.port),
1229 None => "".to_owned(),
1230 };
1231 (worker_node.id, addr)
1232 })
1233 .collect();
1234 let table_compaction_group_id_mapping = hummock_manager
1235 .get_table_compaction_group_id_mapping()
1236 .await;
1237
1238 meta_metrics.actor_info.reset();
1241 meta_metrics.table_info.reset();
1242 meta_metrics.sink_info.reset();
1243 for actor_location in actor_locations {
1244 let actor_id_str = actor_location.actor_id.to_string();
1245 let fragment_id_str = actor_location.fragment_id.to_string();
1246 if let Some(address) = worker_addr_mapping.get(&actor_location.worker_id) {
1249 meta_metrics
1250 .actor_info
1251 .with_label_values(&[&actor_id_str, &fragment_id_str, address])
1252 .set(1);
1253 }
1254 }
1255 for (sink_id, (sink_name, actor_ids)) in sink_actor_mapping {
1256 let sink_id_str = sink_id.to_string();
1257 for actor_id in actor_ids {
1258 let actor_id_str = actor_id.to_string();
1259 meta_metrics
1260 .sink_info
1261 .with_label_values(&[&actor_id_str, &sink_id_str, &sink_name])
1262 .set(1);
1263 }
1264 }
1265 for PartialFragmentStateTables {
1266 fragment_id,
1267 job_id,
1268 state_table_ids,
1269 } in fragment_state_tables
1270 {
1271 let fragment_id_str = fragment_id.to_string();
1272 let job_id_str = job_id.to_string();
1273 for table_id in state_table_ids.into_inner() {
1274 let table_id_str = table_id.to_string();
1275 let (table_name, table_type) = table_name_and_type_mapping
1276 .get(&table_id)
1277 .cloned()
1278 .unwrap_or_else(|| ("unknown".to_owned(), "unknown".to_owned()));
1279 let compaction_group_id = table_compaction_group_id_mapping
1280 .get(&table_id)
1281 .map(|cg_id| cg_id.to_string())
1282 .unwrap_or_else(|| "unknown".to_owned());
1283 meta_metrics
1284 .table_info
1285 .with_label_values(&[
1286 &job_id_str,
1287 &table_id_str,
1288 &fragment_id_str,
1289 &table_name,
1290 &table_type,
1291 &compaction_group_id,
1292 ])
1293 .set(1);
1294 }
1295 }
1296}
1297
1298pub async fn refresh_relation_info_metrics(
1299 catalog_controller: &CatalogControllerRef,
1300 meta_metrics: Arc<MetaMetrics>,
1301) {
1302 let table_objects = match catalog_controller.list_table_objects().await {
1303 Ok(table_objects) => table_objects,
1304 Err(err) => {
1305 tracing::warn!(error=%err.as_report(), "fail to get table objects");
1306 return;
1307 }
1308 };
1309
1310 let source_objects = match catalog_controller.list_source_objects().await {
1311 Ok(source_objects) => source_objects,
1312 Err(err) => {
1313 tracing::warn!(error=%err.as_report(), "fail to get source objects");
1314 return;
1315 }
1316 };
1317
1318 let sink_objects = match catalog_controller.list_sink_objects().await {
1319 Ok(sink_objects) => sink_objects,
1320 Err(err) => {
1321 tracing::warn!(error=%err.as_report(), "fail to get sink objects");
1322 return;
1323 }
1324 };
1325 let subscriptions = match catalog_controller.list_subscriptions().await {
1326 Ok(subscriptions) => subscriptions,
1327 Err(err) => {
1328 tracing::warn!(error=%err.as_report(), "fail to get subscription objects");
1329 return;
1330 }
1331 };
1332
1333 meta_metrics.relation_info.reset();
1334 meta_metrics
1335 .streaming_table_change_log_retention_seconds
1336 .reset();
1337
1338 for (id, db, schema, name, resource_group, table_type) in table_objects {
1339 let relation_type = match table_type {
1340 TableType::Table => "table",
1341 TableType::MaterializedView => "materialized_view",
1342 TableType::Index | TableType::VectorIndex => "index",
1343 TableType::Internal => "internal",
1344 };
1345 meta_metrics
1346 .relation_info
1347 .with_label_values(&[
1348 &id.to_string(),
1349 &db,
1350 &schema,
1351 &name,
1352 &resource_group,
1353 &relation_type.to_owned(),
1354 ])
1355 .set(1);
1356 }
1357
1358 for (id, db, schema, name, resource_group) in source_objects {
1359 meta_metrics
1360 .relation_info
1361 .with_label_values(&[
1362 &id.to_string(),
1363 &db,
1364 &schema,
1365 &name,
1366 &resource_group,
1367 &"source".to_owned(),
1368 ])
1369 .set(1);
1370 }
1371
1372 for (id, db, schema, name, resource_group) in sink_objects {
1373 meta_metrics
1374 .relation_info
1375 .with_label_values(&[
1376 &id.to_string(),
1377 &db,
1378 &schema,
1379 &name,
1380 &resource_group,
1381 &"sink".to_owned(),
1382 ])
1383 .set(1);
1384 }
1385
1386 let mut max_retention_by_table = HashMap::new();
1387 for subscription in subscriptions {
1388 max_retention_by_table
1389 .entry(subscription.dependent_table_id)
1390 .and_modify(|retention: &mut u64| {
1391 *retention = (*retention).max(subscription.retention_seconds);
1392 })
1393 .or_insert(subscription.retention_seconds);
1394 }
1395 for (table_id, retention_seconds) in max_retention_by_table {
1396 meta_metrics
1397 .streaming_table_change_log_retention_seconds
1398 .with_label_values(&[&table_id.to_string()])
1399 .set(retention_seconds as _);
1400 }
1401}
1402
1403pub async fn refresh_database_info_metrics(
1404 catalog_controller: &CatalogControllerRef,
1405 meta_metrics: Arc<MetaMetrics>,
1406) {
1407 let databases = match catalog_controller.list_databases().await {
1408 Ok(databases) => databases,
1409 Err(err) => {
1410 tracing::warn!(error=%err.as_report(), "fail to get databases");
1411 return;
1412 }
1413 };
1414
1415 meta_metrics.database_info.reset();
1416
1417 for db in databases {
1418 meta_metrics
1419 .database_info
1420 .with_label_values(&[&db.id.to_string(), &db.name])
1421 .set(1);
1422 }
1423}
1424
1425fn extract_backfill_fragment_info(
1426 distribution: &FragmentDistribution,
1427) -> Option<BackfillFragmentInfo> {
1428 let backfill_type =
1429 if distribution.fragment_type_mask & FragmentTypeFlag::SourceScan as u32 != 0 {
1430 "SOURCE"
1431 } else if distribution.fragment_type_mask
1432 & (FragmentTypeFlag::SnapshotBackfillStreamScan as u32
1433 | FragmentTypeFlag::CrossDbSnapshotBackfillStreamScan as u32)
1434 != 0
1435 {
1436 "SNAPSHOT_BACKFILL"
1437 } else if distribution.fragment_type_mask & FragmentTypeFlag::StreamScan as u32 != 0 {
1438 "ARRANGEMENT_OR_NO_SHUFFLE"
1439 } else {
1440 return None;
1441 };
1442
1443 let stream_node = distribution.node.as_ref()?;
1444 let mut info = None;
1445 match backfill_type {
1446 "SOURCE" => {
1447 visit_stream_node_source_backfill(stream_node, |node| {
1448 info = Some(BackfillFragmentInfo {
1449 job_id: distribution.table_id.as_raw_id(),
1450 fragment_id: distribution.fragment_id.as_raw_id(),
1451 backfill_state_table_id: node
1452 .state_table
1453 .as_ref()
1454 .map(|table| table.id.as_raw_id())
1455 .unwrap_or_default(),
1456 backfill_target_relation_id: node.upstream_source_id.as_raw_id(),
1457 backfill_type,
1458 backfill_epoch: 0,
1459 });
1460 });
1461 }
1462 "SNAPSHOT_BACKFILL" | "ARRANGEMENT_OR_NO_SHUFFLE" => {
1463 visit_stream_node_stream_scan(stream_node, |node| {
1464 info = Some(BackfillFragmentInfo {
1465 job_id: distribution.table_id.as_raw_id(),
1466 fragment_id: distribution.fragment_id.as_raw_id(),
1467 backfill_state_table_id: node
1468 .state_table
1469 .as_ref()
1470 .map(|table| table.id.as_raw_id())
1471 .unwrap_or_default(),
1472 backfill_target_relation_id: node.table_id.as_raw_id(),
1473 backfill_type,
1474 backfill_epoch: node.snapshot_backfill_epoch.unwrap_or_default(),
1475 });
1476 });
1477 }
1478 _ => {}
1479 }
1480
1481 info
1482}
1483
1484pub async fn refresh_backfill_progress_metrics(
1485 catalog_controller: &CatalogControllerRef,
1486 hummock_manager: &HummockManagerRef,
1487 barrier_manager: &BarrierManagerRef,
1488 meta_metrics: Arc<MetaMetrics>,
1489) {
1490 let fragment_descs = match catalog_controller.list_fragment_descs_with_node(true).await {
1491 Ok(fragment_descs) => fragment_descs,
1492 Err(err) => {
1493 tracing::warn!(error=%err.as_report(), "fail to list creating fragment descs");
1494 return;
1495 }
1496 };
1497
1498 let backfill_infos: HashMap<(u32, u32), BackfillFragmentInfo> = fragment_descs
1499 .iter()
1500 .filter_map(|(distribution, _)| extract_backfill_fragment_info(distribution))
1501 .map(|info| ((info.job_id, info.fragment_id), info))
1502 .collect();
1503
1504 let fragment_progresses = match barrier_manager.get_fragment_backfill_progress().await {
1505 Ok(progress) => progress,
1506 Err(err) => {
1507 tracing::warn!(error=%err.as_report(), "fail to get fragment backfill progress");
1508 return;
1509 }
1510 };
1511
1512 let progress_by_fragment: HashMap<(u32, u32), _> = fragment_progresses
1513 .into_iter()
1514 .map(|progress| {
1515 (
1516 (
1517 progress.job_id.as_raw_id(),
1518 progress.fragment_id.as_raw_id(),
1519 ),
1520 progress,
1521 )
1522 })
1523 .collect();
1524
1525 let version_stats = hummock_manager.get_version_stats().await;
1526
1527 let relation_ids: HashSet<_> = backfill_infos
1528 .values()
1529 .map(|info| ObjectId::new(info.backfill_target_relation_id))
1530 .collect();
1531 let relation_objects = match catalog_controller
1532 .list_relation_objects_by_ids(&relation_ids)
1533 .await
1534 {
1535 Ok(relation_objects) => relation_objects,
1536 Err(err) => {
1537 tracing::warn!(error=%err.as_report(), "fail to get relation objects");
1538 return;
1539 }
1540 };
1541
1542 let mut relation_info = HashMap::new();
1543 for (id, db, schema, name, rel_type) in relation_objects {
1544 relation_info.insert(id.as_raw_id(), (db, schema, name, rel_type));
1545 }
1546
1547 meta_metrics.backfill_fragment_progress.reset();
1548
1549 for info in backfill_infos.values() {
1550 let progress = progress_by_fragment.get(&(info.job_id, info.fragment_id));
1551 let (db, schema, name, rel_type) = relation_info
1552 .get(&info.backfill_target_relation_id)
1553 .cloned()
1554 .unwrap_or_else(|| {
1555 (
1556 "unknown".to_owned(),
1557 "unknown".to_owned(),
1558 "unknown".to_owned(),
1559 "unknown".to_owned(),
1560 )
1561 });
1562
1563 let job_id_str = info.job_id.to_string();
1564 let fragment_id_str = info.fragment_id.to_string();
1565 let backfill_state_table_id_str = info.backfill_state_table_id.to_string();
1566 let backfill_target_relation_id_str = info.backfill_target_relation_id.to_string();
1567 let backfill_target_relation_name_str = format!("{db}.{schema}.{name}");
1568 let backfill_target_relation_type_str = rel_type;
1569 let backfill_type_str = info.backfill_type.to_owned();
1570 let backfill_epoch_str = info.backfill_epoch.to_string();
1571 let total_key_count = version_stats
1572 .table_stats
1573 .get(&TableId::new(info.backfill_target_relation_id))
1574 .map(|stats| stats.total_key_count as u64);
1575
1576 let progress_label = match (info.backfill_type, progress) {
1577 ("SOURCE", Some(progress)) => format!("{} consumed rows", progress.consumed_rows),
1578 ("SOURCE", None) => "0 consumed rows".to_owned(),
1579 (_, Some(progress)) if progress.done => {
1580 let total = total_key_count.unwrap_or(0);
1581 format!("100.0000% ({}/{})", total, total)
1582 }
1583 (_, Some(progress)) => {
1584 let total = total_key_count.unwrap_or(0);
1585 if total == 0 {
1586 "100.0000% (0/0)".to_owned()
1587 } else {
1588 let raw = (progress.consumed_rows as f64) / (total as f64) * 100.0;
1589 format!(
1590 "{:.4}% ({}/{})",
1591 raw.min(100.0),
1592 progress.consumed_rows,
1593 total
1594 )
1595 }
1596 }
1597 (_, None) => "0.0000% (0/0)".to_owned(),
1598 };
1599 let upstream_type_str = progress
1600 .map(|progress| progress.upstream_type.to_string())
1601 .unwrap_or_else(|| "Unknown".to_owned());
1602
1603 meta_metrics
1604 .backfill_fragment_progress
1605 .with_label_values(&[
1606 &job_id_str,
1607 &fragment_id_str,
1608 &backfill_state_table_id_str,
1609 &backfill_target_relation_id_str,
1610 &backfill_target_relation_name_str,
1611 &backfill_target_relation_type_str,
1612 &backfill_type_str,
1613 &backfill_epoch_str,
1614 &upstream_type_str,
1615 &progress_label,
1616 ])
1617 .set(1);
1618 }
1619}
1620
1621pub fn start_info_monitor(
1622 metadata_manager: MetadataManager,
1623 hummock_manager: HummockManagerRef,
1624 barrier_manager: BarrierManagerRef,
1625 system_params_controller: SystemParamsControllerRef,
1626 meta_metrics: Arc<MetaMetrics>,
1627) -> (JoinHandle<()>, Sender<()>) {
1628 const COLLECT_INTERVAL_SECONDS: u64 = 60;
1629
1630 let (shutdown_tx, mut shutdown_rx) = tokio::sync::oneshot::channel();
1631 let join_handle = tokio::spawn(async move {
1632 let mut monitor_interval =
1633 tokio::time::interval(Duration::from_secs(COLLECT_INTERVAL_SECONDS));
1634 monitor_interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
1635 loop {
1636 tokio::select! {
1637 _ = monitor_interval.tick() => {},
1639 _ = &mut shutdown_rx => {
1641 tracing::info!("Meta info monitor is stopped");
1642 return;
1643 }
1644 }
1645
1646 refresh_fragment_info_metrics(
1648 &metadata_manager.catalog_controller,
1649 &metadata_manager.cluster_controller,
1650 &hummock_manager,
1651 meta_metrics.clone(),
1652 )
1653 .await;
1654
1655 refresh_relation_info_metrics(
1656 &metadata_manager.catalog_controller,
1657 meta_metrics.clone(),
1658 )
1659 .await;
1660
1661 refresh_database_info_metrics(
1662 &metadata_manager.catalog_controller,
1663 meta_metrics.clone(),
1664 )
1665 .await;
1666
1667 refresh_backfill_progress_metrics(
1668 &metadata_manager.catalog_controller,
1669 &hummock_manager,
1670 &barrier_manager,
1671 meta_metrics.clone(),
1672 )
1673 .await;
1674
1675 refresh_system_param_info_metrics(&system_params_controller, meta_metrics.clone())
1677 .await;
1678 }
1679 });
1680
1681 (join_handle, shutdown_tx)
1682}