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

refactor(config): Move configs to components #5460

Merged
merged 4 commits into from
Oct 24, 2022
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
3 changes: 2 additions & 1 deletion zebra-network/src/isolated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ where
/// Transactions sent over this connection can be linked to the sending and receiving IP address
/// by passive internet observers.
///
/// Prefer [`connect_isolated_tor`](tor::connect_isolated_tor) if available.
///
/// Prefer `connect_isolated_tor` if available.
pub fn connect_isolated_tcp_direct(
network: Network,
addr: SocketAddr,
Expand Down
4 changes: 2 additions & 2 deletions zebrad/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ test_sync_past_mandatory_checkpoint_testnet = []

[dependencies]
zebra-chain = { path = "../zebra-chain" }
zebra-consensus = { path = "../zebra-consensus/" }
zebra-consensus = { path = "../zebra-consensus" }
zebra-network = { path = "../zebra-network" }
zebra-node-services = { path = "../zebra-node-services" }
zebra-rpc = { path = "../zebra-rpc" }
Expand Down Expand Up @@ -176,7 +176,7 @@ proptest-derive = "0.3.0"
color-eyre = { version = "0.6.2", features = ["issue-url"] }

zebra-chain = { path = "../zebra-chain", features = ["proptest-impl"] }
zebra-consensus = { path = "../zebra-consensus/", features = ["proptest-impl"] }
zebra-consensus = { path = "../zebra-consensus", features = ["proptest-impl"] }
zebra-network = { path = "../zebra-network", features = ["proptest-impl"] }
zebra-state = { path = "../zebra-state", features = ["proptest-impl"] }
zebra-test = { path = "../zebra-test" }
3 changes: 2 additions & 1 deletion zebrad/src/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@ impl Application for ZebradApp {

// Ignore the configured tracing filter for short-lived utility commands
let mut tracing_config = cfg_ref.tracing.clone();
let metrics_config = cfg_ref.metrics.clone();
if is_server {
// Override the default tracing filter based on the command-line verbosity.
tracing_config.filter = tracing_config
Expand Down Expand Up @@ -426,7 +427,7 @@ impl Application for ZebradApp {
if is_server {
components.push(Box::new(TokioComponent::new()?));
components.push(Box::new(TracingEndpoint::new(cfg_ref)?));
components.push(Box::new(MetricsEndpoint::new(cfg_ref)?));
components.push(Box::new(MetricsEndpoint::new(&metrics_config)?));
}

self.state.components.register(components)
Expand Down
36 changes: 30 additions & 6 deletions zebrad/src/components/metrics.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
//! An HTTP endpoint for metrics collection.

use abscissa_core::{Component, FrameworkError};
use std::net::SocketAddr;

use crate::config::ZebradConfig;
use abscissa_core::{Component, FrameworkError};
use serde::{Deserialize, Serialize};

/// Abscissa component which runs a metrics endpoint.
#[derive(Debug, Component)]
Expand All @@ -11,8 +12,8 @@ pub struct MetricsEndpoint {}
impl MetricsEndpoint {
/// Create the component.
#[cfg(feature = "prometheus")]
pub fn new(config: &ZebradConfig) -> Result<Self, FrameworkError> {
if let Some(addr) = config.metrics.endpoint_addr {
pub fn new(config: &Config) -> Result<Self, FrameworkError> {
if let Some(addr) = config.endpoint_addr {
info!("Trying to open metrics endpoint at {}...", addr);

let endpoint_result = metrics_exporter_prometheus::PrometheusBuilder::new()
Expand Down Expand Up @@ -45,8 +46,8 @@ impl MetricsEndpoint {

/// Create the component.
#[cfg(not(feature = "prometheus"))]
pub fn new(config: &ZebradConfig) -> Result<Self, FrameworkError> {
if let Some(addr) = config.metrics.endpoint_addr {
pub fn new(config: &Config) -> Result<Self, FrameworkError> {
if let Some(addr) = config.endpoint_addr {
warn!(
?addr,
"unable to activate configured metrics endpoint: \
Expand All @@ -57,3 +58,26 @@ impl MetricsEndpoint {
Ok(Self {})
}
}

/// Metrics configuration section.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields, default)]
pub struct Config {
/// The address used for the Prometheus metrics endpoint.
///
/// Install Zebra using `cargo install --features=prometheus` to enable this config.
///
/// The endpoint is disabled if this is set to `None`.
pub endpoint_addr: Option<SocketAddr>,
}

// we like our default configs to be explicit
#[allow(unknown_lints)]
#[allow(clippy::derivable_impls)]
impl Default for Config {
fn default() -> Self {
Self {
endpoint_addr: None,
}
}
}
78 changes: 78 additions & 0 deletions zebrad/src/components/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use std::{cmp::max, collections::HashSet, pin::Pin, sync::Arc, task::Poll, time:
use color_eyre::eyre::{eyre, Report};
use futures::stream::{FuturesUnordered, StreamExt};
use indexmap::IndexSet;
use serde::{Deserialize, Serialize};
use tokio::time::sleep;
use tower::{
builder::ServiceBuilder, hedge::Hedge, limit::ConcurrencyLimit, retry::Retry, timeout::Timeout,
Expand Down Expand Up @@ -204,6 +205,83 @@ const SYNC_RESTART_DELAY: Duration = Duration::from_secs(67);
/// a denial of service on those peers.
const GENESIS_TIMEOUT_RETRY: Duration = Duration::from_secs(5);

/// Sync configuration section.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields, default)]
pub struct Config {
/// The number of parallel block download requests.
///
/// This is set to a low value by default, to avoid task and
/// network contention. Increasing this value may improve
/// performance on machines with a fast network connection.
#[serde(alias = "max_concurrent_block_requests")]
pub download_concurrency_limit: usize,

/// The number of blocks submitted in parallel to the checkpoint verifier.
///
/// Increasing this limit increases the buffer size, so it reduces
/// the impact of an individual block request failing. However, it
/// also increases memory and CPU usage if block validation stalls,
/// or there are some large blocks in the pipeline.
///
/// The block size limit is 2MB, so in theory, this could represent multiple
/// gigabytes of data, if we downloaded arbitrary blocks. However,
/// because we randomly load balance outbound requests, and separate
/// block download from obtaining block hashes, an adversary would
/// have to control a significant fraction of our peers to lead us
/// astray.
///
/// For reliable checkpoint syncing, Zebra enforces a
/// [`MIN_CHECKPOINT_CONCURRENCY_LIMIT`](MIN_CHECKPOINT_CONCURRENCY_LIMIT).
///
/// This is set to a high value by default, to avoid verification pipeline stalls.
/// Decreasing this value reduces RAM usage.
#[serde(alias = "lookahead_limit")]
pub checkpoint_verify_concurrency_limit: usize,

/// The number of blocks submitted in parallel to the full verifier.
///
/// This is set to a low value by default, to avoid verification timeouts on large blocks.
/// Increasing this value may improve performance on machines with many cores.
pub full_verify_concurrency_limit: usize,

/// The number of threads used to verify signatures, proofs, and other CPU-intensive code.
///
/// Set to `0` by default, which uses one thread per available CPU core.
/// For details, see [the `rayon` documentation](https://docs.rs/rayon/latest/rayon/struct.ThreadPoolBuilder.html#method.num_threads).
pub parallel_cpu_threads: usize,
}

impl Default for Config {
fn default() -> Self {
Self {
// 2/3 of the default outbound peer limit.
download_concurrency_limit: 50,

// A few max-length checkpoints.
checkpoint_verify_concurrency_limit: DEFAULT_CHECKPOINT_CONCURRENCY_LIMIT,

// This default is deliberately very low, so Zebra can verify a few large blocks in under 60 seconds,
// even on machines with only a few cores.
//
// This lets users see the committed block height changing in every progress log,
// and avoids hangs due to out-of-order verifications flooding the CPUs.
//
// TODO:
// - limit full verification concurrency based on block transaction counts?
// - move more disk work to blocking tokio threads,
// and CPU work to the rayon thread pool inside blocking tokio threads
full_verify_concurrency_limit: 20,

// Use one thread per CPU.
//
// If this causes tokio executor starvation, move CPU-intensive tasks to rayon threads,
// or reserve a few cores for tokio threads, based on `num_cpus()`.
parallel_cpu_threads: 0,
}
}
}

/// Helps work around defects in the bitcoin protocol by checking whether
/// the returned hashes actually extend a chain tip.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
Expand Down
110 changes: 110 additions & 0 deletions zebrad/src/components/tracing.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
//! Tracing and logging infrastructure for Zebra.

use std::{net::SocketAddr, path::PathBuf};

use serde::{Deserialize, Serialize};

mod component;
mod endpoint;

Expand All @@ -11,3 +15,109 @@ pub use endpoint::TracingEndpoint;

#[cfg(feature = "flamegraph")]
pub use flame::{layer, Grapher};

/// Tracing configuration section.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields, default)]
pub struct Config {
/// Whether to use colored terminal output, if available.
///
/// Colored terminal output is automatically disabled if an output stream
/// is connected to a file. (Or another non-terminal device.)
///
/// Defaults to `true`, which automatically enables colored output to
/// terminals.
pub use_color: bool,

/// Whether to force the use of colored terminal output, even if it's not available.
///
/// Will force Zebra to use colored terminal output even if it does not detect that the output
/// is a terminal that supports colors.
///
/// Defaults to `false`, which keeps the behavior of `use_color`.
pub force_use_color: bool,

/// The filter used for tracing events.
///
/// The filter is used to create a `tracing-subscriber`
/// [`EnvFilter`](https://docs.rs/tracing-subscriber/0.2.10/tracing_subscriber/filter/struct.EnvFilter.html#directives),
/// and more details on the syntax can be found there or in the examples
/// below.
///
/// If no filter is specified (`None`), the filter is set to `info` if the
/// `-v` flag is given and `warn` if it is not given.
///
/// # Examples
///
/// `warn,zebrad=info,zebra_network=debug` sets a global `warn` level, an
/// `info` level for the `zebrad` crate, and a `debug` level for the
/// `zebra_network` crate.
///
/// ```ascii,no_run
/// [block_verify{height=Some\(block::Height\(.*000\)\)}]=trace
/// ```
/// sets `trace` level for all events occurring in the context of a
/// `block_verify` span whose `height` field ends in `000`, i.e., traces the
/// verification of every 1000th block.
pub filter: Option<String>,

/// The buffer_limit size sets the number of log lines that can be queued by the tracing subscriber
/// to be written to stdout before logs are dropped.
///
/// Defaults to 128,000 with a minimum of 100.
pub buffer_limit: usize,

/// The address used for an ad-hoc RPC endpoint allowing dynamic control of the tracing filter.
///
/// Install Zebra using `cargo install --features=filter-reload` to enable this config.
///
/// If this is set to None, the endpoint is disabled.
pub endpoint_addr: Option<SocketAddr>,

/// Controls whether to write a flamegraph of tracing spans.
///
/// Install Zebra using `cargo install --features=flamegraph` to enable this config.
///
/// If this is set to None, flamegraphs are disabled. Otherwise, it specifies
/// an output file path, as described below.
///
/// This path is not used verbatim when writing out the flamegraph. This is
/// because the flamegraph is written out as two parts. First the flamegraph
/// is constantly persisted to the disk in a "folded" representation that
/// records collapsed stack traces of the tracing spans that are active.
/// Then, when the application is finished running the destructor will flush
/// the flamegraph output to the folded file and then read that file and
/// generate the final flamegraph from it as an SVG.
///
/// The need to create two files means that we will slightly manipulate the
/// path given to us to create the two representations.
///
/// # Example
///
/// Given `flamegraph = "flamegraph"` we will generate a `flamegraph.svg` and
/// a `flamegraph.folded` file in the current directory.
///
/// If you provide a path with an extension the extension will be ignored and
/// replaced with `.folded` and `.svg` for the respective files.
pub flamegraph: Option<PathBuf>,

/// The use_journald flag sends tracing events to systemd-journald, on Linux
/// distributions that use systemd.
///
/// Install Zebra using `cargo install --features=journald` to enable this config.
pub use_journald: bool,
}

impl Default for Config {
fn default() -> Self {
Self {
use_color: true,
force_use_color: false,
filter: None,
buffer_limit: 128_000,
endpoint_addr: None,
flamegraph: None,
use_journald: false,
}
}
}
4 changes: 2 additions & 2 deletions zebrad/src/components/tracing/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use tracing_subscriber::{

use tracing_appender::non_blocking::{NonBlocking, NonBlockingBuilder, WorkerGuard};

use crate::{application::app_version, config::TracingSection};
use crate::{application::app_version, components::tracing::Config};

#[cfg(feature = "flamegraph")]
use super::flame;
Expand Down Expand Up @@ -43,7 +43,7 @@ pub struct Tracing {

impl Tracing {
/// Try to create a new [`Tracing`] component with the given `filter`.
pub fn new(config: TracingSection) -> Result<Self, FrameworkError> {
pub fn new(config: Config) -> Result<Self, FrameworkError> {
let filter = config.filter.unwrap_or_default();
let flame_root = &config.flamegraph;

Expand Down
Loading