Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pageserver: expose prometheus metrics for startup time #4893

Merged
merged 14 commits into from
Aug 8, 2023
10 changes: 10 additions & 0 deletions libs/metrics/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
//! Otherwise, we might not see all metrics registered via
//! a default registry.
use once_cell::sync::Lazy;
use prometheus::core::AtomicF64;
use prometheus::core::{AtomicU64, Collector, GenericGauge, GenericGaugeVec};
pub use prometheus::opts;
pub use prometheus::register;
Expand All @@ -28,6 +29,7 @@ pub mod metric_vec_duration;

pub type UIntGauge = GenericGauge<AtomicU64>;
pub type UIntGaugeVec = GenericGaugeVec<AtomicU64>;
pub type F64GaugeVec = GenericGaugeVec<AtomicF64>;

#[macro_export]
macro_rules! register_uint_gauge_vec {
Expand All @@ -45,6 +47,14 @@ macro_rules! register_uint_gauge {
}};
}

#[macro_export]
macro_rules! register_f64_gauge_vec {
($NAME:expr, $HELP:expr, $LABELS_NAMES:expr $(,)?) => {{
let gauge_vec = F64GaugeVec::new($crate::opts!($NAME, $HELP), $LABELS_NAMES).unwrap();
jcsp marked this conversation as resolved.
Show resolved Hide resolved
$crate::register(Box::new(gauge_vec.clone())).map(|_| gauge_vec)
}};
}

/// Special internal registry, to collect metrics independently from the default registry.
/// Was introduced to fix deadlock with lazy registration of metrics in the default registry.
static INTERNAL_REGISTRY: Lazy<Registry> = Lazy::new(Registry::new);
Expand Down
43 changes: 22 additions & 21 deletions pageserver/src/bin/pageserver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ use clap::{Arg, ArgAction, Command};
use fail::FailScenario;
use metrics::launch_timestamp::{set_launch_timestamp_metric, LaunchTimestamp};
use pageserver::disk_usage_eviction_task::{self, launch_disk_usage_global_eviction_task};
use pageserver::metrics::STARTUP_DURATION;
use pageserver::task_mgr::WALRECEIVER_RUNTIME;
use remote_storage::GenericRemoteStorage;
use tokio::time::Instant;
use tracing::*;

