-
Notifications
You must be signed in to change notification settings - Fork 453
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
[dbnode] Use ref to segment data for index results instead of alloc each #1839
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1839 +/- ##
==========================================
- Coverage 72.8% 63.6% -9.3%
==========================================
Files 1006 1123 +117
Lines 86671 107039 +20368
==========================================
+ Hits 63099 68079 +4980
- Misses 19360 34603 +15243
- Partials 4212 4357 +145
Continue to review full report at Codecov.
|
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.
This looks ok to me although it would be nice if there was a place where you documented this entire lifecycle end-to-end so we don't have to piece it together manually next time we need to understand it
src/dbnode/server/server.go
Outdated
zap.Error(err), | ||
) | ||
} | ||
// if err := bsGauge.UpdateStringList(bootstrappers); err != nil { |
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.
did you mean to disable this?
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.
Yeah this is meant to be re-enabled but it was crashing and I needed to test, I'll re-enable when it's fixed on master.
src/dbnode/storage/index/block.go
Outdated
docsPool.Put(batch) | ||
}() | ||
|
||
// Register the executor to close when context closes | ||
// so can copy the results. |
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.
This comment is a little confusing. I would assume you'd want to register it to the context so you dont have to copy it. Could you maybe clarify?
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.
Correct, I think I mean to say "so we can avoid copying the results". Honestly I hadn't cleaned all this up yet.
@@ -865,10 +871,6 @@ func (b *block) queryWithSpan( | |||
return false, err | |||
} | |||
|
|||
if err := execCloser.Close(); err != nil { |
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.
lol interesting, did we have a double close?
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.
Oh nah, this got moved to the context closing it when it closes. (SafeCloser wraps the exec close call and prevents it from being double closed, so the two calls existing wasn't an issue).
// the tsID's bytes. | ||
r.resultsMap.Set(tsID, tags) | ||
// It is assumed that the document is valid for the lifetime of the index | ||
// results. |
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.
Can this comment somehow explain or point to the context stuff and an explanation of that?
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.
Yeah, I'm trying to find the best place to document that.
}, nil | ||
} | ||
|
||
// NB(r): The segment uses the context finalization to finalize |
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.
This might be a good place to explain the general approach and how it interacts with outstanding queries
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.
Sure yeah.
Is there a container with this patch available on a public repo? I want tot test it out. |
@mstump about to merge and cut release in next few hours 👍 |
@mstump let me just build a container for this change. |
@mstump here's a container for this branch:
|
src/dbnode/encoding/m3tsz/encoder.go
Outdated
func (enc *encoder) Stream(opts encoding.StreamOptions) (xio.SegmentReader, bool) { | ||
segment := enc.segment(byCopyResultType) | ||
func (enc *encoder) Stream( | ||
ctx context.Context, |
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.
Take it or leave it, but it could be nice to make the zeroCopy
behavior optional via the encoding.StreamOptions
and put the context in their too so that we don't have to pollute this API (and create a context everytime we want to do this even when we dont need zero copy)
@@ -229,23 +230,24 @@ func (m *merger) Merge( | |||
// Closing the context will finalize the data returned from | |||
// mergeWith.Read(), but is safe because it has already been persisted | |||
// to disk. | |||
tmpCtx.BlockingClose() | |||
// NB(r): Make sure to use BlockingCloseReset so can reuse the context. |
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.
isnt the reset handled by the reset right before the call to mergeWith.Read()
?
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.
Yeah the main thing we avoid using BlockingCloseReset()
is to avoid the context going back to the pool. (i.e. the Reset as the suffix means, after closing do not put back in the pool, we explicitly want to reuse this context).
And the main reason need to use a pooled context here is since the context needs to refer to the pooled finalizers linked list now, or else it will allocate a ton in between uses in this tight loop.
@mstump I published a new container with the latest changes for testing:
|
It looks like the container only has the coordinator binary and doesn't have
|
@mstump yeah that is weird, I noticed that. I use the wrong dockerfile as I'd just prepared a coordinator image before. Here's a working one:
|
OK I got it deployed a day or two ago but didn't have time to test until just now.
The workload is essentially CSV export for all metrics of a cluster at 1m granularity for a 60m time period. It's about 2-3k time series and the query looks like the following.
Screen cap from load test |
I should also mention that it's only 10 concurrent queries from this job. There is an additional baseline load resulting in 10k tagged RPC writes per second, and 6 analytical queries per second (7d queries over a 1h aggregated namespace) which are fronted by a dedicated query tier. |
I repeated the test with a single thread of execution and it's still enough to cause nodes to go unresponsive. |
With the 1 concurrent query test I removed load as soon as the nodes started to go unresponsive. The only message of note has to do with etcd. I checked etcd memory and CPU utilization during that time-frame and it was nominal maxing out at 67MB of memory and .015 CPU.
|
@mstump cant comment on the the actual performance since this was Rob's work but the etcd stuff is usually a red herring. Usually it just means the node is under heavy load and as a result connections to etcd get broken and need to be re-established |
fdbef61
to
0c6a0fe
Compare
* Make bytesRef finalization called by RefCount Finalize call
3674995
to
3e9511b
Compare
What this PR does / why we need it:
This greatly reduces the memory allocation usage when querying the index as it ensures the lifetime of the segment survives the query and returns just references to the index data.
Special notes for your reviewer:
Does this PR introduce a user-facing and/or backwards incompatible change?:
Does this PR require updating code package or user-facing documentation?: