diff --git a/crates/config/src/constants/runtime.rs b/crates/config/src/constants/runtime.rs index 36fc33141..3e0203a71 100644 --- a/crates/config/src/constants/runtime.rs +++ b/crates/config/src/constants/runtime.rs @@ -103,7 +103,7 @@ pub const ENV_ALLOCATOR_RECLAIM_ENABLED: &str = "RUSTFS_ALLOCATOR_RECLAIM_ENABLE pub const ENV_ALLOCATOR_RECLAIM_INTERVAL_SECS: &str = "RUSTFS_ALLOCATOR_RECLAIM_INTERVAL_SECS"; pub const ENV_ALLOCATOR_RECLAIM_FORCE: &str = "RUSTFS_ALLOCATOR_RECLAIM_FORCE"; pub const ENV_ALLOCATOR_RECLAIM_IDLE_INTERVALS: &str = "RUSTFS_ALLOCATOR_RECLAIM_IDLE_INTERVALS"; -pub const DEFAULT_ALLOCATOR_RECLAIM_ENABLED: bool = false; +pub const DEFAULT_ALLOCATOR_RECLAIM_ENABLED: bool = true; pub const DEFAULT_ALLOCATOR_RECLAIM_INTERVAL_SECS: u64 = 30; pub const DEFAULT_ALLOCATOR_RECLAIM_FORCE: bool = true; pub const DEFAULT_ALLOCATOR_RECLAIM_IDLE_INTERVALS: u64 = 3; diff --git a/deploy/config/rustfs.env b/deploy/config/rustfs.env index c16ecd95e..95dfb6ff5 100644 --- a/deploy/config/rustfs.env +++ b/deploy/config/rustfs.env @@ -20,6 +20,13 @@ RUSTFS_CONSOLE_ADDRESS=0.0.0.0:9001 # RUSTFS_SERVER_DOMAINS=s3.example.com # Optional RustFS license content # RUSTFS_LICENSE=REPLACE_WITH_LICENSE_CONTENT +# Allocator reclaim is enabled by default to return freed allocator pages to +# the OS after idle samples. Set to false only for latency-sensitive profiles +# that have measured a benefit from keeping allocator pages resident. +# RUSTFS_ALLOCATOR_RECLAIM_ENABLED=false +# RUSTFS_ALLOCATOR_RECLAIM_INTERVAL_SECS=30 +# RUSTFS_ALLOCATOR_RECLAIM_IDLE_INTERVALS=3 +# RUSTFS_ALLOCATOR_RECLAIM_FORCE=true # Observability configuration endpoint: RUSTFS_OBS_ENDPOINT RUSTFS_OBS_ENDPOINT=http://localhost:4318 # Optional TLS certificates directory path: deploy/certs diff --git a/rustfs/src/allocator_reclaim.rs b/rustfs/src/allocator_reclaim.rs index 5c2853de2..f2983e9ac 100644 --- a/rustfs/src/allocator_reclaim.rs +++ b/rustfs/src/allocator_reclaim.rs @@ -18,8 +18,8 @@ //! GET, scanner, and heal workloads, mimalloc can retain freed pages in process //! heaps for later reuse instead of immediately returning them to the OS. That //! behavior is usually good for latency, but it can make process RSS look high -//! after a workload has gone idle. This module provides an opt-in background -//! loop that waits for a configurable idle window and then asks the allocator to +//! after a workload has gone idle. This module provides a configurable +//! background loop that waits for an idle window and then asks the allocator to //! collect retained memory. //! //! The loop is intentionally conservative: @@ -41,7 +41,7 @@ use metrics::{counter, gauge, histogram}; use serde::Serialize; use std::time::Duration; use tokio_util::sync::CancellationToken; -use tracing::{debug, warn}; +use tracing::{debug, info, warn}; const ALLOCATOR_RECLAIM_SERVICE_NAME: &str = "allocator_reclaim"; @@ -238,8 +238,9 @@ fn reclaimable_work_snapshot() -> ReclaimableWorkSnapshot { /// Read the startup enablement switch. /// -/// The code default is disabled. Local developer scripts may choose to export -/// the variable as enabled for their own launch profile. +/// The code default is enabled so direct binary, container, Helm, and local +/// script launches share the same reclaim contract. Operators can still set +/// `RUSTFS_ALLOCATOR_RECLAIM_ENABLED=false` for latency-sensitive deployments. fn configured_allocator_reclaim_enabled() -> bool { rustfs_utils::get_env_bool( rustfs_config::ENV_ALLOCATOR_RECLAIM_ENABLED, @@ -421,15 +422,27 @@ pub fn init_allocator_reclaim(ctx: CancellationToken) { gauge!("rustfs_memory_allocator_reclaim_enabled").set(if enabled { 1.0 } else { 0.0 }); counter!("rustfs_memory_allocator_backend_info", "backend" => backend.to_string()).increment(1); - if !enabled { - debug!("allocator reclaim loop disabled"); - return; - } - let configured_force = configured_allocator_reclaim_force(); let force = effective_allocator_reclaim_force(backend, configured_force); let idle_intervals = configured_allocator_reclaim_idle_intervals(); let interval = Duration::from_secs(configured_allocator_reclaim_interval_secs()); + info!( + event = "allocator_reclaim_configured", + component = "runtime", + subsystem = "memory", + state = if enabled { "enabled" } else { "disabled" }, + backend, + configured_force, + effective_force = force, + idle_intervals, + interval_secs = interval.as_secs(), + "allocator reclaim configured" + ); + + if !enabled { + debug!("allocator reclaim loop disabled"); + return; + } tokio::spawn(async move { let mut ticker = tokio::time::interval(interval); diff --git a/rustfs/src/config/cli.rs b/rustfs/src/config/cli.rs index 172101911..91bb098b4 100644 --- a/rustfs/src/config/cli.rs +++ b/rustfs/src/config/cli.rs @@ -302,6 +302,11 @@ pub struct TlsInspectOpts { /// Server subcommand options #[derive(Args, Clone)] +#[command(after_help = "Allocator reclaim environment: + RUSTFS_ALLOCATOR_RECLAIM_ENABLED=true|false Enable allocator page reclaim after idle samples (default: true) + RUSTFS_ALLOCATOR_RECLAIM_INTERVAL_SECS=30 Sampling interval in seconds + RUSTFS_ALLOCATOR_RECLAIM_FORCE=true|false Request forceful collection when supported + RUSTFS_ALLOCATOR_RECLAIM_IDLE_INTERVALS=3 Consecutive idle samples required before reclaim")] pub struct ServerOpts { /// DIR points to a directory on a filesystem. #[arg( @@ -612,4 +617,23 @@ mod tests { assert_eq!(help.kind(), ErrorKind::DisplayHelp); assert!(help.to_string().contains("Unix only")); } + + #[test] + fn server_help_lists_allocator_reclaim_environment() { + let result = Cli::try_parse_from(["rustfs", "server", "--help"]); + let Err(help) = result else { + panic!("help exits without parsing server options"); + }; + + assert_eq!(help.kind(), ErrorKind::DisplayHelp); + let help = help.to_string(); + for env in [ + "RUSTFS_ALLOCATOR_RECLAIM_ENABLED", + "RUSTFS_ALLOCATOR_RECLAIM_INTERVAL_SECS", + "RUSTFS_ALLOCATOR_RECLAIM_FORCE", + "RUSTFS_ALLOCATOR_RECLAIM_IDLE_INTERVALS", + ] { + assert!(help.contains(env), "server help should mention {env}"); + } + } } diff --git a/scripts/run.sh b/scripts/run.sh index 7954c2be1..dbdb78ed4 100755 --- a/scripts/run.sh +++ b/scripts/run.sh @@ -52,10 +52,6 @@ if [ -z "${RUSTFS_UNSAFE_BYPASS_DISK_CHECK+x}" ] && [ -z "${MINIO_CI+x}" ]; then export RUSTFS_UNSAFE_BYPASS_DISK_CHECK=true fi -if [ -z "${RUSTFS_ALLOCATOR_RECLAIM_ENABLED+x}" ]; then - export RUSTFS_ALLOCATOR_RECLAIM_ENABLED=true -fi - export RUSTFS_VOLUMES="${RUSTFS_VOLUMES:-./target/volume/test{1...4}}" # export RUSTFS_VOLUMES="./target/volume/test" export RUSTFS_ADDRESS="${RUSTFS_ADDRESS:-127.0.0.1:9000}"