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

Store: store responses should always be sorted #6706

Merged

Conversation

MichaHoffmann
Copy link
Contributor

@MichaHoffmann MichaHoffmann commented Sep 6, 2023

  • I added CHANGELOG entry for this change.
  • Change is not relevant to the end user.

Changes

  • always resort store responses
  • compare labelsets without dropping replica labels in proxy heap

Verification

Not verified yet

@MichaHoffmann MichaHoffmann force-pushed the mhoffm-proxy-heap-sorting-issue-2 branch 4 times, most recently from c285a43 to 882e417 Compare September 6, 2023 15:58
@pull-request-size pull-request-size bot added size/L and removed size/M labels Sep 6, 2023
@vCra
Copy link

vCra commented Sep 6, 2023

Tested this out in our test environment:

After deployment number of 422s and 503s disappear completely

image

And we no longer see any of the Error executing query: vector cannot contain metrics with the same labelset issues seen in #6677

@tekicode
Copy link

tekicode commented Sep 6, 2023

Thanks for your effort on this PR @MichaHoffmann I'm running this in our testing environment as well and the labelset error I reported in #6677 is resolved

saswatamcode
saswatamcode previously approved these changes Sep 7, 2023
Copy link
Member

@saswatamcode saswatamcode left a comment

Choose a reason for hiding this comment

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

LGTM, seems like this also preserves the optimization

@fpetkovski @GiedriusS maybe we can merge and cut a patch?

pkg/store/bucket.go Outdated Show resolved Hide resolved
@GiedriusS
Copy link
Member

GiedriusS commented Sep 7, 2023

Thanks for working on this but I think that this is a wrong approach to take because it just papers over the problem namely that StoreAPIs don't uphold the invariant of sending a sorted response set. I think that for project's long term health we should focus our efforts toward fixing that.

I think this is related: prometheus/prometheus#12605. This is because we actually implement a very similar logic regards external labels.

Essentially, I think that external labels functionality breaks this invariant when the internal TSDB has overlapping labels with different values. Everywhere we use this logic:

  • Select() or, in other words, get a sorted series set
  • Overwrite labels with the external labels

But if the 1st operation has a mix of time series with and without labels that are part of external labels, problems might ensue. Because time series with less labels come before those with more labels, it means that the end result might be unsorted if the first series in the result do not have external labels in the TSDB and the latter ones do.

I'm a bit busy but I could try writing a test for this case in all components to show what I'm talking about. I'll try to do that over the next few working days.

Also, I think it's correct to only compare raw labels and the previous change regarding comparing external labels first tries to workaround the same problem that I mentioned here

@MichaHoffmann
Copy link
Contributor Author

Just to state: I didnt intend this as the solution to the problem; more as a short term ad-hoc fix so we can uphold the invariant and solve the problem properly in subsequent PRs.

@GiedriusS
Copy link
Member

It's all good, no worries. I was thinking about this and perhaps this problem could be temporarily fixed by forcing resorting if there's an intersection between the external labelset and the label names filter? This would allow us to check if such a possibility is even possible before starting to read the series.

@MichaHoffmann
Copy link
Contributor Author

MichaHoffmann commented Sep 7, 2023

It's all good, no worries. I was thinking about this and perhaps this problem could be temporarily fixed by forcing resorting if there's an intersection between the external labelset and the label names filter? This would allow us to check if such a possibility is even possible before starting to read the series.

If we get respSet A and B we would need to check if labelnames of store B intersect extlabels of A and vice versa; in which case we would need to resort i think. But that seems way more complicated then forcing sort on store APIs for first iteration

@douglascamata
Copy link
Contributor

douglascamata commented Sep 7, 2023

Could we commit to merging this as a hotfix and work on improvements or a "proper fix" in follow ups? This dedup issue is plaguing Thanos releases since 6 months, blocking many people out there from upgrading to take advantage of new features because of uncertainty to whether there will be issues or not with queries. Nobody will care if the memory improvements introduced by the big query sorting change are completely negated for them to be able to always have correct query results and the ability to upgrade their Thanos. Query dedup logic is clearly broken and it has to be fixed. Query accuracy is a pilar of any observability software.

@MichaHoffmann is putting a lot of hard effort and time into this working on fixes, automated tests, testing things in general, etc. I'm sure he has many plans or ideas to improve this further down the line. Others could and are very welcome to help too.

But let's get this working first, shall we? We gotta move forward and, most importantly, move over this bug.

