kvserver: rework memory allocation in replicastats#86592
kvserver: rework memory allocation in replicastats#86592craig[bot] merged 2 commits intocockroachdb:masterfrom
Conversation
914e0bc to
9522702
Compare
9522702 to
afe67ec
Compare
irfansharif
left a comment
There was a problem hiding this comment.
Reducing the size of the struct like we've done is good, but the total count of objects allocated is important which can cause undue lot of pressure on the Go GC. It seems that for every *ReplicaStats object we have 6 underlying *replicaStatsRecord objects.
cockroach/pkg/kv/kvserver/replicastats/replica_stats.go
Lines 145 to 147 in 8b03aea
Also for every *Replica on a store, we have 6 *ReplicaStats objects.
cockroach/pkg/kv/kvserver/replica_load.go
Lines 36 to 43 in afe67ec
So that's a multiplier of 6*6=36 objects per replica. Could we get this down to just one object allocated per-replica? I suspect that's the bottleneck more than the size of each object itself.
Reviewable status:
complete! 0 of 0 LGTMs obtained (waiting on @lidorcarmel)
lidorcarmel
left a comment
There was a problem hiding this comment.
Reviewed 2 of 2 files at r1, 1 of 1 files at r2, all commit messages.
Reviewable status:complete! 0 of 0 LGTMs obtained (waiting on @kvoli)
pkg/kv/kvserver/replicastats/replica_stats.go line 104 at r1 (raw file):
// mergeReplicaStatsRecords combines two records and returns a new record with // the merged data. When this is called with nil records, a nil record is
update the comment? at least replace nil with "inactive" or something like that.
pkg/kv/kvserver/replicastats/replica_stats.go line 107 at r1 (raw file):
// returned; otherwise a new record instead. func (rsr *replicaStatsRecord) mergeReplicaStatsRecords(other *replicaStatsRecord) { if !rsr.active && !other.active {
can this ever happen? I think no but maybe I'm missing something.
pkg/kv/kvserver/replicastats/replica_stats.go line 115 at r1 (raw file):
} if !other.active {
I think these 2 if statements are also not needed? because we will always reset when deactivating?
Code quote:
if !rsr.active {
rsr.reset()
}
if !other.active {
other.reset()
}pkg/kv/kvserver/replicastats/replica_stats.go line 120 at r1 (raw file):
rsr.sum += other.sum rsr.active = true
btw in the old behavior we "activated" other.. right? so this is different. this new behavior makes more sense to me though.
pkg/kv/kvserver/replicastats/replica_stats.go line 210 at r1 (raw file):
if !rs.Mu.records[i].active { other.Mu.records[i].reset() other.Mu.records[i].active = false
reset() will already set active to false, right? so maybe drop this line?
can we simplify things by having activate() and deactivate() or something like that? I feel like I need to track reset() together with active which is error prone.
afe67ec to
41e4313
Compare
kvoli
left a comment
There was a problem hiding this comment.
I agree we should reconsider the structure - however I'm opting to not move to this single object model yet. I don't think it would address the OOM issue that motivated this change and I would rather put in a smaller fix here.
Reviewable status:
complete! 0 of 0 LGTMs obtained (waiting on @irfansharif and @lidorcarmel)
pkg/kv/kvserver/replicastats/replica_stats.go line 104 at r1 (raw file):
Previously, lidorcarmel (Lidor Carmel) wrote…
update the comment? at least replace nil with "inactive" or something like that.
Updated.
pkg/kv/kvserver/replicastats/replica_stats.go line 107 at r1 (raw file):
Previously, lidorcarmel (Lidor Carmel) wrote…
can this ever happen? I think no but maybe I'm missing something.
This can happen - it's possible that either has only gone through < 6 windows, in which case they would be inactive.
The logic is bloated however, I've updated to make this clearer.
pkg/kv/kvserver/replicastats/replica_stats.go line 115 at r1 (raw file):
Previously, lidorcarmel (Lidor Carmel) wrote…
I think these 2 if statements are also not needed? because we will always reset when deactivating?
Updated - see above.
pkg/kv/kvserver/replicastats/replica_stats.go line 210 at r1 (raw file):
Previously, lidorcarmel (Lidor Carmel) wrote…
reset() will already set active to false, right? so maybe drop this line?
can we simplify things by having
activate()anddeactivate()or something like that? I feel like I need to trackreset()together withactivewhich is error prone.
Good idea. Updated.
lidorcarmel
left a comment
There was a problem hiding this comment.
consider filing a short issue about this so we don't forget (unless you can send the pr soon).
Reviewed 3 of 3 files at r3, 1 of 1 files at r4, all commit messages.
Reviewable status:complete! 0 of 0 LGTMs obtained (waiting on @irfansharif and @kvoli)
pkg/kv/kvserver/replicastats/replica_stats.go line 107 at r1 (raw file):
Previously, kvoli (Austen) wrote…
This can happen - it's possible that either has only gone through < 6 windows, in which case they would be inactive.
The logic is bloated however, I've updated to make this clearer.
thanks!
pkg/kv/kvserver/replicastats/replica_stats.go line 78 at r3 (raw file):
syncutil.Mutex idx int // the window records are initialized once, then each window is reused
s/the/The/ :)
and a double space on the next line (I missed those!)
thanks for the comment btw.
Code quote:
thepkg/kv/kvserver/replicastats/replica_stats.go line 103 at r3 (raw file):
// values to avoid churning memory. We could also delete elements that // haven't been seen in a while, however it makes no difference as the // memory wouldn't be released (https://github.com/golang/go/issues/20135).
nice!
Code quote:
// haven't been seen in a while, however it makes no difference as the
// memory wouldn't be released (https://github.com/golang/go/issues/20135).
// To protect against a memory leak, where many unused localities
// accumulate, create a new map if the number of unused localities was
// greater than 1.pkg/kv/kvserver/replicastats/replica_stats.go line 240 at r3 (raw file):
continue } // Otherwise, active the rhs record and split the request count between
s/active/activate/ probably?
Code quote:
active 4cebeec to
0bb69c9
Compare
This patch removes some unused fields within the replica stats object. It also opts to allocate all the memory needed upfront for a replica stats object for better cache locality and less GC overhead. resolves cockroachdb#85112 Release justification: low risk, lowers memory footprint to avoid oom. Release note: None
Previously, every replica throughput tracker in `replica_load` would track the request locality. Only batch requests used this locality for follow-the-workload leaseholder transfers. This patch removes locality tracking for the other throughput trackers to reduce per-replica memory footprint. Release justification: Low risk, high benefit change to reduce memory overhead in multi-region clusters. Release note: None
0bb69c9 to
5e91ca5
Compare
kvoli
left a comment
There was a problem hiding this comment.
Reviewable status:
complete! 0 of 0 LGTMs obtained (waiting on @irfansharif, @kvoli, and @lidorcarmel)
pkg/kv/kvserver/replicastats/replica_stats.go line 107 at r1 (raw file):
Previously, lidorcarmel (Lidor Carmel) wrote…
thanks!
updated
pkg/kv/kvserver/replicastats/replica_stats.go line 120 at r1 (raw file):
Previously, lidorcarmel (Lidor Carmel) wrote…
btw in the old behavior we "activated" other.. right? so this is different. this new behavior makes more sense to me though.
yeah - changed to be more logical.
pkg/kv/kvserver/replicastats/replica_stats.go line 78 at r3 (raw file):
Previously, lidorcarmel (Lidor Carmel) wrote…
s/the/The/ :)
and a double space on the next line (I missed those!)thanks for the comment btw.
fixed.
pkg/kv/kvserver/replicastats/replica_stats.go line 240 at r3 (raw file):
Previously, lidorcarmel (Lidor Carmel) wrote…
s/active/activate/ probably?
updated.
|
filed #87187 for ref. Tested w/ 300k ranges. Minimal (-500mb) difference. Multi-region would show greater distinction - likely O(localities). Also pushed ~3.48% more throughput on kv95, however that's within a error imo. |
|
bors r+ |
|
Build succeeded: |
This patch removes some unused fields within the replica stats object.
It also opts to allocate all the memory needed upfront for a replica
stats object for better cache locality and less GC overhead.
This patch also removes locality tracking for the other throughput trackers
to reduce per-replica memory footprint.
resolves #85112
Release justification: low risk, lowers memory footprint to avoid oom.
Release note: None