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