- 区块链
【免费下载链接】polkadot
Polkadot Node Implementation
本篇技术指南围绕 node/metrics 这一 Subsystem 指标辅助 crate(polkadot-node-metrics)展开,讲解其在 Polkadot 节点中的定位、构建前提、Metronome周期采样机制、Metricstrait 设计,以及基于 Substrate WASM tracing 的 Runtime 指标(runtime-metrics)完整上报链路。读完本文,你将掌握:如何正确构建并测试该 crate、如何在 overseer 中用Metronome周期性采集指标快照、如何用logger_hook()把 Runtime 侧 Prometheus 指标桥接到客户端 Prometheus registry,以及如何验证这条链路的正确性。
一、crate 定位与能力总览
polkadot-node-metrics是一个"子系统指标助手"(Subsystem metric helpers)crate,其职责在 node/metrics/src/lib.rs 的 crate 级文档中定义得很清楚:收集一批指标提供者(metrics providers)以及诸如Metronome之类的配套能力,供指标采集使用,同时重新导出(reexport)子系统需要实现/使用的 Prometheus 指标类型。
该 crate 主要提供四类能力:
| 能力 | 说明 | 关键源码位置 |
|---|---|---|
Metronome | 以固定周期产生 tick 的Stream,用于周期性采集指标 | node/metrics/src/metronome.rs |
Metricstrait | 子系统/任务专用 Prometheus 指标的统一注册接口 | node/metrics/src/lib.rs |
| Prometheus 类型 reexport | 重新导出substrate_prometheus_endpoint,子系统可直接复用 | node/metrics/src/lib.rs |
| Runtime 指标提供者 | runtime-metricsfeature 下的logger_hook()与RuntimeMetricsProvider | node/metrics/src/runtime/mod.rs |
crate 的依赖设计(见 node/metrics/Cargo.toml)值得注意:它依赖了metered(即prioritized-metered-channel)来获取 channel 的计量数据,并依赖sc-service、sc-cli、substrate-prometheus-endpoint、sc-tracing等 Substrate 组件——注释明确指出sc-service与sc-cli是 Runtime 指标logger_hook()所必需的。
crate 还通过 Cargo features 控制编译开关:
default = []:默认不开启任何额外能力,此时logger_hook()退化为一个空操作闭包(见 node/metrics/src/lib.rs);runtime-metrics:启用 Runtime 指标提供者模块(runtime模块仅在开启该 feature 时编译,见 node/metrics/src/lib.rs);runtime-benchmarks:与测试条件配合,控制集成测试的编译范围(见 node/metrics/src/lib.rs)。
二、测试前提:先构建两个 PVF worker 二进制
polkadot-node-metrics的 README 只有一节,但非常关键,它规定了该 crate 的测试前置条件:
Before running
cargo testin this crate, make sure the worker binaries are built first.
在运行本 crate 的cargo test之前,必须先构建 worker 二进制,命令如下:
cargo build --bin polkadot-execute-worker --bin polkadot-prepare-worker为什么会有这个前提?因为 node/metrics/src/tests.rs 中的集成测试会通过polkadot-test-service(见 node/test/service)启动真实的验证人节点(validator node),而节点运行 PVF(平行链验证函数)需要polkadot-execute-worker(执行 worker)与polkadot-prepare-worker(准备 worker)这两个进程级 worker 二进制。这些 worker 由 node/core/pvf 的execute-worker与prepare-worker子 crate 产出,属于同仓库内编译产物,不会随依赖自动构建,因此必须先显式cargo build,否则测试节点启动时会因找不到 worker 而失败。
测试代码的依赖也印证了这一点:dev-dependencies 中引入了polkadot-test-service(并开启runtime-metricsfeature)、substrate-test-utils、sp-keyring、hyper、tokio、prometheus-parse等(见 node/metrics/Cargo.toml),完整模拟"起节点 → 抓取 Prometheus 指标 → 解析断言"的端到端验证。
三、Metronome:周期驱动的指标采样源
Metronome是一个按固定周期产生 tick 的futures::Stream,其实现位于 node/metrics/src/metronome.rs,核心代码量不大但很精炼:
pub struct Metronome { delay: Delay, period: Duration, state: MetronomeState, // Snooze / SetAlarm } impl Metronome { pub fn new(cycle: Duration) -> Self { let period = cycle.into(); Self { period, delay: Delay::new(period), state: MetronomeState::Snooze } } }从源码看,它内部持有一个futures_timer::Delay和一个内部状态机:
Snooze(休眠)状态:轮询内部Delay,若尚未就绪则返回Poll::Pending;若就绪则切换到SetAlarm并返回Poll::Ready(Some(()))产出一个 tick;SetAlarm(设闹钟)状态:用self.period重置Delay,回到Snooze状态。
由于每次 tick 后都会用同一周期重置计时器,Metronome是一个永不终止的无限流,这一点在 node/subsystem-util/src/tests.rs 的单元测试注释中被直接写为unreachable!("Metronome never stops. qed")。
Metronome的典型使用场景在 node/overseer/src/lib.rs 的spawn_metronome_metrics函数中:overseer 用Metronome::new(std::time::Duration::from_millis(950))创建约950ms 一个周期的采样器,每个 tick 触发:
collect_memory_stats(&metronome_metrics):采集内存分配统计;metronome_metrics.channel_metrics_snapshot(...):汇总所有子系统到 overseer 的 channel 消息量(将各子系统的subsystem_meters快照合并成一个to_overseer指标)。
这种"周期 tick + 快照采集"的模式正是Metronome存在的意义:把低频、周期性的指标聚合任务与事件驱动的消息处理解耦。若需要其他周期,直接向Metronome::new传入不同的Duration即可。
四、Metrics trait:子系统的 Prometheus 指标注册约定
所有子系统/任务专用的 Prometheus 指标都通过 node/metrics/src/lib.rs 定义的Metricstrait 统一接入:
pub trait Metrics: Default + Clone { fn try_register( registry: &prometheus::Registry, ) -> Result<Self, prometheus::PrometheusError>; fn register( registry: Option<&prometheus::Registry>, ) -> Result<Self, prometheus::PrometheusError> { match registry { None => Ok(Self::default()), Some(registry) => Self::try_register(registry), } } }该 trait 的设计要点:
Default + Clone约束:实现者通常是Option<ActualMetrics>的包装(无 registry 时取Default空实现),或者是单元类型();Prometheus 指标内部持有Arc引用,克隆成本极低,因此可以放心 clone 分发;try_register:真正把指标注册进 Prometheus registry;register:便捷方法——传入None(未启用 Prometheus)时静默返回Default::default(),传入Some(registry)时等价于try_register。这样子系统在"启用/未启用 Prometheus"两种配置下都能统一调用register(registry.as_ref());- 为
()提供了空实现:try_register直接返回Ok(()),使得"无指标"的子系统也能天然满足Metrics约束。
模块中还pub use substrate_prometheus_endpoint as prometheus重新导出了 Substrate 的 Prometheus 端点(见 node/metrics/src/lib.rs),意味着子系统编写指标时直接使用polkadot_node_metrics::metrics::prometheus::{Counter, Gauge, ...}即可,无需各自引入 Substrate 依赖。overseer 正是这样做的(见 node/overseer/src/lib.rs),它pub use polkadot_node_metrics::{... Metronome, ...}直接复用本 crate 的指标基础设施。
五、Runtime 指标:从 WASM Runtime 到 Prometheus 的完整链路
5.1 整体架构:WASM tracing 事件桥接
polkadot-node-metrics的进阶能力是runtime-metricsfeature 下的 Runtime 指标提供者,其设计思路记录在 node/metrics/src/runtime/mod.rs 的模块文档中:
A runtime metric provider implementation that builds on top of Substrate wasm tracing support. This requires that the custom profiler (
TraceHandler) to be registered in substrate via alogger_hook(). Events emitted from runtime are then captured/processed by theTraceHandlerimplementation.
也就是说:Runtime 侧(WASM)发出的指标事件,通过 Substrate 的 WASM tracing 机制传输到客户端(native),由注册在logger_hook()里的TraceHandler捕获并落地到 Prometheus 指标。完整链路为:
- Runtime 侧:
polkadot-runtime-metrics(runtime/metrics/src/with_runtime_metrics.rs)提供 Prometheus 风格的Counter/CounterVec/Histogram类型。它们的inc_by/observe方法会构造一个RuntimeMetricUpdate结构体(含指标名 + 操作),经 SCALE 编码后用bs58编码,再通过sp_tracing::event!(target: "metrics", Level::TRACE, update_op = ...)发射 tracing 事件(见 runtime/metrics/src/with_runtime_metrics.rs); - 客户端侧:
RuntimeMetricsProvider实现sc_tracing::TraceHandler,在handle_event中过滤target == "metrics"的事件,从params字符串解析出bs58编码的RuntimeMetricUpdate,解码后执行对应的指标更新(见 node/metrics/src/runtime/mod.rs); - 落地:
RuntimeMetricsProvider持有Registry与三个内部 HashMap(counter_vecs/counters/histograms,均以Arc<Mutex<...>>保护),把更新映射到真正的 PrometheusCounterVec/Counter/Histogram。
数据结构的定义在 primitives/src/v5/metrics.rs:
pub enum RuntimeMetricOp { IncrementCounterVec(u64, RuntimeMetricLabelValues), IncrementCounter(u64), ObserveHistogram(u128), } pub struct RuntimeMetricUpdate { pub metric_name: Vec<u8>, pub op: RuntimeMetricOp, }5.2 logger_hook():注册 TraceHandler 的入口
客户端侧接入的入口是logger_hook(),其实现位于 node/metrics/src/runtime/mod.rs:
pub fn logger_hook() -> impl FnOnce(&mut sc_cli::LoggerBuilder, &sc_service::Configuration) -> () { |logger_builder, config| { if config.prometheus_registry().is_none() { return } let registry = config.prometheus_registry().cloned().unwrap(); let metrics_provider = RuntimeMetricsProvider::new(registry); parachain::register_metrics(&metrics_provider); logger_builder.with_custom_profiling(Box::new(metrics_provider)); } }关键行为:
- 若节点未配置 Prometheus registry(
prometheus_registry().is_none())则直接返回,不做任何事,避免无谓开销; - 有 registry 时,创建
RuntimeMetricsProvider,调用parachain::register_metrics预注册一组平行链 Runtime 指标,最后通过logger_builder.with_custom_profiling把 provider 注册为 Substrate 自定义 profiler(TraceHandler)。
该 hook 的实际接线发生在 CLI 层:polkadot 命令的主流程在 cli/src/command.rs 调用run_node_inner(..., polkadot_node_metrics::logger_hook()),run_node_inner再把它传给create_runner_with_logger_hook(见 cli/src/command.rs)。因此,只要用polkadotCLI 启动节点并开启 Prometheus 端点,Runtime 指标上报链路就自动生效。
5.3 指标注册与更新:客户端侧实现
RuntimeMetricsProvider暴露三组注册与更新方法(见 node/metrics/src/runtime/mod.rs):
| 方法 | 作用 |
|---|---|
register_countervec/register_counter/register_histogram | 将 Runtime 侧定义的指标注册进 registry,以指标名为 key 去重(or_insert),重复注册不会覆盖 |
inc_counter_vec_by(name, value, labels) | 按标签值递增CounterVec |
inc_counter_by(name, value) | 递增普通Counter |
observe_histogram(name, value) | 记录直方图观测值,入参单位为纳秒(ns),内部除以1_000_000_000.0转换为秒后交给 Prometheus Histogram |
handle_event的解析细节也值得注意(见 node/metrics/src/runtime/mod.rs):Runtime 侧通过sp_tracing宏格式化出的params形如" { update_op: <bs58字符串> }",客户端先剥掉前缀" { update_op: "和后缀" }",再对剩余 bs58 字符串解码、RuntimeMetricUpdate::decodeSCALE 解码,最后按RuntimeMetricOp分发到对应更新方法。该模块文档特别提醒(见 node/metrics/src/runtime/mod.rs):不要在此文件中加日志,因为它在 logger 初始化之前执行、日志不会送达;需要调试时应使用println!。
5.4 平行链 Runtime 指标清单
parachain::register_metrics(node/metrics/src/runtime/parachain.rs)预注册了六类指标,它们的完整定义(名称、描述、标签、直方图桶)集中在 primitives/src/v5/metrics.rs 的metric_definitions模块中:
| 指标名(Prometheus) | 类型 | 描述 | 标签 |
|---|---|---|---|
polkadot_parachain_inherent_data_weight | CounterVec | inherent data 在过滤前/后的权重 | when:before-filter/after-filter |
polkadot_parachain_inherent_data_bitfields_processed | Counter | process_inherent_data处理的 bitfield 数量 | — |
polkadot_parachain_inherent_data_candidates_processed | CounterVec | 处理的候选区块数量 | category:total/sanitized/included |
polkadot_parachain_inherent_data_dispute_sets_processed | CounterVec | 处理的争议声明集数量 | category:imported/current/concluded_invalid(以及frozen) |
polkadot_parachain_create_inherent_bitfields_signature_checks | CounterVec | bitfield 签名检查次数 | validity:valid/invalid |
polkadot_parachain_verify_dispute_signature | Histogram | 验证单个争议声明验证人签名耗时(秒) | 桶:0.0, 0.00005, 0.00006, 0.0001, 0.0005, 0.001, 0.005, 0.01, 0.05, 0.1, 0.3, 0.5, 1.0 |
Runtime 侧对应的指标结构体在 runtime/parachains/src/metrics.rs:它使用polkadot_runtime_metrics::{Counter, CounterVec, Histogram}(即 runtime/metrics 的实现),通过on_bitfields_processed、on_candidates_included、on_before_filter、on_after_filter等语义化方法包装底层更新,实际上报点位于 runtime/parachains/src/paras_inherent/mod.rs(METRICS.on_bitfields_processed(bitfields.len() as u64))。
六、端到端验证:runtime_can_publish_metrics 集成测试
node/metrics/src/tests.rs 中的runtime_can_publish_metrics测试完整验证了"Runtime 指标 → Prometheus 端点"这条链路,可作为手工验证的参考流程:
- 配置验证人节点并启用 Prometheus:用
polkadot_test_service::node_config构建 Alice 配置,alice_config.prometheus_config = Some(test_prometheus_config(DEFAULT_PROMETHEUS_PORT)),默认端口9616(见 node/metrics/src/tests.rs); - 开启 WASM tracing 并注入 logger_hook:
builder.with_profiling(Default::default(), "wasm_tracing=trace")启用 Runtime 侧 tracing,随后调用crate::logger_hook()(&mut builder, &alice_config)注册RuntimeMetricsProvider(见 node/metrics/src/tests.rs); - 启动双验证人节点:Alice 与 Bob 组成最小网络,
alice.wait_for_finalized_blocks(2)等待两个区块 finalize,保证 Runtime 至少执行过一次process_inherent_data; - 抓取并断言指标:用
hyper向http://localhost:9616/metrics发起 GET,用prometheus_parse::Scrape解析响应,断言polkadot_parachain_inherent_data_bitfields_processed的值大于 1(见 node/metrics/src/tests.rs)。
该测试被限定在cfg(all(feature = "runtime-metrics", not(feature = "runtime-benchmarks"), test))条件下编译(见 node/metrics/src/lib.rs),也就是说只有同时满足"开启 runtime-metrics、不开启 runtime-benchmarks、处于测试模式"时才会编译,这再次说明了第三节中先构建 worker 二进制的必要性——没有 PVF worker,测试无法拉起真实节点。
手工复现这一验证的要点可归纳为:启动带--prometheus-port(默认 9615/9616)的 polkadot 节点 → 确认日志出现 runtime-metrics 相关输出 →curl localhost:<port>/metrics | grep polkadot_parachain观察指标。测试代码中的scrape_prometheus_metrics解析函数(node/metrics/src/tests.rs)展示了如何处理/metrics响应中的 Counter/Gauge/Untyped 采样值,可作为自建指标采集脚本的参考实现。
七、小结与实践建议
围绕 node/metrics/README.md 以及本 crate 源码,可以得出以下实践要点:
- 测试本 crate 前务必先构建 PVF worker:
cargo build --bin polkadot-execute-worker --bin polkadot-prepare-worker,否则cargo test会因真实节点无法启动而失败; - 周期性指标采集首选
Metronome:它是一个永不终止的 tick 流,overseer 用它每 ~950ms 聚合内存统计与 channel 消息快照;自定义周期只需修改Duration; - 子系统指标统一实现
Metricstrait:无 Prometheus 配置时register(None)自动退化为Default,保证各子系统行为一致; - Runtime 指标开箱即用:
polkadotCLI 主流程已经接入polkadot_node_metrics::logger_hook(),只要节点启用了 Prometheus 端点,Runtime 内polkadot_runtime_metrics上报的平行链指标(inherent data 权重、bitfield 处理数、候选处理数、争议签名验证耗时等)就会自动出现在/metrics输出中; - 调试注意:
RuntimeMetricsProvider的代码运行在 logger 初始化之前,调试时用println!而不是log/gum。
如需深入了解指标在 Runtime 侧的定义与上报语义,可继续阅读 runtime/metrics、runtime/parachains/src/metrics.rs 与 primitives/src/v5/metrics.rs;如需查看Metronome在真实运行节点中的消费方式,参考 node/overseer/src/lib.rs。
- 区块链
【免费下载链接】polkadot
Polkadot Node Implementation
相关推荐
micro框架性能监控:自定义指标实现与收集
micro框架性能监控:自定义指标实现与收集 你是否在部署micro框架构建的微服务时遇到过这些问题?请求延迟突然飙升却找不到原因?系统资源耗尽但不知瓶颈所在?
后端微服务Web框架Volcano 调度器节点标签选择器:用 --node-selector 让 Volcano 只在指定节点子集上调度
Volcano 调度器节点标签选择器:用 node selector 让 Volcano 只在指定节点子集上调度 本文围绕 Volcano 调度器的 node
云原生后端任务调度批处理Audacity 免费多轨音频编辑与录音软件:安装、剪辑、降噪快速上手指南
Audacity 免费多轨音频编辑与录音软件:安装、剪辑、降噪快速上手指南 Audacity 是一款免费的多轨音频编辑与录音软件,Windows、macOS、L
音频处理桌面应用音视频
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考