use metrics::set_build_info_metric;
Expand Down Expand Up @@ -226,6 +228,15 @@ fn start_pageserver(
launch_ts: &'static LaunchTimestamp,
conf: &'static PageServerConf,
) -> anyhow::Result<()> {
// Monotonic time for later calculating startup duration
let started_startup_at = Instant::now();

let startup_checkpoint = move |phase: &str, human_phase: &str| {
let secs = started_startup_at.elapsed().as_secs_f64();
STARTUP_DURATION.with_label_values(&[phase]).set(secs);
info!("{human_phase} ({secs:.3}s since start)")
jcsp marked this conversation as resolved.
Show resolved Hide resolved
};

// Print version and launch timestamp to the log,
// and expose them as prometheus metrics.
// A changed version string indicates changed software.
Expand Down Expand Up @@ -335,6 +346,10 @@ fn start_pageserver(
// Set up remote storage client
let remote_storage = create_remote_storage_client(conf)?;

// Up to this point no significant I/O has been done: this should have been fast. Record
// duration prior to starting I/O intensive phase of startup.
startup_checkpoint("initial", "Starting loading tenants");

// Startup staging or optimizing:
//
// We want to minimize downtime for `page_service` connections, and trying not to overload
Expand All @@ -360,7 +375,6 @@ fn start_pageserver(
};

// Scan the local 'tenants/' directory and start loading the tenants
let init_started_at = std::time::Instant::now();
let shutdown_pageserver = tokio_util::sync::CancellationToken::new();

BACKGROUND_RUNTIME.block_on(mgr::init_tenant_mgr(
Expand All @@ -378,18 +392,12 @@ fn start_pageserver(
let guard = scopeguard::guard_on_success((), |_| tracing::info!("Cancelled before initial load completed"));

init_done_rx.wait().await;
startup_checkpoint("initial_tenant_load", "Initial load completed");

// initial logical sizes can now start, as they were waiting on init_done_rx.

scopeguard::ScopeGuard::into_inner(guard);

let init_done = std::time::Instant::now();
let elapsed = init_done - init_started_at;

tracing::info!(
elapsed_millis = elapsed.as_millis(),
"Initial load completed"
);

let mut init_sizes_done = std::pin::pin!(init_logical_size_done_rx.wait());

let timeout = conf.background_task_maximum_delay;
Expand All @@ -398,12 +406,7 @@ fn start_pageserver(

let init_sizes_done = match tokio::time::timeout(timeout, &mut init_sizes_done).await {
Ok(_) => {
let now = std::time::Instant::now();
tracing::info!(
from_init_done_millis = (now - init_done).as_millis(),
from_init_millis = (now - init_started_at).as_millis(),
"Initial logical sizes completed"
);
startup_checkpoint("initial_logical_sizes", "Initial logical sizes completed");
None
}
Err(_) => {
Expand All @@ -419,6 +422,7 @@ fn start_pageserver(

// allow background jobs to start
drop(background_jobs_can_start);
startup_checkpoint("background_jobs_can_start", "Starting background jobs");

if let Some(init_sizes_done) = init_sizes_done {
// ending up here is not a bug; at the latest logical sizes will be queried by
Expand All @@ -428,14 +432,10 @@ fn start_pageserver(

scopeguard::ScopeGuard::into_inner(guard);

let now = std::time::Instant::now();
tracing::info!(
from_init_done_millis = (now - init_done).as_millis(),
from_init_millis = (now - init_started_at).as_millis(),
"Initial logical sizes completed after timeout (background jobs already started)"
);
startup_checkpoint("initial_logical_sizes", "Initial logical sizes completed after timeout (background jobs already started)");

}

};

async move {
Expand Down Expand Up @@ -573,6 +573,7 @@ fn start_pageserver(
);
}

startup_checkpoint("complete", "Startup complete");
jcsp marked this conversation as resolved.
Show resolved Hide resolved
let mut shutdown_pageserver = Some(shutdown_pageserver.drop_guard());

// All started up! Now just sit and wait for shutdown signal.
Expand Down
2 changes: 1 addition & 1 deletion pageserver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub mod disk_usage_eviction_task;
pub mod http;
pub mod import_datadir;
pub mod keyspace;
pub(crate) mod metrics;
pub mod metrics;
pub mod page_cache;
pub mod page_service;
pub mod pgdatadir_mapping;
Expand Down
19 changes: 15 additions & 4 deletions pageserver/src/metrics.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use metrics::metric_vec_duration::DurationResultObserver;
use metrics::{
register_counter_vec, register_histogram, register_histogram_vec, register_int_counter,
register_int_counter_vec, register_int_gauge, register_int_gauge_vec, register_uint_gauge,
register_uint_gauge_vec, Counter, CounterVec, Histogram, HistogramVec, IntCounter,
IntCounterVec, IntGauge, IntGaugeVec, UIntGauge, UIntGaugeVec,
register_counter_vec, register_f64_gauge_vec, register_histogram, register_histogram_vec,
register_int_counter, register_int_counter_vec, register_int_gauge, register_int_gauge_vec,
register_uint_gauge, register_uint_gauge_vec, Counter, CounterVec, F64GaugeVec, Histogram,
HistogramVec, IntCounter, IntCounterVec, IntGauge, IntGaugeVec, UIntGauge, UIntGaugeVec,
};
use once_cell::sync::Lazy;
use strum::VariantNames;
Expand Down Expand Up @@ -394,6 +394,17 @@ pub(crate) static UNEXPECTED_ONDEMAND_DOWNLOADS: Lazy<IntCounter> = Lazy::new(||
.expect("failed to define a metric")
});

/// How long did we take to start up? Broken down by labels to describe
/// different phases of startup.
pub static STARTUP_DURATION: Lazy<F64GaugeVec> = Lazy::new(|| {
register_f64_gauge_vec!(
"pageserver_startup_duration_secs",
"Time taken by phases of pageserver startup, in seconds",
&["phase"]
)
.expect("Failed to register pageserver_startup_duration_secs metric")
});

/// Each `Timeline`'s [`EVICTIONS_WITH_LOW_RESIDENCE_DURATION`] metric.
#[derive(Debug)]
pub struct EvictionsWithLowResidenceDuration {
Expand Down