pkg/store/flushable.go Outdated Show resolved Hide resolved
@GiedriusS
Copy link
Member

We've moved this discussion a bit into #prometheus-dev. It seems like in most cases it is not safe to extend a sorted series set with external labels because it might lead an unsorted series set. Maybe someone will have some ideas there. In general it looks like external labels is a broken functionality. Anyway... if nothing comes up, we will probably be forced to revert back buffering and resorting in the querier :'/

@fpetkovski
Copy link
Contributor

Isn't it better to resort in the store instead of centralizing a compute intensive operation in a single component?

@MichaHoffmann
Copy link
Contributor Author

Isn't it better to resort in the store instead of centralizing a compute intensive operation in a single component?

The worry is that sidecar gets expensive i think. We could introduce a slight expansion of the protocol where we generally assume that store responses are sorted except if we get a hint that its not ( and sidecar would send that hint maybe )

@fpetkovski
Copy link
Contributor

It would be great if we can leave this out to the user to decide. Our performance will drop significantly if we had to sort in the querier again.

@MichaHoffmann
Copy link
Contributor Author

It would be great if we can leave this out to the user to decide. Our performance will drop significantly if we had to sort in the querier again.

I added a sortingStrategy thats currently hard coded in the different stores. I would like to move making it configurable ( to opt-out or to sort in the querier if wanted ) into a followup PR though since strictly speaking its an optimziation and this is already getting kinda big

@GiedriusS
Copy link
Member

Adding test on Prometheus side to show the issue: prometheus/prometheus#12822.


const (
sortingStrategyStore sortingStrategy = iota + 1
sortingStrategyNone
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we want a sortingStrategyQuery?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah i wanted to add it in followup pr

}
// NOTE. Client is not guaranteed to give a sorted response when extLset is added
// Generally we need to resort here.
sortWithoutLabels(l.bufferedResponses, l.removeLabels)
Copy link
Contributor

Choose a reason for hiding this comment

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

Hm, does it mean we will resort again in the querier? Maybe we want the strategy to be set in the querier and propagated to the store. This way we can decide in both places whether to resort or not.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Querier should use lazyresponse set always right?

Copy link
Contributor

Choose a reason for hiding this comment

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

As I understand it, if sorting strategy querier, then we need to use eager in the querier and stream from the store. Not sure if that gets added as a follow up though.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah yeah but if we use querier sorting strategy we should resort here i think; otherwise we could use sorting strategy none right?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, so:

  • sorting strategy querier = eager in querier, lazy in stores.
  • sorting strategy store = eager in store, lazy in querier.

Copy link
Contributor

Choose a reason for hiding this comment

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

yeah precisely ( but i would like to add querier later since its more complicated change )

Copy link
Member

Choose a reason for hiding this comment

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

Agreed, we will need this but maybe for a separate PR.

@MichaHoffmann
Copy link
Contributor Author

@GiedriusS is this PR acceptable?

Copy link
Member

@GiedriusS GiedriusS left a comment

Choose a reason for hiding this comment

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

Let's also remove the paragraph https://thanos.io/tip/components/query.md/#deduplication-on-non-external-labels from here regarding cuckoo filter

