Merge pull request #12084 from bboreham/target-labels

scraping: reduce memory allocations on Target labels
This commit is contained in:
Bryan Boreham 2023-03-22 09:02:08 +00:00 committed by GitHub
commit 5d90dc0627
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 33 additions and 26 deletions

View file

@ -500,9 +500,12 @@ func (sp *scrapePool) Sync(tgs []*targetgroup.Group) {
} }
targetSyncFailed.WithLabelValues(sp.config.JobName).Add(float64(len(failures))) targetSyncFailed.WithLabelValues(sp.config.JobName).Add(float64(len(failures)))
for _, t := range targets { for _, t := range targets {
if !t.Labels().IsEmpty() { // Replicate .Labels().IsEmpty() with a loop here to avoid generating garbage.
nonEmpty := false
t.LabelsRange(func(l labels.Label) { nonEmpty = true })
if nonEmpty {
all = append(all, t) all = append(all, t)
} else if !t.DiscoveredLabels().IsEmpty() { } else if !t.discoveredLabels.IsEmpty() {
sp.droppedTargets = append(sp.droppedTargets, t) sp.droppedTargets = append(sp.droppedTargets, t)
} }
} }
@ -666,17 +669,16 @@ func verifyLabelLimits(lset labels.Labels, limits *labelLimits) error {
func mutateSampleLabels(lset labels.Labels, target *Target, honor bool, rc []*relabel.Config) labels.Labels { func mutateSampleLabels(lset labels.Labels, target *Target, honor bool, rc []*relabel.Config) labels.Labels {
lb := labels.NewBuilder(lset) lb := labels.NewBuilder(lset)
targetLabels := target.Labels()
if honor { if honor {
targetLabels.Range(func(l labels.Label) { target.LabelsRange(func(l labels.Label) {
if !lset.Has(l.Name) { if !lset.Has(l.Name) {
lb.Set(l.Name, l.Value) lb.Set(l.Name, l.Value)
} }
}) })
} else { } else {
var conflictingExposedLabels []labels.Label var conflictingExposedLabels []labels.Label
targetLabels.Range(func(l labels.Label) { target.LabelsRange(func(l labels.Label) {
existingValue := lset.Get(l.Name) existingValue := lset.Get(l.Name)
if existingValue != "" { if existingValue != "" {
conflictingExposedLabels = append(conflictingExposedLabels, labels.Label{Name: l.Name, Value: existingValue}) conflictingExposedLabels = append(conflictingExposedLabels, labels.Label{Name: l.Name, Value: existingValue})
@ -686,7 +688,7 @@ func mutateSampleLabels(lset labels.Labels, target *Target, honor bool, rc []*re
}) })
if len(conflictingExposedLabels) > 0 { if len(conflictingExposedLabels) > 0 {
resolveConflictingExposedLabels(lb, lset, targetLabels, conflictingExposedLabels) resolveConflictingExposedLabels(lb, conflictingExposedLabels)
} }
} }
@ -699,42 +701,27 @@ func mutateSampleLabels(lset labels.Labels, target *Target, honor bool, rc []*re
return res return res
} }
func resolveConflictingExposedLabels(lb *labels.Builder, exposedLabels, targetLabels labels.Labels, conflictingExposedLabels []labels.Label) { func resolveConflictingExposedLabels(lb *labels.Builder, conflictingExposedLabels []labels.Label) {
sort.SliceStable(conflictingExposedLabels, func(i, j int) bool { sort.SliceStable(conflictingExposedLabels, func(i, j int) bool {
return len(conflictingExposedLabels[i].Name) < len(conflictingExposedLabels[j].Name) return len(conflictingExposedLabels[i].Name) < len(conflictingExposedLabels[j].Name)
}) })
for i, l := range conflictingExposedLabels { for _, l := range conflictingExposedLabels {
newName := l.Name newName := l.Name
for { for {
newName = model.ExportedLabelPrefix + newName newName = model.ExportedLabelPrefix + newName
if !exposedLabels.Has(newName) && if lb.Get(newName) == "" {
!targetLabels.Has(newName) && lb.Set(newName, l.Value)
!labelSliceHas(conflictingExposedLabels[:i], newName) {
conflictingExposedLabels[i].Name = newName
break break
} }
} }
} }
for _, l := range conflictingExposedLabels {
lb.Set(l.Name, l.Value)
}
}
func labelSliceHas(lbls []labels.Label, name string) bool {
for _, l := range lbls {
if l.Name == name {
return true
}
}
return false
} }
func mutateReportSampleLabels(lset labels.Labels, target *Target) labels.Labels { func mutateReportSampleLabels(lset labels.Labels, target *Target) labels.Labels {
lb := labels.NewBuilder(lset) lb := labels.NewBuilder(lset)
target.Labels().Range(func(l labels.Label) { target.LabelsRange(func(l labels.Label) {
lb.Set(model.ExportedLabelPrefix+l.Name, lset.Get(l.Name)) lb.Set(model.ExportedLabelPrefix+l.Name, lset.Get(l.Name))
lb.Set(l.Name, l.Value) lb.Set(l.Name, l.Value)
}) })

View file

@ -181,6 +181,15 @@ func (t *Target) Labels() labels.Labels {
return b.Labels() return b.Labels()
} }
// LabelsRange calls f on each public label of the target.
func (t *Target) LabelsRange(f func(l labels.Label)) {
t.labels.Range(func(l labels.Label) {
if !strings.HasPrefix(l.Name, model.ReservedLabelPrefix) {
f(l)
}
})
}
// DiscoveredLabels returns a copy of the target's labels before any processing. // DiscoveredLabels returns a copy of the target's labels before any processing.
func (t *Target) DiscoveredLabels() labels.Labels { func (t *Target) DiscoveredLabels() labels.Labels {
t.mtx.Lock() t.mtx.Lock()

View file

@ -43,6 +43,17 @@ func TestTargetLabels(t *testing.T) {
want := labels.FromStrings(model.JobLabel, "some_job", "foo", "bar") want := labels.FromStrings(model.JobLabel, "some_job", "foo", "bar")
got := target.Labels() got := target.Labels()
require.Equal(t, want, got) require.Equal(t, want, got)
i := 0
target.LabelsRange(func(l labels.Label) {
switch i {
case 0:
require.Equal(t, labels.Label{Name: "foo", Value: "bar"}, l)
case 1:
require.Equal(t, labels.Label{Name: model.JobLabel, Value: "some_job"}, l)
}
i++
})
require.Equal(t, 2, i)
} }
func TestTargetOffset(t *testing.T) { func TestTargetOffset(t *testing.T) {