Skip to content

Commit cf574c9

Browse files
authored
Fixing how ring ownership is calculated on the ring status page (#5889)
Signed-off-by: alanprot <[email protected]>
1 parent f9cb3ea commit cf574c9

File tree

4 files changed

+58
-19
lines changed

4 files changed

+58
-19
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
* [ENHANCEMENT] Querier: Add context error check when merging slices from ingesters for GetLabel operations. #5837
3939
* [ENHANCEMENT] Ring: Add experimental `-ingester.tokens-generator-strategy=minimize-spread` flag to enable the new minimize spread token generator strategy. #5855
4040
* [ENHANCEMENT] Query Frontend: Ensure error response returned by Query Frontend follows Prometheus API error response format. #5811
41+
* [ENHANCEMENT] Ring Status Page: Add `Ownership Diff From Expected` column in the ring table to indicate the extent to which the ownership of a specific ingester differs from the expected ownership. #5889
4142
* [BUGFIX] Distributor: Do not use label with empty values for sharding #5717
4243
* [BUGFIX] Query Frontend: queries with negative offset should check whether it is cacheable or not. #5719
4344
* [BUGFIX] Redis Cache: pass `cache_size` config correctly. #5734

pkg/ring/http.go

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ const pageContent = `
3838
<th>Last Heartbeat</th>
3939
<th>Tokens</th>
4040
<th>Ownership</th>
41+
<th>Ownership Diff From Expected</th>
4142
<th>Actions</th>
4243
</tr>
4344
</thead>
@@ -56,6 +57,7 @@ const pageContent = `
5657
<td>{{ .HeartbeatTimestamp }}</td>
5758
<td>{{ .NumTokens }}</td>
5859
<td>{{ .Ownership }}%</td>
60+
<td>{{ .DiffOwnership }}%</td>
5961
<td><button name="forget" value="{{ .ID }}" type="submit">Forget</button></td>
6062
</tr>
6163
{{ end }}
@@ -114,6 +116,7 @@ type ingesterDesc struct {
114116
Tokens []uint32 `json:"tokens"`
115117
NumTokens int `json:"-"`
116118
Ownership float64 `json:"-"`
119+
DiffOwnership float64 `json:"-"`
117120
}
118121

119122
type httpResponse struct {
@@ -153,7 +156,6 @@ func (r *Ring) ServeHTTP(w http.ResponseWriter, req *http.Request) {
153156

154157
storageLastUpdate := r.KVClient.LastUpdateTime(r.key)
155158
var ingesters []ingesterDesc
156-
_, owned := r.countTokens()
157159
for _, id := range ingesterIDs {
158160
ing := r.ringDesc.Ingesters[id]
159161
heartbeatTimestamp := time.Unix(ing.Timestamp, 0)
@@ -168,6 +170,21 @@ func (r *Ring) ServeHTTP(w http.ResponseWriter, req *http.Request) {
168170
registeredTimestamp = ing.GetRegisteredAt().String()
169171
}
170172

173+
var ownership float64
174+
var deltaOwnership float64
175+
176+
if r.cfg.ZoneAwarenessEnabled {
177+
numTokens, ownedByAz := r.countTokensByAz()
178+
ownership = (float64(ownedByAz[id]) / float64(math.MaxUint32+1)) * 100
179+
expectedOwnership := 1 / float64(len(numTokens[ing.Zone])) * 100
180+
deltaOwnership = (1 - expectedOwnership/ownership) * 100
181+
} else {
182+
_, owned := r.countTokens()
183+
ownership = (float64(owned[id]) / float64(math.MaxUint32+1)) * 100
184+
expectedOwnership := 1 / float64(len(owned)) * 100
185+
deltaOwnership = (1 - expectedOwnership/ownership) * 100
186+
}
187+
171188
ingesters = append(ingesters, ingesterDesc{
172189
ID: id,
173190
State: state,
@@ -177,7 +194,8 @@ func (r *Ring) ServeHTTP(w http.ResponseWriter, req *http.Request) {
177194
Tokens: ing.Tokens,
178195
Zone: ing.Zone,
179196
NumTokens: len(ing.Tokens),
180-
Ownership: (float64(owned[id]) / float64(math.MaxUint32)) * 100,
197+
Ownership: ownership,
198+
DiffOwnership: deltaOwnership,
181199
})
182200
}
183201

pkg/ring/ring.go

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -590,22 +590,42 @@ func (r *Ring) GetReplicationSetForOperation(op Operation) (ReplicationSet, erro
590590
}, nil
591591
}
592592

593+
func (r *Ring) countTokensByAz() (map[string]map[string]uint32, map[string]int64) {
594+
numTokens := map[string]map[string]uint32{}
595+
owned := map[string]int64{}
596+
597+
for zone, zonalTokens := range r.ringDesc.getTokensByZone() {
598+
numTokens[zone] = map[string]uint32{}
599+
for i := 1; i <= len(zonalTokens); i++ {
600+
index := i % len(zonalTokens)
601+
diff := tokenDistance(zonalTokens[i-1], zonalTokens[index])
602+
info := r.ringInstanceByToken[zonalTokens[index]]
603+
owned[info.InstanceID] = owned[info.InstanceID] + diff
604+
numTokens[zone][info.InstanceID] = numTokens[zone][info.InstanceID] + 1
605+
}
606+
}
607+
608+
// Set to 0 the number of owned tokens by instances which don't have tokens yet.
609+
for id, info := range r.ringDesc.Ingesters {
610+
if _, ok := owned[id]; !ok {
611+
owned[id] = 0
612+
numTokens[info.Zone][id] = 0
613+
}
614+
}
615+
616+
return numTokens, owned
617+
}
618+
593619
// countTokens returns the number of tokens and tokens within the range for each instance.
594620
// The ring read lock must be already taken when calling this function.
595-
func (r *Ring) countTokens() (map[string]uint32, map[string]uint32) {
596-
owned := map[string]uint32{}
621+
func (r *Ring) countTokens() (map[string]uint32, map[string]int64) {
622+
owned := map[string]int64{}
597623
numTokens := map[string]uint32{}
598-
for i, token := range r.ringTokens {
599-
var diff uint32
600-
601-
// Compute how many tokens are within the range.
602-
if i+1 == len(r.ringTokens) {
603-
diff = (math.MaxUint32 - token) + r.ringTokens[0]
604-
} else {
605-
diff = r.ringTokens[i+1] - token
606-
}
624+
for i := 1; i <= len(r.ringTokens); i++ { // Compute how many tokens are within the range.
625+
index := i % len(r.ringTokens)
626+
diff := tokenDistance(r.ringTokens[i-1], r.ringTokens[index])
607627

608-
info := r.ringInstanceByToken[token]
628+
info := r.ringInstanceByToken[r.ringTokens[index]]
609629
numTokens[info.InstanceID] = numTokens[info.InstanceID] + 1
610630
owned[info.InstanceID] = owned[info.InstanceID] + diff
611631
}
@@ -662,7 +682,7 @@ func (r *Ring) updateRingMetrics(compareResult CompareResult) {
662682
r.reportedOwners = make(map[string]struct{})
663683
numTokens, ownedRange := r.countTokens()
664684
for id, totalOwned := range ownedRange {
665-
r.memberOwnershipGaugeVec.WithLabelValues(id).Set(float64(totalOwned) / float64(math.MaxUint32))
685+
r.memberOwnershipGaugeVec.WithLabelValues(id).Set(float64(totalOwned) / float64(math.MaxUint32+1))
666686
r.numTokensGaugeVec.WithLabelValues(id).Set(float64(numTokens[id]))
667687
delete(prevOwners, id)
668688
r.reportedOwners[id] = struct{}{}

pkg/ring/ring_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3008,8 +3008,8 @@ func TestUpdateMetrics(t *testing.T) {
30083008
err = testutil.GatherAndCompare(registry, bytes.NewBufferString(`
30093009
# HELP ring_member_ownership_percent The percent ownership of the ring by member
30103010
# TYPE ring_member_ownership_percent gauge
3011-
ring_member_ownership_percent{member="A",name="test"} 0.500000000349246
3012-
ring_member_ownership_percent{member="B",name="test"} 0.49999999965075403
3011+
ring_member_ownership_percent{member="A",name="test"} 0.49999999976716936
3012+
ring_member_ownership_percent{member="B",name="test"} 0.5000000002328306
30133013
# HELP ring_members Number of members in the ring
30143014
# TYPE ring_members gauge
30153015
ring_members{name="test",state="ACTIVE"} 2
@@ -3060,8 +3060,8 @@ func TestUpdateMetricsWithRemoval(t *testing.T) {
30603060
err = testutil.GatherAndCompare(registry, bytes.NewBufferString(`
30613061
# HELP ring_member_ownership_percent The percent ownership of the ring by member
30623062
# TYPE ring_member_ownership_percent gauge
3063-
ring_member_ownership_percent{member="A",name="test"} 0.500000000349246
3064-
ring_member_ownership_percent{member="B",name="test"} 0.49999999965075403
3063+
ring_member_ownership_percent{member="A",name="test"} 0.49999999976716936
3064+
ring_member_ownership_percent{member="B",name="test"} 0.5000000002328306
30653065
# HELP ring_members Number of members in the ring
30663066
# TYPE ring_members gauge
30673067
ring_members{name="test",state="ACTIVE"} 2

0 commit comments

Comments
 (0)