From 70b10a98b4b37fa6815836a96c16ae596556d2e4 Mon Sep 17 00:00:00 2001 From: Steve Simpson Date: Wed, 1 Dec 2021 21:03:39 +0100 Subject: [PATCH 1/2] Memberlist: Avoid checking for conflicting tokens if no tokens changed. If we can assume that the current ring state does not have conflicting tokens, then we only need to check for conflicting tokens if the tokens for any ingester actually changed. This will be the case for systems not currently scaling up or down, as only heartbeats will be sent. --- ring/model.go | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/ring/model.go b/ring/model.go index b8ad22281..13753aeb2 100644 --- a/ring/model.go +++ b/ring/model.go @@ -202,11 +202,15 @@ func (d *Desc) mergeWithTime(mergeable memberlist.Mergeable, localCAS bool, now otherIngesterMap := other.Ingesters var updated []string + tokensChanged := false for name, oing := range otherIngesterMap { ting := thisIngesterMap[name] // ting.Timestamp will be 0, if there was no such ingester in our version if oing.Timestamp > ting.Timestamp { + if !tokensEqual(ting.Tokens, oing.Tokens) { + tokensChanged = true + } oing.Tokens = append([]uint32(nil), oing.Tokens...) // make a copy of tokens thisIngesterMap[name] = oing updated = append(updated, name) @@ -241,7 +245,7 @@ func (d *Desc) mergeWithTime(mergeable memberlist.Mergeable, localCAS bool, now } // resolveConflicts allocates lot of memory, so if we can avoid it, do that. - if conflictingTokensExist(thisIngesterMap) { + if tokensChanged && conflictingTokensExist(thisIngesterMap) { resolveConflicts(thisIngesterMap) } @@ -303,6 +307,19 @@ func normalizeIngestersMap(inputRing *Desc) { } } +// tokensEqual checks for equality of two slices. Assumes the slices are sorted. +func tokensEqual(lhs, rhs []uint32) bool { + if len(lhs) != len(rhs) { + return false + } + for i := 0; i < len(lhs); i++ { + if lhs[i] != rhs[i] { + return false + } + } + return true +} + var tokenMapPool = sync.Pool{New: func() interface{} { return make(map[uint32]struct{}) }} func conflictingTokensExist(normalizedIngesters map[string]InstanceDesc) bool { From 0de3f97de8b7053ceb843b2cb633a10ef9d08de4 Mon Sep 17 00:00:00 2001 From: Steve Simpson Date: Wed, 1 Dec 2021 21:29:26 +0100 Subject: [PATCH 2/2] Changelog. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8776a86d6..c964f7ae7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,7 @@ * [ENHANCEMENT] Replace go-kit/kit/log with go-kit/log. #52 * [ENHANCEMENT] Add spanlogger package. #42 * [ENHANCEMENT] Add runutil.CloseWithLogOnErr function. #58 -* [ENHANCEMENT] Optimise memberlist receive path when used as a backing store for rings with a large number of members. #76 #77 #84 +* [ENHANCEMENT] Optimise memberlist receive path when used as a backing store for rings with a large number of members. #76 #77 #84 #91 * [ENHANCEMENT] Memberlist: prepare the data to send on the write before starting counting the elapsed time for `-memberlist.packet-write-timeout`, in order to reduce chances we hit the timeout when sending a packet to other node. #89 * [ENHANCEMENT] flagext: for cases such as `DeprecatedFlag()` that need a logger, add RegisterFlagsWithLogger. #80 * [BUGFIX] spanlogger: Support multiple tenant IDs. #59