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 barrier_send_latency: LabelGuardedHistogramVec,
92 pub all_barrier_nums: LabelGuardedIntGaugeVec,
95 pub in_flight_barrier_nums: LabelGuardedIntGaugeVec,
97 pub last_committed_barrier_time: LabelGuardedIntGaugeVec,
99 pub barrier_interval_by_database: GaugeVec,
101
102 pub snapshot_backfill_barrier_latency: LabelGuardedHistogramVec, pub snapshot_backfill_lag: LabelGuardedIntGaugeVec, pub snapshot_backfill_inflight_barrier_num: LabelGuardedIntGaugeVec, pub recovery_failure_cnt: IntCounterVec,
112 pub recovery_latency: HistogramVec,
113
114 pub max_committed_epoch: IntGauge,
117 pub min_committed_epoch: IntGauge,
119 pub level_sst_num: IntGaugeVec,
121 pub level_compact_cnt: IntGaugeVec,
123 pub compact_frequency: IntCounterVec,
125 pub level_file_size: IntGaugeVec,
127 pub version_size: IntGauge,
129 pub current_version_id: IntGauge,
131 pub checkpoint_version_id: IntGauge,
133 pub min_pinned_version_id: IntGauge,
135 pub min_safepoint_version_id: IntGauge,
137 pub write_stop_compaction_groups: IntGaugeVec,
139 pub full_gc_trigger_count: IntGauge,
141 pub full_gc_candidate_object_count: Histogram,
143 pub full_gc_selected_object_count: Histogram,
145 pub version_stats: IntGaugeVec,
147 pub materialized_view_stats: IntGaugeVec,
149 pub stale_object_count: IntGauge,
151 pub stale_object_size: IntGauge,
153 pub old_version_object_count: IntGauge,
155 pub old_version_object_size: IntGauge,
157 pub time_travel_object_count: IntGauge,
159 pub current_version_object_count: IntGauge,
161 pub current_version_object_size: IntGauge,
163 pub total_object_count: IntGauge,
165 pub total_object_size: IntGauge,
167 pub table_change_log_object_count: IntGaugeVec,
169 pub table_change_log_object_size: IntGaugeVec,
171 pub table_change_log_min_epoch: IntGaugeVec,
173 pub table_change_log_get_latency: Histogram,
175 pub delta_log_count: IntGauge,
177 pub version_checkpoint_latency: Histogram,
179 pub hummock_manager_lock_time: HistogramVec,
181 pub hummock_manager_real_process_time: HistogramVec,
183 pub compact_skip_frequency: IntCounterVec,
185 pub compact_pending_bytes: IntGaugeVec,
187 pub compact_level_compression_ratio: GenericGaugeVec<AtomicF64>,
189 pub level_compact_task_cnt: IntGaugeVec,
191 pub time_after_last_observation: Arc<AtomicU64>,
192 pub l0_compact_level_count: HistogramVec,
193 pub compact_task_size: HistogramVec,
194 pub compact_task_file_count: HistogramVec,
195 pub compact_task_batch_count: HistogramVec,
196 pub split_compaction_group_count: IntCounterVec,
197 pub state_table_count: IntGaugeVec,
198 pub branched_sst_count: IntGaugeVec,
199 pub compact_task_trivial_move_sst_count: HistogramVec,
200
201 pub compaction_event_consumed_latency: Histogram,
202 pub compaction_event_loop_iteration_latency: Histogram,
203 pub time_travel_vacuum_metadata_latency: Histogram,
204 pub time_travel_write_metadata_latency: Histogram,
205
206 pub object_store_metric: Arc<ObjectStoreMetrics>,
209
210 pub source_is_up: LabelGuardedIntGaugeVec,
213 pub source_worker_tick_duration_seconds: LabelGuardedHistogramVec,
215 pub source_enumerator_monitor_error_count: LabelGuardedIntCounterVec,
217 pub source_enumerator_metrics: Arc<SourceEnumeratorMetrics>,
218
219 pub actor_info: IntGaugeVec,
222 pub table_info: IntGaugeVec,
224 pub sink_info: IntGaugeVec,
226 pub relation_info: IntGaugeVec,
228 pub database_info: IntGaugeVec,
230 pub backfill_fragment_progress: IntGaugeVec,
232 pub streaming_table_change_log_retention_seconds: IntGaugeVec,
234
235 pub system_param_info: IntGaugeVec,
239
240 pub table_write_throughput: IntCounterVec,
242
243 pub merge_compaction_group_count: IntCounterVec,
245
246 pub auto_schema_change_failure_cnt: LabelGuardedIntCounterVec,
248 pub auto_schema_change_success_cnt: LabelGuardedIntCounterVec,
249 pub auto_schema_change_latency: LabelGuardedHistogramVec,
250
251 pub time_travel_version_replay_latency: Histogram,
252
253 pub compaction_group_count: IntGauge,
254 pub compaction_group_size: IntGaugeVec,
255 pub compaction_group_file_count: IntGaugeVec,
256 pub compaction_group_throughput: IntGaugeVec,
257
258 pub refresh_job_duration: LabelGuardedUintGaugeVec,
260 pub refresh_job_finish_cnt: LabelGuardedIntCounterVec,
261 pub refresh_cron_job_trigger_cnt: LabelGuardedIntCounterVec,
262 pub refresh_cron_job_miss_cnt: LabelGuardedIntCounterVec,
263}
264
265pub static GLOBAL_META_METRICS: LazyLock<MetaMetrics> =
266 LazyLock::new(|| MetaMetrics::new(&GLOBAL_METRICS_REGISTRY));
267
268impl MetaMetrics {
269 fn new(registry: &Registry) -> Self {
270 let opts = histogram_opts!(
271 "meta_grpc_duration_seconds",
272 "gRPC latency of meta services",
273 exponential_buckets(0.0001, 2.0, 20).unwrap() );
275 let grpc_latency =
276 register_histogram_vec_with_registry!(opts, &["path"], registry).unwrap();
277
278 let opts = histogram_opts!(
279 "meta_barrier_duration_seconds",
280 "barrier latency",
281 exponential_buckets(0.1, 1.5, 20).unwrap() );
283 let barrier_latency =
284 register_guarded_histogram_vec_with_registry!(opts, &["database_id"], registry)
285 .unwrap();
286
287 let opts = histogram_opts!(
288 "meta_barrier_wait_commit_duration_seconds",
289 "barrier_wait_commit_latency",
290 exponential_buckets(0.1, 1.5, 20).unwrap() );
292 let barrier_wait_commit_latency =
293 register_histogram_with_registry!(opts, registry).unwrap();
294
295 let opts = histogram_opts!(
296 "meta_barrier_send_duration_seconds",
297 "barrier send latency",
298 exponential_buckets(0.1, 1.5, 19).unwrap() );
300 let barrier_send_latency =
301 register_guarded_histogram_vec_with_registry!(opts, &["database_id"], registry)
302 .unwrap();
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 exponential_buckets(0.1, 1.5, 20).unwrap() );
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 barrier_send_latency,
1002 all_barrier_nums,
1003 in_flight_barrier_nums,
1004 last_committed_barrier_time,
1005 barrier_interval_by_database,
1006 snapshot_backfill_barrier_latency,
1007 snapshot_backfill_lag,
1008 snapshot_backfill_inflight_barrier_num,
1009 recovery_failure_cnt,
1010 recovery_latency,
1011
1012 max_committed_epoch,
1013 min_committed_epoch,
1014 level_sst_num,
1015 level_compact_cnt,
1016 compact_frequency,
1017 compact_skip_frequency,
1018 level_file_size,
1019 version_size,
1020 version_stats,
1021 materialized_view_stats,
1022 stale_object_count,
1023 stale_object_size,
1024 old_version_object_count,
1025 old_version_object_size,
1026 time_travel_object_count,
1027 current_version_object_count,
1028 current_version_object_size,
1029 total_object_count,
1030 total_object_size,
1031 table_change_log_object_count,
1032 table_change_log_object_size,
1033 table_change_log_min_epoch,
1034 table_change_log_get_latency,
1035 delta_log_count,
1036 version_checkpoint_latency,
1037 current_version_id,
1038 checkpoint_version_id,
1039 min_pinned_version_id,
1040 min_safepoint_version_id,
1041 write_stop_compaction_groups,
1042 full_gc_trigger_count,
1043 full_gc_candidate_object_count,
1044 full_gc_selected_object_count,
1045 hummock_manager_lock_time,
1046 hummock_manager_real_process_time,
1047 time_after_last_observation: Arc::new(AtomicU64::new(0)),
1048 worker_num,
1049 meta_type,
1050 compact_pending_bytes,
1051 compact_level_compression_ratio,
1052 level_compact_task_cnt,
1053 object_store_metric,
1054 source_is_up,
1055 source_worker_tick_duration_seconds,
1056 source_enumerator_monitor_error_count,
1057 source_enumerator_metrics,
1058 actor_info,
1059 table_info,
1060 sink_info,
1061 relation_info,
1062 database_info,
1063 backfill_fragment_progress,
1064 streaming_table_change_log_retention_seconds,
1065 system_param_info,
1066 l0_compact_level_count,
1067 compact_task_size,
1068 compact_task_file_count,
1069 compact_task_batch_count,
1070 compact_task_trivial_move_sst_count,
1071 table_write_throughput,
1072 split_compaction_group_count,
1073 state_table_count,
1074 branched_sst_count,
1075 compaction_event_consumed_latency,
1076 compaction_event_loop_iteration_latency,
1077 auto_schema_change_failure_cnt,
1078 auto_schema_change_success_cnt,
1079 auto_schema_change_latency,
1080 merge_compaction_group_count,
1081 time_travel_version_replay_latency,
1082 compaction_group_count,
1083 compaction_group_size,
1084 compaction_group_file_count,
1085 compaction_group_throughput,
1086 refresh_job_duration,
1087 refresh_job_finish_cnt,
1088 refresh_cron_job_trigger_cnt,
1089 refresh_cron_job_miss_cnt,
1090 time_travel_vacuum_metadata_latency,
1091 time_travel_write_metadata_latency,
1092 }
1093 }
1094
1095 #[cfg(test)]
1096 pub fn for_test(registry: &Registry) -> Self {
1097 Self::new(registry)
1098 }
1099}
1100impl Default for MetaMetrics {
1101 fn default() -> Self {
1102 GLOBAL_META_METRICS.clone()
1103 }
1104}
1105
1106pub async fn refresh_system_param_info_metrics(
1108 system_params_controller: &SystemParamsControllerRef,
1109 meta_metrics: Arc<MetaMetrics>,
1110) {
1111 let params_info = system_params_controller.get_params().await.get_all();
1112
1113 meta_metrics.system_param_info.reset();
1114 for info in params_info {
1115 meta_metrics
1116 .system_param_info
1117 .with_label_values(&[info.name, &info.value])
1118 .set(1);
1119 }
1120}
1121
1122pub fn start_worker_info_monitor(
1123 metadata_manager: MetadataManager,
1124 election_client: ElectionClientRef,
1125 interval: Duration,
1126 meta_metrics: Arc<MetaMetrics>,
1127) -> (JoinHandle<()>, Sender<()>) {
1128 let (shutdown_tx, mut shutdown_rx) = tokio::sync::oneshot::channel();
1129 let join_handle = tokio::spawn(async move {
1130 let mut monitor_interval = tokio::time::interval(interval);
1131 monitor_interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
1132 loop {
1133 tokio::select! {
1134 _ = monitor_interval.tick() => {},
1136 _ = &mut shutdown_rx => {
1138 tracing::info!("Worker number monitor is stopped");
1139 return;
1140 }
1141 }
1142
1143 let node_map = match metadata_manager.count_worker_node().await {
1144 Ok(node_map) => node_map,
1145 Err(err) => {
1146 tracing::warn!(error = %err.as_report(), "fail to count worker node");
1147 continue;
1148 }
1149 };
1150
1151 meta_metrics.worker_num.reset();
1153 meta_metrics.meta_type.reset();
1154
1155 for (worker_type, worker_num) in node_map {
1156 meta_metrics
1157 .worker_num
1158 .with_label_values(&[(worker_type.as_str_name())])
1159 .set(worker_num as i64);
1160 }
1161 if let Ok(meta_members) = election_client.get_members().await {
1162 meta_metrics
1163 .worker_num
1164 .with_label_values(&[WorkerType::Meta.as_str_name()])
1165 .set(meta_members.len() as i64);
1166 meta_members.into_iter().for_each(|m| {
1167 let role = if m.is_leader { "leader" } else { "follower" };
1168 meta_metrics
1169 .meta_type
1170 .with_label_values(&[m.id.as_str(), role])
1171 .set(1);
1172 });
1173 }
1174 }
1175 });
1176
1177 (join_handle, shutdown_tx)
1178}
1179
1180pub async fn refresh_fragment_info_metrics(
1181 catalog_controller: &CatalogControllerRef,
1182 cluster_controller: &ClusterControllerRef,
1183 hummock_manager: &HummockManagerRef,
1184 meta_metrics: Arc<MetaMetrics>,
1185) {
1186 let worker_nodes = match cluster_controller
1187 .list_workers(Some(WorkerType::ComputeNode.into()), None)
1188 .await
1189 {
1190 Ok(worker_nodes) => worker_nodes,
1191 Err(err) => {
1192 tracing::warn!(error=%err.as_report(), "fail to list worker node");
1193 return;
1194 }
1195 };
1196 let actor_locations = match catalog_controller.list_actor_locations() {
1197 Ok(actor_locations) => actor_locations,
1198 Err(err) => {
1199 tracing::warn!(error=%err.as_report(), "fail to get actor locations");
1200 return;
1201 }
1202 };
1203 let sink_actor_mapping = match catalog_controller.list_sink_actor_mapping().await {
1204 Ok(sink_actor_mapping) => sink_actor_mapping,
1205 Err(err) => {
1206 tracing::warn!(error=%err.as_report(), "fail to get sink actor mapping");
1207 return;
1208 }
1209 };
1210 let fragment_state_tables = match catalog_controller.list_fragment_state_tables().await {
1211 Ok(fragment_state_tables) => fragment_state_tables,
1212 Err(err) => {
1213 tracing::warn!(error=%err.as_report(), "fail to get fragment state tables");
1214 return;
1215 }
1216 };
1217 let table_name_and_type_mapping = match catalog_controller.get_table_name_type_mapping().await {
1218 Ok(mapping) => mapping,
1219 Err(err) => {
1220 tracing::warn!(error=%err.as_report(), "fail to get table name mapping");
1221 return;
1222 }
1223 };
1224
1225 let worker_addr_mapping: HashMap<WorkerId, String> = worker_nodes
1226 .into_iter()
1227 .map(|worker_node| {
1228 let addr = match worker_node.host {
1229 Some(host) => format!("{}:{}", host.host, host.port),
1230 None => "".to_owned(),
1231 };
1232 (worker_node.id, addr)
1233 })
1234 .collect();
1235 let table_compaction_group_id_mapping = hummock_manager
1236 .get_table_compaction_group_id_mapping()
1237 .await;
1238
1239 meta_metrics.actor_info.reset();
1242 meta_metrics.table_info.reset();
1243 meta_metrics.sink_info.reset();
1244 for actor_location in actor_locations {
1245 let actor_id_str = actor_location.actor_id.to_string();
1246 let fragment_id_str = actor_location.fragment_id.to_string();
1247 if let Some(address) = worker_addr_mapping.get(&actor_location.worker_id) {
1250 meta_metrics
1251 .actor_info
1252 .with_label_values(&[&actor_id_str, &fragment_id_str, address])
1253 .set(1);
1254 }
1255 }
1256 for (sink_id, (sink_name, actor_ids)) in sink_actor_mapping {
1257 let sink_id_str = sink_id.to_string();
1258 for actor_id in actor_ids {
1259 let actor_id_str = actor_id.to_string();
1260 meta_metrics
1261 .sink_info
1262 .with_label_values(&[&actor_id_str, &sink_id_str, &sink_name])
1263 .set(1);
1264 }
1265 }
1266 for PartialFragmentStateTables {
1267 fragment_id,
1268 job_id,
1269 state_table_ids,
1270 } in fragment_state_tables
1271 {
1272 let fragment_id_str = fragment_id.to_string();
1273 let job_id_str = job_id.to_string();
1274 for table_id in state_table_ids.into_inner() {
1275 let table_id_str = table_id.to_string();
1276 let (table_name, table_type) = table_name_and_type_mapping
1277 .get(&table_id)
1278 .cloned()
1279 .unwrap_or_else(|| ("unknown".to_owned(), "unknown".to_owned()));
1280 let compaction_group_id = table_compaction_group_id_mapping
1281 .get(&table_id)
1282 .map(|cg_id| cg_id.to_string())
1283 .unwrap_or_else(|| "unknown".to_owned());
1284 meta_metrics
1285 .table_info
1286 .with_label_values(&[
1287 &job_id_str,
1288 &table_id_str,
1289 &fragment_id_str,
1290 &table_name,
1291 &table_type,
1292 &compaction_group_id,
1293 ])
1294 .set(1);
1295 }
1296 }
1297}
1298
1299pub async fn refresh_relation_info_metrics(
1300 catalog_controller: &CatalogControllerRef,
1301 meta_metrics: Arc<MetaMetrics>,
1302) {
1303 let table_objects = match catalog_controller.list_table_objects().await {
1304 Ok(table_objects) => table_objects,
1305 Err(err) => {
1306 tracing::warn!(error=%err.as_report(), "fail to get table objects");
1307 return;
1308 }
1309 };
1310
1311 let source_objects = match catalog_controller.list_source_objects().await {
1312 Ok(source_objects) => source_objects,
1313 Err(err) => {
1314 tracing::warn!(error=%err.as_report(), "fail to get source objects");
1315 return;
1316 }
1317 };
1318
1319 let sink_objects = match catalog_controller.list_sink_objects().await {
1320 Ok(sink_objects) => sink_objects,
1321 Err(err) => {
1322 tracing::warn!(error=%err.as_report(), "fail to get sink objects");
1323 return;
1324 }
1325 };
1326 let subscriptions = match catalog_controller.list_subscriptions().await {
1327 Ok(subscriptions) => subscriptions,
1328 Err(err) => {
1329 tracing::warn!(error=%err.as_report(), "fail to get subscription objects");
1330 return;
1331 }
1332 };
1333
1334 meta_metrics.relation_info.reset();
1335 meta_metrics
1336 .streaming_table_change_log_retention_seconds
1337 .reset();
1338
1339 for (id, db, schema, name, resource_group, table_type) in table_objects {
1340 let relation_type = match table_type {
1341 TableType::Table => "table",
1342 TableType::MaterializedView => "materialized_view",
1343 TableType::Index | TableType::VectorIndex => "index",
1344 TableType::Internal => "internal",
1345 };
1346 meta_metrics
1347 .relation_info
1348 .with_label_values(&[
1349 &id.to_string(),
1350 &db,
1351 &schema,
1352 &name,
1353 &resource_group,
1354 &relation_type.to_owned(),
1355 ])
1356 .set(1);
1357 }
1358
1359 for (id, db, schema, name, resource_group) in source_objects {
1360 meta_metrics
1361 .relation_info
1362 .with_label_values(&[
1363 &id.to_string(),
1364 &db,
1365 &schema,
1366 &name,
1367 &resource_group,
1368 &"source".to_owned(),
1369 ])
1370 .set(1);
1371 }
1372
1373 for (id, db, schema, name, resource_group) in sink_objects {
1374 meta_metrics
1375 .relation_info
1376 .with_label_values(&[
1377 &id.to_string(),
1378 &db,
1379 &schema,
1380 &name,
1381 &resource_group,
1382 &"sink".to_owned(),
1383 ])
1384 .set(1);
1385 }
1386
1387 let mut max_retention_by_table = HashMap::new();
1388 for subscription in subscriptions {
1389 max_retention_by_table
1390 .entry(subscription.dependent_table_id)
1391 .and_modify(|retention: &mut u64| {
1392 *retention = (*retention).max(subscription.retention_seconds);
1393 })
1394 .or_insert(subscription.retention_seconds);
1395 }
1396 for (table_id, retention_seconds) in max_retention_by_table {
1397 meta_metrics
1398 .streaming_table_change_log_retention_seconds
1399 .with_label_values(&[&table_id.to_string()])
1400 .set(retention_seconds as _);
1401 }
1402}
1403
1404pub async fn refresh_database_info_metrics(
1405 catalog_controller: &CatalogControllerRef,
1406 meta_metrics: Arc<MetaMetrics>,
1407) {
1408 let databases = match catalog_controller.list_databases().await {
1409 Ok(databases) => databases,
1410 Err(err) => {
1411 tracing::warn!(error=%err.as_report(), "fail to get databases");
1412 return;
1413 }
1414 };
1415
1416 meta_metrics.database_info.reset();
1417
1418 for db in databases {
1419 meta_metrics
1420 .database_info
1421 .with_label_values(&[&db.id.to_string(), &db.name])
1422 .set(1);
1423 }
1424}
1425
1426fn extract_backfill_fragment_info(
1427 distribution: &FragmentDistribution,
1428) -> Option<BackfillFragmentInfo> {
1429 let backfill_type =
1430 if distribution.fragment_type_mask & FragmentTypeFlag::SourceScan as u32 != 0 {
1431 "SOURCE"
1432 } else if distribution.fragment_type_mask
1433 & (FragmentTypeFlag::SnapshotBackfillStreamScan as u32
1434 | FragmentTypeFlag::CrossDbSnapshotBackfillStreamScan as u32)
1435 != 0
1436 {
1437 "SNAPSHOT_BACKFILL"
1438 } else if distribution.fragment_type_mask & FragmentTypeFlag::StreamScan as u32 != 0 {
1439 "ARRANGEMENT_OR_NO_SHUFFLE"
1440 } else {
1441 return None;
1442 };
1443
1444 let stream_node = distribution.node.as_ref()?;
1445 let mut info = None;
1446 match backfill_type {
1447 "SOURCE" => {
1448 visit_stream_node_source_backfill(stream_node, |node| {
1449 info = Some(BackfillFragmentInfo {
1450 job_id: distribution.table_id.as_raw_id(),
1451 fragment_id: distribution.fragment_id.as_raw_id(),
1452 backfill_state_table_id: node
1453 .state_table
1454 .as_ref()
1455 .map(|table| table.id.as_raw_id())
1456 .unwrap_or_default(),
1457 backfill_target_relation_id: node.upstream_source_id.as_raw_id(),
1458 backfill_type,
1459 backfill_epoch: 0,
1460 });
1461 });
1462 }
1463 "SNAPSHOT_BACKFILL" | "ARRANGEMENT_OR_NO_SHUFFLE" => {
1464 visit_stream_node_stream_scan(stream_node, |node| {
1465 info = Some(BackfillFragmentInfo {
1466 job_id: distribution.table_id.as_raw_id(),
1467 fragment_id: distribution.fragment_id.as_raw_id(),
1468 backfill_state_table_id: node
1469 .state_table
1470 .as_ref()
1471 .map(|table| table.id.as_raw_id())
1472 .unwrap_or_default(),
1473 backfill_target_relation_id: node.table_id.as_raw_id(),
1474 backfill_type,
1475 backfill_epoch: node.snapshot_backfill_epoch.unwrap_or_default(),
1476 });
1477 });
1478 }
1479 _ => {}
1480 }
1481
1482 info
1483}
1484
1485pub async fn refresh_backfill_progress_metrics(
1486 catalog_controller: &CatalogControllerRef,
1487 hummock_manager: &HummockManagerRef,
1488 barrier_manager: &BarrierManagerRef,
1489 meta_metrics: Arc<MetaMetrics>,
1490) {
1491 let fragment_descs = match catalog_controller.list_fragment_descs_with_node(true).await {
1492 Ok(fragment_descs) => fragment_descs,
1493 Err(err) => {
1494 tracing::warn!(error=%err.as_report(), "fail to list creating fragment descs");
1495 return;
1496 }
1497 };
1498
1499 let backfill_infos: HashMap<(u32, u32), BackfillFragmentInfo> = fragment_descs
1500 .iter()
1501 .filter_map(|(distribution, _)| extract_backfill_fragment_info(distribution))
1502 .map(|info| ((info.job_id, info.fragment_id), info))
1503 .collect();
1504
1505 let fragment_progresses = match barrier_manager.get_fragment_backfill_progress().await {
1506 Ok(progress) => progress,
1507 Err(err) => {
1508 tracing::warn!(error=%err.as_report(), "fail to get fragment backfill progress");
1509 return;
1510 }
1511 };
1512
1513 let progress_by_fragment: HashMap<(u32, u32), _> = fragment_progresses
1514 .into_iter()
1515 .map(|progress| {
1516 (
1517 (
1518 progress.job_id.as_raw_id(),
1519 progress.fragment_id.as_raw_id(),
1520 ),
1521 progress,
1522 )
1523 })
1524 .collect();
1525
1526 let version_stats = hummock_manager.get_version_stats().await;
1527
1528 let relation_ids: HashSet<_> = backfill_infos
1529 .values()
1530 .map(|info| ObjectId::new(info.backfill_target_relation_id))
1531 .collect();
1532 let relation_objects = match catalog_controller
1533 .list_relation_objects_by_ids(&relation_ids)
1534 .await
1535 {
1536 Ok(relation_objects) => relation_objects,
1537 Err(err) => {
1538 tracing::warn!(error=%err.as_report(), "fail to get relation objects");
1539 return;
1540 }
1541 };
1542
1543 let mut relation_info = HashMap::new();
1544 for (id, db, schema, name, rel_type) in relation_objects {
1545 relation_info.insert(id.as_raw_id(), (db, schema, name, rel_type));
1546 }
1547
1548 meta_metrics.backfill_fragment_progress.reset();
1549
1550 for info in backfill_infos.values() {
1551 let progress = progress_by_fragment.get(&(info.job_id, info.fragment_id));
1552 let (db, schema, name, rel_type) = relation_info
1553 .get(&info.backfill_target_relation_id)
1554 .cloned()
1555 .unwrap_or_else(|| {
1556 (
1557 "unknown".to_owned(),
1558 "unknown".to_owned(),
1559 "unknown".to_owned(),
1560 "unknown".to_owned(),
1561 )
1562 });
1563
1564 let job_id_str = info.job_id.to_string();
1565 let fragment_id_str = info.fragment_id.to_string();
1566 let backfill_state_table_id_str = info.backfill_state_table_id.to_string();
1567 let backfill_target_relation_id_str = info.backfill_target_relation_id.to_string();
1568 let backfill_target_relation_name_str = format!("{db}.{schema}.{name}");
1569 let backfill_target_relation_type_str = rel_type;
1570 let backfill_type_str = info.backfill_type.to_owned();
1571 let backfill_epoch_str = info.backfill_epoch.to_string();
1572 let total_key_count = version_stats
1573 .table_stats
1574 .get(&TableId::new(info.backfill_target_relation_id))
1575 .map(|stats| stats.total_key_count as u64);
1576
1577 let progress_label = match (info.backfill_type, progress) {
1578 ("SOURCE", Some(progress)) => format!("{} consumed rows", progress.consumed_rows),
1579 ("SOURCE", None) => "0 consumed rows".to_owned(),
1580 (_, Some(progress)) if progress.done => {
1581 let total = total_key_count.unwrap_or(0);
1582 format!("100.0000% ({}/{})", total, total)
1583 }
1584 (_, Some(progress)) => {
1585 let total = total_key_count.unwrap_or(0);
1586 if total == 0 {
1587 "100.0000% (0/0)".to_owned()
1588 } else {
1589 let raw = (progress.consumed_rows as f64) / (total as f64) * 100.0;
1590 format!(
1591 "{:.4}% ({}/{})",
1592 raw.min(100.0),
1593 progress.consumed_rows,
1594 total
1595 )
1596 }
1597 }
1598 (_, None) => "0.0000% (0/0)".to_owned(),
1599 };
1600 let upstream_type_str = progress
1601 .map(|progress| progress.upstream_type.to_string())
1602 .unwrap_or_else(|| "Unknown".to_owned());
1603
1604 meta_metrics
1605 .backfill_fragment_progress
1606 .with_label_values(&[
1607 &job_id_str,
1608 &fragment_id_str,
1609 &backfill_state_table_id_str,
1610 &backfill_target_relation_id_str,
1611 &backfill_target_relation_name_str,
1612 &backfill_target_relation_type_str,
1613 &backfill_type_str,
1614 &backfill_epoch_str,
1615 &upstream_type_str,
1616 &progress_label,
1617 ])
1618 .set(1);
1619 }
1620}
1621
1622pub fn start_info_monitor(
1623 metadata_manager: MetadataManager,
1624 hummock_manager: HummockManagerRef,
1625 barrier_manager: BarrierManagerRef,
1626 system_params_controller: SystemParamsControllerRef,
1627 meta_metrics: Arc<MetaMetrics>,
1628) -> (JoinHandle<()>, Sender<()>) {
1629 const COLLECT_INTERVAL_SECONDS: u64 = 60;
1630
1631 let (shutdown_tx, mut shutdown_rx) = tokio::sync::oneshot::channel();
1632 let join_handle = tokio::spawn(async move {
1633 let mut monitor_interval =
1634 tokio::time::interval(Duration::from_secs(COLLECT_INTERVAL_SECONDS));
1635 monitor_interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
1636 loop {
1637 tokio::select! {
1638 _ = monitor_interval.tick() => {},
1640 _ = &mut shutdown_rx => {
1642 tracing::info!("Meta info monitor is stopped");
1643 return;
1644 }
1645 }
1646
1647 refresh_fragment_info_metrics(
1649 &metadata_manager.catalog_controller,
1650 &metadata_manager.cluster_controller,
1651 &hummock_manager,
1652 meta_metrics.clone(),
1653 )
1654 .await;
1655
1656 refresh_relation_info_metrics(
1657 &metadata_manager.catalog_controller,
1658 meta_metrics.clone(),
1659 )
1660 .await;
1661
1662 refresh_database_info_metrics(
1663 &metadata_manager.catalog_controller,
1664 meta_metrics.clone(),
1665 )
1666 .await;
1667
1668 refresh_backfill_progress_metrics(
1669 &metadata_manager.catalog_controller,
1670 &hummock_manager,
1671 &barrier_manager,
1672 meta_metrics.clone(),
1673 )
1674 .await;
1675
1676 refresh_system_param_info_metrics(&system_params_controller, meta_metrics.clone())
1678 .await;
1679 }
1680 });
1681
1682 (join_handle, shutdown_tx)
1683}