Skip to content

Native histograms: reconcile mismatched NHCB bounds in Add/Sub#17278

Merged
beorn7 merged 9 commits intoprometheus:mainfrom
linasm:nhcb-safe-add-sub
Oct 17, 2025
Merged

Native histograms: reconcile mismatched NHCB bounds in Add/Sub#17278
beorn7 merged 9 commits intoprometheus:mainfrom
linasm:nhcb-safe-add-sub

Conversation

@linasm
Copy link
Contributor

@linasm linasm commented Oct 3, 2025

Which issue(s) does the PR fix:

Fixes #17255

Does this PR introduce a user-facing change?

[ENHANCEMENT] `Add` and `Sub` methods called on NHCB histograms with different bucket bounds will no longer result in an error (which was resulting in query warning). Instead, observation counts in unmatched buckets on either side will be rolled up into the next matching bucket (which could be the `+Inf` serving as the last, catch all bucket).

@linasm linasm changed the title Native histograms: reconcile mismatched NHCB bounds in Add/Sub [ENHANCEMENT] Native histograms: reconcile mismatched NHCB bounds in Add/Sub Oct 3, 2025
@linasm linasm changed the title [ENHANCEMENT] Native histograms: reconcile mismatched NHCB bounds in Add/Sub Native histograms: reconcile mismatched NHCB bounds in Add/Sub Oct 3, 2025
@linasm linasm force-pushed the nhcb-safe-add-sub branch 2 times, most recently from 09841db to 9950ff1 Compare October 3, 2025 13:53
@linasm linasm marked this pull request as ready for review October 3, 2025 14:11
@linasm linasm requested a review from roidelapluie as a code owner October 3, 2025 14:11
@beorn7
Copy link
Member

beorn7 commented Oct 5, 2025

Thanks for this. As said, I do not have capacity for a detailed review right now (but maybe others have). I peeked at it, though, because it is very intriguing.

Just to clarify: From the PromQL perspective, this fixes all the cases where NHCB buckets are mismatched. (While the implementation happens in the Add/Sub methods, it helps for rate calculation and everything else, not just for + and - or the sum aggregation.) I'll change the PR's title so that people won't be confused later.

I have a lot of more strategic thoughts about this, which is more around how to release this (before/after declaring NH a stable feature, and how to do it if we do the latter) and if we should have annotation when buckets are reconciled. To not pollute the review of the actual implementation here, I'll add those thoughts to #17255.

@beorn7
Copy link
Member

beorn7 commented Oct 8, 2025

General note (not having looked at the code in detail, maybe it already works):

We also want to reconcile buckets for calculation of rate and friends.

This then leads to the problem of counter reset detection. So far, we considered each change of the custom values a counter reset. However, now we should just do the normal detection after buckets have been reconciled.

@beorn7
Copy link
Member

beorn7 commented Oct 8, 2025

About reset detection:

