metrics: expose cluster identity via cluster_info gauge#31066
Draft
tmgstevens wants to merge 3 commits into
Draft
metrics: expose cluster identity via cluster_info gauge#31066tmgstevens wants to merge 3 commits into
tmgstevens wants to merge 3 commits into
Conversation
set_cluster_uuid() used condition_variable::signal(), which wakes a single waiter. Multiple independent fibers can be blocked in wait_for_cluster_uuid() on the same shard (the cloud metadata uploader, the datalake iceberg committer, and the upcoming cluster identity metrics registration), and whichever fibers lost the race would sleep forever on a freshly bootstrapped cluster. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E7sDG1E1hom3tZ2nd3FH2e
Nothing in a Prometheus scrape uniquely identifies which cluster a
broker belongs to, forcing users to inject external labels in their
scrape configs. Expose the bootstrap cluster UUID as a constant gauge
on both endpoints:
redpanda_cluster_info{cluster_uuid="..."} 1
vectorized_cluster_info{cluster_uuid="..."} 1
The UUID is not yet known when setup_metrics() runs, so registration
happens in a background fiber (gated, closed via _deferred) that waits
on storage::api::wait_for_cluster_uuid(): immediate on restart, right
after bootstrap on a brand new cluster. Until then the metric is simply
absent, which is honest: a node that has not joined a cluster has no
cluster identity.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E7sDG1E1hom3tZ2nd3FH2e
Every broker must expose cluster_info on both metrics endpoints with a cluster_uuid label matching the admin API's GET /v1/cluster/uuid. The gauge registers in the background once the cluster UUID is known, so the test polls with retries. Also exclude cluster_info from test_aggregate_metrics' line counts: the async registration could otherwise change the count between scrapes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E7sDG1E1hom3tZ2nd3FH2e
Author
|
/ci-repeat 1 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
Nothing in a Prometheus scrape uniquely identifies which cluster a broker belongs to. Users who want to distinguish clusters in dashboards, recording rules, or federated setups must inject
external_labelsin every scrape config, which is error-prone and often skipped. The bootstrap cluster UUID (immutable, created once at cluster formation, not user-editable — unlike thecluster_idconfig) is the trustworthy identity, so expose it directly.What this does
Adds a constant info-style gauge to both metrics endpoints, following the
kube_state_metrics*_infoconvention (join viagroup_leftin PromQL):An info metric was chosen over stamping the UUID onto every series: per-series labels would change the identity of every time series on upgrade (breaking dashboards and recording rules), bloat scrape payloads, and fight with external labels that observability pipelines already add.
Design notes
setup_metrics()runs (it is loaded from the kvstore / replicated via the bootstrap command only after storage starts), so registration happens in a background fiber that waits onstorage::api::wait_for_cluster_uuid(): immediate on restart, right after bootstrap on a brand-new cluster. Until then the metric is simply absent — a node that has not joined a cluster has no cluster identity.metrics/instance_metrics.ccprecedent:metrics::all_metrics_groupsfor dual-endpoint registration (honors both disable flags),ssx::spawn_with_gatefor the fiber, gate closed via_deferredat shutdown (application::shutdown()breaks the UUID waiters as its first step, so the fiber always unblocks).Bug fix (first commit, independently backportable)
storage::api::set_cluster_uuid()usedcondition_variable::signal(), which wakes exactly one waiter. Multiple independent fibers can be blocked inwait_for_cluster_uuid()on the same shard — the cloud metadata uploader (cluster/cloud_metadata/uploader.cc) and the datalake iceberg committer (datalake/coordinator/iceberg_file_committer.cc) — so on a freshly bootstrapped cluster the losing fiber slept forever (e.g. cluster metadata uploads silently never starting for the life of the process). This is a latent pre-existing race that the new waiter here would have made more likely; fixed withbroadcast().Testing
ClusterIdentityMetricsTest.test_cluster_info_metric: 3-broker cluster, asserts the metric appears on both endpoints of every broker and the label matches the admin API'sGET /v1/cluster/uuid.MetricsTest.test_aggregate_metricsnow excludescluster_infofrom its line counts, since the async registration could otherwise change the count between scrapes.Backports Required
signal()→broadcast()fix)signal()→broadcast()fix)Release Notes
Improvements
cluster_infogauge with acluster_uuidlabel, so Prometheus scrapes can uniquely identify the cluster without external labels.🤖 Generated with Claude Code
https://claude.ai/code/session_01E7sDG1E1hom3tZ2nd3FH2e