@@ -1334,7 +1329,8 @@ func debugFoundBlockSetOverview(logger log.Logger, mint, maxt, maxResolutionMill

// Series implements the storepb.StoreServer interface.
func (s *BucketStore) Series(req *storepb.SeriesRequest, seriesSrv storepb.Store_SeriesServer) (err error) {
srv := newFlushableServer(seriesSrv, s.LabelNamesSet(), req.WithoutReplicaLabels)
srv := newFlushableServer(seriesSrv, sortingStrategyNone)
Copy link
Member

Choose a reason for hiding this comment

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

Why doesn't this need resorting? 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

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

block responses are sorted because of eager retrieval there; basically we put sorted stuff in dedup proxy heap and get sorted series set back out and dont need to sort it again before returning it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

all the dropping and extlabel juggling is done on block level already so after we joined it we can just pass it along

mhoffm-aiven and others added 3 commits September 14, 2023 15:55
Signed-off-by: Michael Hoffmann <mhoffm@posteo.de>
Signed-off-by: Michael Hoffmann <mhoffm@posteo.de>
This is the wrong approach to detect if we need to resort. It cannot
detect if we might end up with an unsorted series set if we add
extLabels.

Signed-off-by: Michael Hoffmann <mhoffm@posteo.de>
@MichaHoffmann MichaHoffmann force-pushed the mhoffm-proxy-heap-sorting-issue-2 branch from 16439df to 2a10d70 Compare September 14, 2023 13:55
Signed-off-by: Michael Hoffmann <mhoffm@posteo.de>
Copy link
Contributor

@fpetkovski fpetkovski left a comment

Choose a reason for hiding this comment

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

Given all the edge cases we have ran into so far, I don't see other options than to eventually resort the dataset.

Copy link
Member

@saswatamcode saswatamcode left a comment

Choose a reason for hiding this comment

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

LGTM!

@saswatamcode saswatamcode merged commit 931439b into thanos-io:main Sep 15, 2023
16 checks passed
coleenquadros pushed a commit to coleenquadros/thanos that referenced this pull request Sep 18, 2023
* Store: always sort, just compare labelset in proxy heap

Signed-off-by: Michael Hoffmann <mhoffm@posteo.de>

* Store: add escape hatch to skip store resorting

Signed-off-by: Michael Hoffmann <mhoffm@posteo.de>

* Store: remove stringset

This is the wrong approach to detect if we need to resort. It cannot
detect if we might end up with an unsorted series set if we add
extLabels.

Signed-off-by: Michael Hoffmann <mhoffm@posteo.de>

* Docs: drop paragraph about deduplication on inner labels

Signed-off-by: Michael Hoffmann <mhoffm@posteo.de>

---------

Signed-off-by: Michael Hoffmann <mhoffm@posteo.de>
Co-authored-by: Michael Hoffmann <michael.hoffmann@aiven.io>
coleenquadros pushed a commit to coleenquadros/thanos that referenced this pull request Sep 18, 2023
* Store: always sort, just compare labelset in proxy heap

Signed-off-by: Michael Hoffmann <mhoffm@posteo.de>

* Store: add escape hatch to skip store resorting

Signed-off-by: Michael Hoffmann <mhoffm@posteo.de>

* Store: remove stringset

This is the wrong approach to detect if we need to resort. It cannot
detect if we might end up with an unsorted series set if we add
extLabels.

Signed-off-by: Michael Hoffmann <mhoffm@posteo.de>

* Docs: drop paragraph about deduplication on inner labels

Signed-off-by: Michael Hoffmann <mhoffm@posteo.de>

---------

Signed-off-by: Michael Hoffmann <mhoffm@posteo.de>
Co-authored-by: Michael Hoffmann <michael.hoffmann@aiven.io>
saswatamcode pushed a commit to saswatamcode/thanos that referenced this pull request Sep 20, 2023
* Store: always sort, just compare labelset in proxy heap

Signed-off-by: Michael Hoffmann <mhoffm@posteo.de>

* Store: add escape hatch to skip store resorting

Signed-off-by: Michael Hoffmann <mhoffm@posteo.de>

* Store: remove stringset

This is the wrong approach to detect if we need to resort. It cannot
detect if we might end up with an unsorted series set if we add
extLabels.

Signed-off-by: Michael Hoffmann <mhoffm@posteo.de>

* Docs: drop paragraph about deduplication on inner labels

Signed-off-by: Michael Hoffmann <mhoffm@posteo.de>

---------

Signed-off-by: Michael Hoffmann <mhoffm@posteo.de>
Co-authored-by: Michael Hoffmann <michael.hoffmann@aiven.io>
saswatamcode added a commit that referenced this pull request Sep 20, 2023
* Update thanos engine and Prometheus dependencies (#6664)

* Update thanos engine and Prometheus dependencies

This commit bumps thanos/promql-engine to latest main and resolves
breaking changes from the prometheus/prometheus dependency.

Signed-off-by: Filip Petkovski <filip.petkovsky@gmail.com>

* Add changelog entry

Signed-off-by: Filip Petkovski <filip.petkovsky@gmail.com>

* Avoid closing head more than once

Signed-off-by: Filip Petkovski <filip.petkovsky@gmail.com>

* Remove call to t.TempDir()

Signed-off-by: Filip Petkovski <filip.petkovsky@gmail.com>

---------

Signed-off-by: Filip Petkovski <filip.petkovsky@gmail.com>

* build(deps): bump github.com/prometheus/alertmanager (#6671)

Bumps [github.com/prometheus/alertmanager](https://github.com/prometheus/alertmanager) from 0.25.0 to 0.25.1.
- [Release notes](https://github.com/prometheus/alertmanager/releases)
- [Changelog](https://github.com/prometheus/alertmanager/blob/v0.25.1/CHANGELOG.md)
- [Commits](prometheus/alertmanager@v0.25.0...v0.25.1)

---
updated-dependencies:
- dependency-name: github.com/prometheus/alertmanager
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* store: add acceptance tests for label methods to bucket store (#6668)

Signed-off-by: Michael Hoffmann <mhoffm@posteo.de>

* Ruler: Add update label names routine for stateful ruler (#6689)

Signed-off-by: Saswata Mukherjee <saswataminsta@yahoo.com>

* Store: add some acceptance tests for label matching (#6691)

Signed-off-by: Michael Hoffmann <mhoffm@posteo.de>

* Store: fix regex matching with set that matches empty (#6692)

Signed-off-by: Michael Hoffmann <mhoffm@posteo.de>

* Store: add failing test for potential dedup issue (#6693)

Signed-off-by: Michael Hoffmann <mhoffm@posteo.de>

* Store: fix block dedup (#6697)

Signed-off-by: Michael Hoffmann <mhoffm@posteo.de>

* Add Shipper bytes uploaded metric #6438 (#6544)

* [FEAT] Add uploaded bytes metric

Signed-off-by: rita.canavarro <rita.canavarro@farfetch.com>

* [FEAT] Add PR number to log

Signed-off-by: rita.canavarro <rita.canavarro@farfetch.com>

* [FIX] Log msg

Signed-off-by: rita.canavarro <rita.canavarro@farfetch.com>

* [FEAT] Clean code

Signed-off-by: rita.canavarro <rita.canavarro@farfetch.com>

* [FIX] Remove shadow code

Signed-off-by: rita.canavarro <rita.canavarro@farfetch.com>

* [FIX] Go format

Signed-off-by: rita.canavarro <rita.canavarro@farfetch.com>

* [FEAT] Update objstore

Signed-off-by: rita.canavarro <rita.canavarro@farfetch.com>

* [FEAT] Update objstore package

Signed-off-by: rita.canavarro <rita.canavarro@farfetch.com>

* [FEAT] Update storage.md

Signed-off-by: rita.canavarro <rita.canavarro@farfetch.com>

* [FEAT] Update erroring bucket

Signed-off-by: rita.canavarro <rita.canavarro@farfetch.com>

* [FEAT] Update erroring bucket

Signed-off-by: rita.canavarro <rita.canavarro@farfetch.com>

---------

Signed-off-by: rita.canavarro <rita.canavarro@farfetch.com>

* Update objstore library to latest main (#6722)

This commit updates the obstore library to the latest main version
which optimizes the Iter operation to only request object names.

Signed-off-by: Filip Petkovski <filip.petkovsky@gmail.com>

* Store: store responses should always be sorted (#6706)

* Store: always sort, just compare labelset in proxy heap

Signed-off-by: Michael Hoffmann <mhoffm@posteo.de>

* Store: add escape hatch to skip store resorting

Signed-off-by: Michael Hoffmann <mhoffm@posteo.de>

* Store: remove stringset

This is the wrong approach to detect if we need to resort. It cannot
detect if we might end up with an unsorted series set if we add
extLabels.

Signed-off-by: Michael Hoffmann <mhoffm@posteo.de>

* Docs: drop paragraph about deduplication on inner labels

Signed-off-by: Michael Hoffmann <mhoffm@posteo.de>

---------

Signed-off-by: Michael Hoffmann <mhoffm@posteo.de>
Co-authored-by: Michael Hoffmann <michael.hoffmann@aiven.io>

* Updates busybox SHA (#6724)

Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: fpetkovski <fpetkovski@users.noreply.github.com>

* Cut patch release v0.32.3

Signed-off-by: Saswata Mukherjee <saswataminsta@yahoo.com>

---------

Signed-off-by: Filip Petkovski <filip.petkovsky@gmail.com>
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Michael Hoffmann <mhoffm@posteo.de>
Signed-off-by: Saswata Mukherjee <saswataminsta@yahoo.com>
Signed-off-by: rita.canavarro <rita.canavarro@farfetch.com>
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: Filip Petkovski <filip.petkovsky@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Michael Hoffmann <mhoffm@posteo.de>
Co-authored-by: Rita Canavarro <98762287+ritaCanavarro@users.noreply.github.com>
Co-authored-by: Michael Hoffmann <michael.hoffmann@aiven.io>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: fpetkovski <fpetkovski@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

9 participants