Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 22 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ serde = { version = "1.0.219", features = ["derive"] }
serde_json = "1.0.140"
tempfile = "3.20.0"
thiserror = "2.0.17"
tikv-jemallocator = { version = "0.6.1", features = ["background_threads", "override_allocator_on_supported_platforms"] }
tikv-jemallocator = { version = "0.7.0", features = ["background_threads", "override_allocator_on_supported_platforms"] }
tikv-jemalloc-ctl = { version = "0.7.0", features = ["stats"] }
tokio = "1.47.0"
tokio-util = { version = "0.7.15", features = ["rt"] }
tracing = "0.1.41"
Expand Down
1 change: 1 addition & 0 deletions objectstore-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ serde = { workspace = true }
serde_json = { workspace = true }
thiserror = { workspace = true }
tikv-jemallocator = { workspace = true }
tikv-jemalloc-ctl = { workspace = true }
tokio = { workspace = true, features = ["full"] }
tower = { version = "0.5.2" }
tower-http = { version = "0.6.6", default-features = false, features = [
Expand Down
38 changes: 38 additions & 0 deletions objectstore-server/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ impl Services {
/// use in the web server.
pub async fn spawn(config: Config) -> Result<ServiceState> {
tokio::spawn(track_runtime_metrics(config.runtime.metrics_interval));
tokio::spawn(track_allocator_metrics(config.runtime.metrics_interval));

let backend = backend::from_config(config.storage.clone()).await?;
let service =
Expand Down Expand Up @@ -108,6 +109,43 @@ impl Services {
}
}

/// Periodically captures and reports jemalloc stats.
async fn track_allocator_metrics(interval: Duration) {
// INVARIANT: MIB resolution only fails if jemalloc is not the active allocator,
// which would be a misconfigured build. Panic early to surface the problem.
let epoch = tikv_jemalloc_ctl::epoch::mib().expect("jemalloc epoch MIB");
Comment thread
jan-auer marked this conversation as resolved.
let allocated = tikv_jemalloc_ctl::stats::allocated::mib().expect("jemalloc allocated MIB");
let active = tikv_jemalloc_ctl::stats::active::mib().expect("jemalloc active MIB");
let resident = tikv_jemalloc_ctl::stats::resident::mib().expect("jemalloc resident MIB");
let mapped = tikv_jemalloc_ctl::stats::mapped::mib().expect("jemalloc mapped MIB");

let mut ticker = tokio::time::interval(interval);
loop {
ticker.tick().await;

let Ok(_) = epoch.advance() else {
Comment thread
lcian marked this conversation as resolved.
continue;
};

if let Ok(allocated_bytes) = allocated.read() {
// Bytes currently allocated by the application.
objectstore_metrics::gauge!("jemalloc.allocated" = allocated_bytes);
}
if let Ok(active_bytes) = active.read() {
// Bytes in active jemalloc pages (≥ allocated).
objectstore_metrics::gauge!("jemalloc.active" = active_bytes);
}
if let Ok(resident_bytes) = resident.read() {
// Bytes in resident pages mapped from the OS (≥ active).
objectstore_metrics::gauge!("jemalloc.resident" = resident_bytes);
}
if let Ok(mapped_bytes) = mapped.read() {
// Bytes in chunks mapped from the OS (≥ resident).
objectstore_metrics::gauge!("jemalloc.mapped" = mapped_bytes);
}
}
}

/// Periodically captures and reports internal Tokio runtime metrics.
async fn track_runtime_metrics(interval: Duration) {
let mut ticker = tokio::time::interval(interval);
Expand Down
Loading