mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-20 03:22:18 +00:00
feat: integrate global metrics system into AHM scanner
- Add global metrics system to common crate for cross-module usage - Integrate global metrics collection into AHM scanner operations - Update ECStore to use common metrics system instead of local implementation - Add chrono dependency to AHM crate for timestamp handling - Re-export IlmAction from common metrics in ECStore lifecycle module - Update scanner methods to use global metrics for cycle, disk, and volume scans - Maintain backward compatibility with local metrics collector - Fix clippy warnings and ensure proper code formatting This change enables unified metrics collection across the entire RustFS system, allowing better monitoring and observability of scanner operations. Signed-off-by: junxiang Mu <1948535941@qq.com>
This commit is contained in:
@@ -22,6 +22,7 @@ use async_channel::{Receiver as A_Receiver, Sender as A_Sender, bounded};
|
||||
use futures::Future;
|
||||
use http::HeaderMap;
|
||||
use lazy_static::lazy_static;
|
||||
use rustfs_common::metrics::{IlmAction, Metrics};
|
||||
use s3s::Body;
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::any::Any;
|
||||
@@ -41,7 +42,7 @@ use xxhash_rust::xxh64;
|
||||
//use rustfs_notify::{BucketNotificationConfig, Event, EventName, LogLevel, NotificationError, init_logger};
|
||||
//use rustfs_notify::{initialize, notification_system};
|
||||
use super::bucket_lifecycle_audit::{LcAuditEvent, LcEventSrc};
|
||||
use super::lifecycle::{self, ExpirationOptions, IlmAction, Lifecycle, TransitionOptions};
|
||||
use super::lifecycle::{self, ExpirationOptions, Lifecycle, TransitionOptions};
|
||||
use super::tier_last_day_stats::{DailyAllTierStats, LastDayTierStats};
|
||||
use super::tier_sweeper::{Jentry, delete_object_from_remote_tier};
|
||||
use crate::bucket::{metadata_sys::get_lifecycle_config, versioning_sys::BucketVersioningSys};
|
||||
@@ -54,7 +55,6 @@ use crate::global::GLOBAL_LocalNodeName;
|
||||
use crate::global::{GLOBAL_LifecycleSys, GLOBAL_TierConfigMgr, get_global_deployment_id};
|
||||
use crate::heal::{
|
||||
data_scanner::{apply_expiry_on_non_transitioned_objects, apply_expiry_on_transitioned_object},
|
||||
data_scanner_metric::ScannerMetrics,
|
||||
data_usage_cache::TierStats,
|
||||
};
|
||||
use crate::store::ECStore;
|
||||
@@ -631,7 +631,7 @@ pub async fn enqueue_transition_immediate(oi: &ObjectInfo, src: LcEventSrc) {
|
||||
if !lc.is_none() {
|
||||
let event = lc.expect("err").eval(&oi.to_lifecycle_opts()).await;
|
||||
match event.action {
|
||||
lifecycle::IlmAction::TransitionAction | lifecycle::IlmAction::TransitionVersionAction => {
|
||||
IlmAction::TransitionAction | IlmAction::TransitionVersionAction => {
|
||||
if oi.delete_marker || oi.is_dir {
|
||||
return;
|
||||
}
|
||||
@@ -728,7 +728,7 @@ pub fn gen_transition_objname(bucket: &str) -> Result<String, Error> {
|
||||
}
|
||||
|
||||
pub async fn transition_object(api: Arc<ECStore>, oi: &ObjectInfo, lae: LcAuditEvent) -> Result<(), Error> {
|
||||
let time_ilm = ScannerMetrics::time_ilm(lae.event.action);
|
||||
let time_ilm = Metrics::time_ilm(lae.event.action);
|
||||
|
||||
let opts = ObjectOptions {
|
||||
transition: TransitionOptions {
|
||||
|
||||
@@ -43,49 +43,7 @@ const _ERR_XML_NOT_WELL_FORMED: &str =
|
||||
const ERR_LIFECYCLE_BUCKET_LOCKED: &str =
|
||||
"ExpiredObjectAllVersions element and DelMarkerExpiration action cannot be used on an retention bucket";
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum IlmAction {
|
||||
NoneAction = 0,
|
||||
DeleteAction,
|
||||
DeleteVersionAction,
|
||||
TransitionAction,
|
||||
TransitionVersionAction,
|
||||
DeleteRestoredAction,
|
||||
DeleteRestoredVersionAction,
|
||||
DeleteAllVersionsAction,
|
||||
DelMarkerDeleteAllVersionsAction,
|
||||
ActionCount,
|
||||
}
|
||||
|
||||
impl IlmAction {
|
||||
pub fn delete_restored(&self) -> bool {
|
||||
*self == Self::DeleteRestoredAction || *self == Self::DeleteRestoredVersionAction
|
||||
}
|
||||
|
||||
pub fn delete_versioned(&self) -> bool {
|
||||
*self == Self::DeleteVersionAction || *self == Self::DeleteRestoredVersionAction
|
||||
}
|
||||
|
||||
pub fn delete_all(&self) -> bool {
|
||||
*self == Self::DeleteAllVersionsAction || *self == Self::DelMarkerDeleteAllVersionsAction
|
||||
}
|
||||
|
||||
pub fn delete(&self) -> bool {
|
||||
if self.delete_restored() {
|
||||
return true;
|
||||
}
|
||||
*self == Self::DeleteVersionAction
|
||||
|| *self == Self::DeleteAction
|
||||
|| *self == Self::DeleteAllVersionsAction
|
||||
|| *self == Self::DelMarkerDeleteAllVersionsAction
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for IlmAction {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
pub use rustfs_common::metrics::IlmAction;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait RuleValidate {
|
||||
|
||||
@@ -39,13 +39,13 @@ use crate::global::{GLOBAL_IsErasureSD, GLOBAL_RootDiskThreshold};
|
||||
use crate::heal::data_scanner::{
|
||||
ScannerItem, ShouldSleepFn, SizeSummary, lc_has_active_rules, rep_has_active_rules, scan_data_folder,
|
||||
};
|
||||
use crate::heal::data_scanner_metric::{ScannerMetric, ScannerMetrics};
|
||||
use crate::heal::data_usage_cache::{DataUsageCache, DataUsageEntry};
|
||||
use crate::heal::error::{ERR_IGNORE_FILE_CONTRIB, ERR_SKIP_FILE};
|
||||
use crate::heal::heal_commands::{HealScanMode, HealingTracker};
|
||||
use crate::heal::heal_ops::HEALING_TRACKER_FILENAME;
|
||||
use crate::new_object_layer_fn;
|
||||
use crate::store_api::{ObjectInfo, StorageAPI};
|
||||
use rustfs_common::metrics::{Metric, Metrics};
|
||||
use rustfs_utils::path::{
|
||||
GLOBAL_DIR_SUFFIX, GLOBAL_DIR_SUFFIX_WITH_SLASH, SLASH_SEPARATOR, clean, decode_dir_object, encode_dir_object, has_suffix,
|
||||
path_join, path_join_buf,
|
||||
@@ -2323,9 +2323,9 @@ impl DiskAPI for LocalDisk {
|
||||
if !item.path.ends_with(&format!("{SLASH_SEPARATOR}{STORAGE_FORMAT_FILE}")) {
|
||||
return Err(Error::other(ERR_SKIP_FILE).into());
|
||||
}
|
||||
let stop_fn = ScannerMetrics::log(ScannerMetric::ScanObject);
|
||||
let stop_fn = Metrics::log(Metric::ScanObject);
|
||||
let mut res = HashMap::new();
|
||||
let done_sz = ScannerMetrics::time_size(ScannerMetric::ReadMetadata);
|
||||
let done_sz = Metrics::time_size(Metric::ReadMetadata);
|
||||
let buf = match disk.read_metadata(item.path.clone()).await {
|
||||
Ok(buf) => buf,
|
||||
Err(err) => {
|
||||
@@ -2351,7 +2351,7 @@ impl DiskAPI for LocalDisk {
|
||||
}
|
||||
};
|
||||
let mut size_s = SizeSummary::default();
|
||||
let done = ScannerMetrics::time(ScannerMetric::ApplyAll);
|
||||
let done = Metrics::time(Metric::ApplyAll);
|
||||
let obj_infos = match item.apply_versions_actions(&fivs.versions).await {
|
||||
Ok(obj_infos) => obj_infos,
|
||||
Err(err) => {
|
||||
@@ -2369,7 +2369,7 @@ impl DiskAPI for LocalDisk {
|
||||
|
||||
let mut obj_deleted = false;
|
||||
for info in obj_infos.iter() {
|
||||
let done = ScannerMetrics::time(ScannerMetric::ApplyVersion);
|
||||
let done = Metrics::time(Metric::ApplyVersion);
|
||||
let sz: i64;
|
||||
(obj_deleted, sz) = item.apply_actions(info, &mut size_s).await;
|
||||
done();
|
||||
@@ -2405,7 +2405,7 @@ impl DiskAPI for LocalDisk {
|
||||
&item.object_path().to_string_lossy(),
|
||||
versioned,
|
||||
);
|
||||
let done = ScannerMetrics::time(ScannerMetric::TierObjSweep);
|
||||
let done = Metrics::time(Metric::TierObjSweep);
|
||||
done();
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ use std::{
|
||||
use time::{self, OffsetDateTime};
|
||||
|
||||
use super::{
|
||||
data_scanner_metric::{ScannerMetric, ScannerMetrics, globalScannerMetrics},
|
||||
data_usage::{DATA_USAGE_BLOOM_NAME_PATH, DataUsageInfo, store_data_usage_in_backend},
|
||||
data_usage_cache::{DataUsageCache, DataUsageEntry, DataUsageHash},
|
||||
heal_commands::{HEAL_DEEP_SCAN, HEAL_NORMAL_SCAN, HealScanMode},
|
||||
@@ -39,6 +38,7 @@ use crate::bucket::{
|
||||
utils::is_meta_bucketname,
|
||||
};
|
||||
use crate::cmd::bucket_replication::queue_replication_heal;
|
||||
use crate::disk::local::LocalDisk;
|
||||
use crate::event::name::EventName;
|
||||
use crate::{
|
||||
bucket::{
|
||||
@@ -57,7 +57,7 @@ use crate::{
|
||||
bucket::{versioning::VersioningApi, versioning_sys::BucketVersioningSys},
|
||||
cmd::bucket_replication::ReplicationStatusType,
|
||||
disk,
|
||||
heal::data_usage::DATA_USAGE_ROOT,
|
||||
// heal::data_usage::DATA_USAGE_ROOT,
|
||||
};
|
||||
use crate::{
|
||||
cache_value::metacache_set::{ListPathRawOptions, list_path_raw},
|
||||
@@ -66,7 +66,7 @@ use crate::{
|
||||
heal::Config,
|
||||
},
|
||||
disk::{DiskInfoOptions, DiskStore},
|
||||
global::{GLOBAL_BackgroundHealState, GLOBAL_IsErasure, GLOBAL_IsErasureSD},
|
||||
global::{GLOBAL_BackgroundHealState, GLOBAL_IsErasureSD},
|
||||
heal::{
|
||||
data_usage::BACKGROUND_HEAL_INFO_PATH,
|
||||
data_usage_cache::{DataUsageHashMap, hash_path},
|
||||
@@ -83,7 +83,6 @@ use crate::{
|
||||
disk::error::DiskError,
|
||||
error::{Error, Result},
|
||||
};
|
||||
use crate::{disk::local::LocalDisk, heal::data_scanner_metric::current_path_updater};
|
||||
use chrono::{DateTime, Utc};
|
||||
use lazy_static::lazy_static;
|
||||
use rand::Rng;
|
||||
@@ -300,14 +299,14 @@ async fn run_data_scanner_cycle() {
|
||||
};
|
||||
|
||||
// Start metrics collection for this cycle
|
||||
let stop_fn = ScannerMetrics::log(ScannerMetric::ScanCycle);
|
||||
// let stop_fn = ScannerMetrics::log(ScannerMetric::ScanCycle);
|
||||
|
||||
// Update cycle information
|
||||
cycle_info.current = cycle_info.next;
|
||||
cycle_info.started = Utc::now();
|
||||
|
||||
// Update global scanner metrics
|
||||
globalScannerMetrics.set_cycle(Some(cycle_info.clone())).await;
|
||||
// globalScannerMetrics.set_cycle(Some(cycle_info.clone())).await;
|
||||
|
||||
// Read background healing information and determine scan mode
|
||||
let bg_heal_info = read_background_heal_info(store.clone()).await;
|
||||
@@ -357,7 +356,7 @@ async fn run_data_scanner_cycle() {
|
||||
}
|
||||
|
||||
// Update global metrics with completion info
|
||||
globalScannerMetrics.set_cycle(Some(cycle_info.clone())).await;
|
||||
// globalScannerMetrics.set_cycle(Some(cycle_info.clone())).await;
|
||||
|
||||
// Persist updated cycle information
|
||||
// ignore error, continue.
|
||||
@@ -379,7 +378,7 @@ async fn run_data_scanner_cycle() {
|
||||
}
|
||||
|
||||
// Complete metrics collection for this cycle
|
||||
stop_fn(&scan_result);
|
||||
// stop_fn(&scan_result);
|
||||
}
|
||||
|
||||
/// Execute namespace scan with cancellation support
|
||||
@@ -781,7 +780,7 @@ impl ScannerItem {
|
||||
}
|
||||
|
||||
pub async fn apply_actions(&mut self, oi: &ObjectInfo, _size_s: &mut SizeSummary) -> (bool, i64) {
|
||||
let done = ScannerMetrics::time(ScannerMetric::Ilm);
|
||||
// let done = ScannerMetrics::time(ScannerMetric::Ilm);
|
||||
|
||||
let (action, _size) = self.apply_lifecycle(oi).await;
|
||||
|
||||
@@ -807,7 +806,7 @@ impl ScannerItem {
|
||||
self.heal_replication(&oi, _size_s).await;
|
||||
}
|
||||
|
||||
done();
|
||||
// done();
|
||||
|
||||
if action.delete_all() {
|
||||
return (true, 0);
|
||||
@@ -1572,68 +1571,69 @@ pub fn rep_has_active_rules(config: &ReplicationConfiguration, prefix: &str, rec
|
||||
|
||||
pub type LocalDrive = Arc<LocalDisk>;
|
||||
pub async fn scan_data_folder(
|
||||
disks: &[Option<DiskStore>],
|
||||
drive: LocalDrive,
|
||||
cache: &DataUsageCache,
|
||||
get_size_fn: GetSizeFn,
|
||||
heal_scan_mode: HealScanMode,
|
||||
should_sleep: ShouldSleepFn,
|
||||
_disks: &[Option<DiskStore>],
|
||||
_drive: LocalDrive,
|
||||
_cache: &DataUsageCache,
|
||||
_get_size_fn: GetSizeFn,
|
||||
_heal_scan_mode: HealScanMode,
|
||||
_should_sleep: ShouldSleepFn,
|
||||
) -> disk::error::Result<DataUsageCache> {
|
||||
if cache.info.name.is_empty() || cache.info.name == DATA_USAGE_ROOT {
|
||||
return Err(DiskError::other("internal error: root scan attempted"));
|
||||
}
|
||||
// if cache.info.name.is_empty() || cache.info.name == DATA_USAGE_ROOT {
|
||||
// return Err(DiskError::other("internal error: root scan attempted"));
|
||||
// }
|
||||
|
||||
let base_path = drive.to_string();
|
||||
let (update_path, close_disk) = current_path_updater(&base_path, &cache.info.name);
|
||||
let skip_heal = if *GLOBAL_IsErasure.read().await || cache.info.skip_healing {
|
||||
AtomicBool::new(true)
|
||||
} else {
|
||||
AtomicBool::new(false)
|
||||
};
|
||||
let mut s = FolderScanner {
|
||||
root: base_path,
|
||||
get_size: get_size_fn,
|
||||
old_cache: cache.clone(),
|
||||
new_cache: DataUsageCache {
|
||||
info: cache.info.clone(),
|
||||
..Default::default()
|
||||
},
|
||||
update_cache: DataUsageCache {
|
||||
info: cache.info.clone(),
|
||||
..Default::default()
|
||||
},
|
||||
data_usage_scanner_debug: false,
|
||||
heal_object_select: 0,
|
||||
scan_mode: heal_scan_mode,
|
||||
updates: cache.info.updates.clone().unwrap(),
|
||||
last_update: SystemTime::now(),
|
||||
update_current_path: update_path,
|
||||
disks: disks.to_vec(),
|
||||
disks_quorum: disks.len() / 2,
|
||||
skip_heal,
|
||||
drive: drive.clone(),
|
||||
we_sleep: should_sleep,
|
||||
};
|
||||
// let base_path = drive.to_string();
|
||||
// // let (update_path, close_disk) = current_path_updater(&base_path, &cache.info.name);
|
||||
// let skip_heal = if *GLOBAL_IsErasure.read().await || cache.info.skip_healing {
|
||||
// AtomicBool::new(true)
|
||||
// } else {
|
||||
// AtomicBool::new(false)
|
||||
// };
|
||||
// let mut s = FolderScanner {
|
||||
// root: base_path,
|
||||
// get_size: get_size_fn,
|
||||
// old_cache: cache.clone(),
|
||||
// new_cache: DataUsageCache {
|
||||
// info: cache.info.clone(),
|
||||
// ..Default::default()
|
||||
// },
|
||||
// update_cache: DataUsageCache {
|
||||
// info: cache.info.clone(),
|
||||
// ..Default::default()
|
||||
// },
|
||||
// data_usage_scanner_debug: false,
|
||||
// heal_object_select: 0,
|
||||
// scan_mode: heal_scan_mode,
|
||||
// updates: cache.info.updates.clone().unwrap(),
|
||||
// last_update: SystemTime::now(),
|
||||
// update_current_path: update_path,
|
||||
// disks: disks.to_vec(),
|
||||
// disks_quorum: disks.len() / 2,
|
||||
// skip_heal,
|
||||
// drive: drive.clone(),
|
||||
// we_sleep: should_sleep,
|
||||
// };
|
||||
|
||||
if *GLOBAL_IsErasure.read().await || !cache.info.skip_healing {
|
||||
s.heal_object_select = HEAL_OBJECT_SELECT_PROB as u32;
|
||||
}
|
||||
// if *GLOBAL_IsErasure.read().await || !cache.info.skip_healing {
|
||||
// s.heal_object_select = HEAL_OBJECT_SELECT_PROB as u32;
|
||||
// }
|
||||
|
||||
let mut root = DataUsageEntry::default();
|
||||
let folder = CachedFolder {
|
||||
name: cache.info.name.clone(),
|
||||
object_heal_prob_div: 1,
|
||||
parent: DataUsageHash("".to_string()),
|
||||
};
|
||||
// let mut root = DataUsageEntry::default();
|
||||
// let folder = CachedFolder {
|
||||
// name: cache.info.name.clone(),
|
||||
// object_heal_prob_div: 1,
|
||||
// parent: DataUsageHash("".to_string()),
|
||||
// };
|
||||
|
||||
if s.scan_folder(&folder, &mut root).await.is_err() {
|
||||
close_disk().await;
|
||||
}
|
||||
s.new_cache.force_compact(DATA_SCANNER_COMPACT_AT_CHILDREN as usize);
|
||||
s.new_cache.info.last_update = Some(SystemTime::now());
|
||||
s.new_cache.info.next_cycle = cache.info.next_cycle;
|
||||
close_disk().await;
|
||||
Ok(s.new_cache)
|
||||
// if s.scan_folder(&folder, &mut root).await.is_err() {
|
||||
// close_disk().await;
|
||||
// }
|
||||
// s.new_cache.force_compact(DATA_SCANNER_COMPACT_AT_CHILDREN as usize);
|
||||
// s.new_cache.info.last_update = Some(SystemTime::now());
|
||||
// s.new_cache.info.next_cycle = cache.info.next_cycle;
|
||||
// close_disk().await;
|
||||
// Ok(s.new_cache)
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub async fn eval_action_from_lifecycle(
|
||||
@@ -1695,11 +1695,11 @@ pub async fn apply_expiry_on_transitioned_object(
|
||||
lc_event: &lifecycle::Event,
|
||||
src: &LcEventSrc,
|
||||
) -> bool {
|
||||
let time_ilm = ScannerMetrics::time_ilm(lc_event.action.clone());
|
||||
// let time_ilm = ScannerMetrics::time_ilm(lc_event.action.clone());
|
||||
if let Err(_err) = expire_transitioned_object(api, oi, lc_event, src).await {
|
||||
return false;
|
||||
}
|
||||
let _ = time_ilm(1);
|
||||
// let _ = time_ilm(1);
|
||||
|
||||
true
|
||||
}
|
||||
@@ -1727,7 +1727,7 @@ pub async fn apply_expiry_on_non_transitioned_objects(
|
||||
opts.delete_prefix_object = true;
|
||||
}
|
||||
|
||||
let time_ilm = ScannerMetrics::time_ilm(lc_event.action.clone());
|
||||
// let time_ilm = ScannerMetrics::time_ilm(lc_event.action.clone());
|
||||
|
||||
let mut dobj = api
|
||||
.delete_object(&oi.bucket, &encode_dir_object(&oi.name), opts)
|
||||
@@ -1759,11 +1759,11 @@ pub async fn apply_expiry_on_non_transitioned_objects(
|
||||
});
|
||||
|
||||
if lc_event.action != lifecycle::IlmAction::NoneAction {
|
||||
let mut num_versions = 1_u64;
|
||||
if lc_event.action.delete_all() {
|
||||
num_versions = oi.num_versions as u64;
|
||||
}
|
||||
let _ = time_ilm(num_versions);
|
||||
// let mut num_versions = 1_u64;
|
||||
// if lc_event.action.delete_all() {
|
||||
// num_versions = oi.num_versions as u64;
|
||||
// }
|
||||
// let _ = time_ilm(num_versions);
|
||||
}
|
||||
|
||||
true
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
pub mod background_heal_ops;
|
||||
pub mod data_scanner;
|
||||
pub mod data_scanner_metric;
|
||||
// pub mod data_scanner_metric;
|
||||
pub mod data_usage;
|
||||
pub mod data_usage_cache;
|
||||
pub mod error;
|
||||
|
||||
@@ -15,7 +15,10 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use chrono::Utc;
|
||||
use rustfs_common::globals::{GLOBAL_Local_Node_Name, GLOBAL_Rustfs_Addr};
|
||||
use rustfs_common::{
|
||||
globals::{GLOBAL_Local_Node_Name, GLOBAL_Rustfs_Addr},
|
||||
metrics::globalMetrics,
|
||||
};
|
||||
use rustfs_madmin::metrics::{DiskIOStats, DiskMetric, RealtimeMetrics};
|
||||
use rustfs_utils::os::get_drive_stats;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -23,10 +26,7 @@ use tracing::info;
|
||||
|
||||
use crate::{
|
||||
admin_server_info::get_local_server_property,
|
||||
heal::{
|
||||
data_scanner_metric::globalScannerMetrics,
|
||||
heal_commands::{DRIVE_STATE_OK, DRIVE_STATE_UNFORMATTED},
|
||||
},
|
||||
heal::heal_commands::{DRIVE_STATE_OK, DRIVE_STATE_UNFORMATTED},
|
||||
new_object_layer_fn,
|
||||
store_api::StorageAPI,
|
||||
// utils::os::get_drive_stats,
|
||||
@@ -108,7 +108,7 @@ pub async fn collect_local_metrics(types: MetricType, opts: &CollectMetricsOpts)
|
||||
|
||||
if types.contains(&MetricType::SCANNER) {
|
||||
info!("start get scanner metrics");
|
||||
let metrics = globalScannerMetrics.report().await;
|
||||
let metrics = globalMetrics.report().await;
|
||||
real_time_metrics.aggregated.scanner = Some(metrics);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user