-
Notifications
You must be signed in to change notification settings - Fork 828
Expose a metric tracking the oldest timestamp of unshipper block in ingester #3705
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
Expose a metric tracking the oldest timestamp of unshipper block in ingester #3705
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, but I'd like to see your take on caching the value instead.
pkg/ingester/ingester_v2.go
Outdated
// Read the list of shipper blocks. If the shipper metadata file doesn't exist | ||
// (eg. because the shipper hasn't run yet) we're considering it as if no block | ||
// has been shipped. | ||
shipped, err := u.getShippedBlocks() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getShippedBlocks
is used twice, each time we build a map from it. Perhaps getShippedBlocks
should build and return map directly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
blocksToDelete()
doesn't build a map of out getShipperBlocks()
. It just iterates over it.
pkg/ingester/ingester_v2.go
Outdated
|
||
oldest := uint64(0) | ||
for _, db := range i.TSDBState.dbs { | ||
if ts, err := db.getOldestUnshippedBlockTime(); err == nil && (oldest == 0 || ts < oldest) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of computing this value on each metric collection, should we cache it and update after each call to the shipper? As it is now, each metric collection needs to read shipper json file for each tenant, which could be slow if there are many tenants.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can benchmark it and then we can decide if extra complexity is worth it. But agree checking it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've written a simple benchmark (commit) and on my MacBook it takes 31μs/op. If you have 1K tenants, it would be 31ms. I've the feeling caching for it, at this stage, would just be premature optimisation.
BenchmarkUserTSDB_getOldestUnshippedBlockTime-12 37930 30898 ns/op 4486 B/op 26 allocs/op
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a valid benchmark? On a busy server getOldestUnshippedBlockTime
will not benefit from heavy caching of all IO operations as much as it does in this standalone test.
I don't think it would be a premature optimization, just a better approach. For 1K tenants, current approach needs to open/read/close 1000 files on each metric collection (=3000 syscalls). Instead we could simply read one atomic variable per tenant, and update it only when it can actually change. I don't see it as "premature optimization".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1, I share concern this could be pretty inefficient for large number of tenants.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, got it. I pushed a change to keep the shipped blocks in memory (they're tiny) and reload them each time any block is uploaded. I've also took the opportunity to improve the tests to not use a mocked shipper but the real one backed by a filesystem bucket.
What do you think?
ffab7ac
to
9447e9a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for doing this, functionally, in terms of the metric exported it looks good to me, but I second pstibrany's concern about the cost of calculating the metric at scrape time so would prefer the alternative implementation suggested.
pkg/ingester/ingester_v2.go
Outdated
|
||
oldest := uint64(0) | ||
for _, db := range i.TSDBState.dbs { | ||
if ts, err := db.getOldestUnshippedBlockTime(); err == nil && (oldest == 0 || ts < oldest) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1, I share concern this could be pretty inefficient for large number of tenants.
@@ -68,6 +68,7 @@ | |||
* [ENHANCEMENT] Distributor: change the error message returned when a received series has too many label values. The new message format has the series at the end and this plays better with Prometheus logs truncation. #3718 | |||
- From: `sample for '<series>' has <value> label names; limit <value>` | |||
- To: `series has too many labels (actual: <value>, limit: <value>) series: '<series>'` | |||
* [ENHANCEMENT] Ingester: exposed metric `cortex_ingester_oldest_unshipped_block_timestamp_seconds`, tracking the unix timestamp of the oldest TSDB block not shipped to the storage yet. #3705 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We've just released 1.7.0-rc.0
. Could you rebase master
and move the CHANGELOG entry under the master / unreleased
section, please?
9447e9a
to
6318f48
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the update.
pkg/ingester/ingester_v2.go
Outdated
shipTicker := time.NewTicker(i.cfg.BlocksStorageConfig.TSDB.ShipInterval) | ||
// We add a slight jitter to make sure that if the head compaction interval and ship interval are set to the same | ||
// value they don't clash (if they both continuously run at the same exact time, the head compaction may not run | ||
// because can't successfully cas the state). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean by "cas the state"? Not sure if I'm confused about a term I don't know or a typo ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By cas I mean "Compare And Swap" (we have a function called casState()
). Maybe "CAS" (upper case) is more clear? Should I explode it to "compare and swap"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Thanks!
Also nice cleanup in the tests!
…ngester Signed-off-by: Marco Pracucci <marco@pracucci.com>
Signed-off-by: Marco Pracucci <marco@pracucci.com>
Signed-off-by: Marco Pracucci <marco@pracucci.com>
Signed-off-by: Marco Pracucci <marco@pracucci.com>
Signed-off-by: Marco Pracucci <marco@pracucci.com>
74f2715
to
2866e6b
Compare
Signed-off-by: Marco Pracucci <marco@pracucci.com>
What this PR does:
Currently, there's no way to alert if any compacted block is not shipped from ingester to storage within a reasonable time. In this PR I'm proposing to introduce a new metric
cortex_ingester_oldest_unshipped_block_timestamp_seconds
tracking the unix timestamp of the oldest TSDB block not shipped to the storage yet.Which issue(s) this PR fixes:
N/A
Checklist
CHANGELOG.md
updated - the order of entries should be[CHANGE]
,[FEATURE]
,[ENHANCEMENT]
,[BUGFIX]