if h.UsesCustomBuckets() != previous.UsesCustomBuckets() || (h.UsesCustomBuckets() && !CustomBucketBoundsMatch(h.CustomValues, previous.CustomValues)) {
// Mark that something has changed or that the application has been restarted. However, this does
// not matter so much since the change in schema will be handled directly in the chunks and PromQL
// functions.
return true
needs an update to do the reconciliation of custom buckets and then detect the resets normally.

beorn7 added a commit to prometheus/docs that referenced this pull request Oct 8, 2025
We originally planned to not include this in the initial feature set.
But now prometheus/prometheus#17278 is
underway, so let's aim for it.

Signed-off-by: beorn7 <beorn@grafana.com>
@linasm linasm force-pushed the nhcb-safe-add-sub branch 4 times, most recently from b35fc4e to 397cf6c Compare October 9, 2025 10:02
@linasm
Copy link
Contributor Author

linasm commented Oct 9, 2025

In sum, let's keep it simple and safe and have an info level annotation whenever we merge NHCB buckets in any way.

I've added info level annotation, this is now ready for review.

needs an update to do the reconciliation of custom buckets and then detect the resets normally.

IIUC this is being implemented separately, in #17312?

@linasm linasm requested review from beorn7 and krajorama October 9, 2025 10:21
@beorn7
Copy link
Member

beorn7 commented Oct 9, 2025

In sum, let's keep it simple and safe and have an info level annotation whenever we merge NHCB buckets in any way.

I've added info level annotation, this is now ready for review.

Thanks. @krajorama or myself will have a look ASAP.

needs an update to do the reconciliation of custom buckets and then detect the resets normally.

IIUC this is being implemented separately, in #17312?

No, #17312 is a separate thing.

I think we just have to update the code I have linked above to handle NHCB specially and include the reconciliation logic. I don't have smart ideas right now how to do it in detail, but I think it should/could be part of this PR.

@linasm
Copy link
Contributor Author

linasm commented Oct 9, 2025

About reset detection:

if h.UsesCustomBuckets() != previous.UsesCustomBuckets() || (h.UsesCustomBuckets() && !CustomBucketBoundsMatch(h.CustomValues, previous.CustomValues)) {
// Mark that something has changed or that the application has been restarted. However, this does
// not matter so much since the change in schema will be handled directly in the chunks and PromQL
// functions.
return true

needs an update to do the reconciliation of custom buckets and then detect the resets normally.

I'm not sure I understand - IMHO a change in CustomValues is a symptom of code instrumentation change, which is enough to presume that the histogram has been reset, with or without the reconcillation? What do I miss here?

@beorn7
Copy link
Member

beorn7 commented Oct 9, 2025

I'm not sure I understand - IMHO a change in CustomValues is a symptom of code instrumentation change, which is enough to presume that the histogram has been reset, with or without the reconcillation? What do I miss here?

That was our reasoning so far, and it was OK because we would never really aggregate NHCBs with different custom values anyway. But now that we can, thanks to your efforts, I realized that there are other things that could happen. For example, somebody might decide to dynamically remove a bucket, without really resetting the underlying classic histogram. The ability of removing buckets from a cumulative histogram, even on the fly or later in storage, was sold as one of the big reasons to go cumulative back in the days… So I guess it could actually happen, or maybe is already doing this.

With the bucket reconciliation, we can now aggregate across those bucket changes, in particular calculating a rate over a timespan that includes the bucket removal. A false-positive in counter reset detection could wreak havoc with the result. (While previously, we would just not have returned a result at all and said "incompatible bucket layout".) So even if it might be rare, I do think we have to treat this correctly.

@krajorama
Copy link
Member

Heads up: #17312 was merged, hence the conflicts. @linasm

Signed-off-by: Linas Medziunas <linas.medziunas@gmail.com>
@krajorama
Copy link
Member

Sorry, DetectReset changes are not ready for review yet, but I should be able to take the comments above into account, anyway,

No worries, my algorithm probably isn't perfect either, it might skip buckets that are not used, so the loop most likely needs to iterate on the custom values (boundaries) like intersectCustomBucketBounds , but at the same time count those accumulators.

@linasm linasm force-pushed the nhcb-safe-add-sub branch from f048e97 to 938e2d4 Compare October 13, 2025 13:21
Signed-off-by: Linas Medziunas <linas.medziunas@gmail.com>
@linasm linasm force-pushed the nhcb-safe-add-sub branch from 938e2d4 to bfee24a Compare October 13, 2025 14:01
Signed-off-by: Linas Medziunas <linas.medziunas@gmail.com>
@linasm linasm force-pushed the nhcb-safe-add-sub branch from bfee24a to 82ac2af Compare October 13, 2025 14:02
@linasm
Copy link
Contributor Author

linasm commented Oct 13, 2025

@krajorama @beorn7 I've implemented counter reset detection based on reconciled buckets, O(n) complexity, no allocations.
@krajorama I've addressed your current feedback on this PR. This is now ready for further reviews.

@linasm linasm requested a review from krajorama October 13, 2025 17:10
Copy link
Member

@krajorama krajorama left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGMT, I'm suggesting a small change to reduce/simplify the code size a little bit. But after that I think this is ready for approve and merge from my side.

linasm and others added 2 commits October 15, 2025 09:28
Signed-off-by: Linas Medziunas <linas.medziunas@gmail.com>
Signed-off-by: Linas Medžiūnas <linasm@users.noreply.github.com>
@linasm linasm requested a review from krajorama October 15, 2025 06:31
@linasm
Copy link
Contributor Author

linasm commented Oct 15, 2025

@krajorama I've addressed your comments regarding custom bounds intersection loop. There was another comment about consistency that I'm not sure about (see my response inline).

@krajorama
Copy link
Member

@krajorama I've addressed your comments regarding custom bounds intersection loop. There was another comment about consistency that I'm not sure about (see my response inline).

Hi, I've elaborated on the comment. Not super important to be honest, as the result is the same, but I'd like to avoid confusion perhaps years from now.

Signed-off-by: Linas Medziunas <linas.medziunas@gmail.com>
Copy link
Member

@krajorama krajorama left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved

@beorn7
Copy link
Member

beorn7 commented Oct 15, 2025

Will give this a final pass ASAP. Thank you both of you for the epic work so far.

Copy link
Member

@beorn7 beorn7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great. Just a minor suggestion to improve the wording of the info annotation.

And maybe there could be tests that calculate non-trivial rates (i.e. one with a bunch of buckets in the result) involving bucket reconciliation, one with a reset and one without a reset?

beorn7 added a commit to prometheus/docs that referenced this pull request Oct 16, 2025
We originally planned to not include this in the initial feature set.
But now prometheus/prometheus#17278 is
underway, so let's aim for it.

Signed-off-by: beorn7 <beorn@grafana.com>
Signed-off-by: Linas Medziunas <linas.medziunas@gmail.com>
Signed-off-by: Linas Medziunas <linas.medziunas@gmail.com>
@linasm
Copy link
Contributor Author

linasm commented Oct 17, 2025

@beorn7 I've addressed your feedback:

  1. Updated info message as suggested.
  2. Added panic in case of non-NHCB arguments, updated the comments, additionally updated method name to make the contract more obvious.
  3. Added a few more sophisticated tests. Note that I have used irate(foo[2m]) * 60 to eliminate any extrapolation effects which were making query results too hard to reason about (at least for me). Hope you won't mind introducing this pattern that seems to be new here (or maybe there is a better approach?).

Copy link
Member

@beorn7 beorn7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent. Let's ship it!

@beorn7 beorn7 merged commit 44df626 into prometheus:main Oct 17, 2025
28 checks passed
crush-on-anechka added a commit to crush-on-anechka/prometheus that referenced this pull request Nov 20, 2025
… improved custom bucket mismatch handling)

Signed-off-by: Aleksandr Smirnov <5targazer@mail.ru>
crush-on-anechka added a commit to crush-on-anechka/prometheus that referenced this pull request Nov 20, 2025
… improved custom bucket mismatch handling)

Signed-off-by: Aleksandr Smirnov <5targazer@mail.ru>
crush-on-anechka added a commit to crush-on-anechka/prometheus that referenced this pull request Feb 5, 2026
… improved custom bucket mismatch handling)

Signed-off-by: Aleksandr Smirnov <5targazer@mail.ru>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

promql: NHCB operations should support different bucket layouts

3 participants