diff --git a/app/vmalert/notifier/config.go b/app/vmalert/notifier/config.go
index 055cf4c75c..23c6b11980 100644
--- a/app/vmalert/notifier/config.go
+++ b/app/vmalert/notifier/config.go
@@ -12,7 +12,6 @@ import (
 	"time"
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promauth"
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promrelabel"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discovery/consul"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discovery/dns"
@@ -130,24 +129,24 @@ func parseConfig(path string) (*Config, error) {
 	return cfg, nil
 }
 
-func parseLabels(target string, metaLabels map[string]string, cfg *Config) (string, []prompbmarshal.Label, error) {
+func parseLabels(target string, metaLabels *promutils.Labels, cfg *Config) (string, *promutils.Labels, error) {
 	labels := mergeLabels(target, metaLabels, cfg)
-	labels = cfg.parsedRelabelConfigs.Apply(labels, 0)
-	labels = promrelabel.RemoveMetaLabels(labels[:0], labels)
-	promrelabel.SortLabels(labels)
+	labels.Labels = cfg.parsedRelabelConfigs.Apply(labels.Labels, 0)
+	labels.RemoveMetaLabels()
+	labels.Sort()
 	// Remove references to already deleted labels, so GC could clean strings for label name and label value past len(labels).
 	// This should reduce memory usage when relabeling creates big number of temporary labels with long names and/or values.
 	// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/825 for details.
-	labels = append([]prompbmarshal.Label{}, labels...)
+	labels = labels.Clone()
 
-	if len(labels) == 0 {
+	if labels.Len() == 0 {
 		return "", nil, nil
 	}
-	schemeRelabeled := promrelabel.GetLabelValueByName(labels, "__scheme__")
+	schemeRelabeled := labels.Get("__scheme__")
 	if len(schemeRelabeled) == 0 {
 		schemeRelabeled = "http"
 	}
-	addressRelabeled := promrelabel.GetLabelValueByName(labels, "__address__")
+	addressRelabeled := labels.Get("__address__")
 	if len(addressRelabeled) == 0 {
 		return "", nil, nil
 	}
@@ -155,7 +154,7 @@ func parseLabels(target string, metaLabels map[string]string, cfg *Config) (stri
 		return "", nil, nil
 	}
 	addressRelabeled = addMissingPort(schemeRelabeled, addressRelabeled)
-	alertsPathRelabeled := promrelabel.GetLabelValueByName(labels, "__alerts_path__")
+	alertsPathRelabeled := labels.Get("__alerts_path__")
 	if !strings.HasPrefix(alertsPathRelabeled, "/") {
 		alertsPathRelabeled = "/" + alertsPathRelabeled
 	}
@@ -179,21 +178,12 @@ func addMissingPort(scheme, target string) string {
 	return target
 }
 
-func mergeLabels(target string, metaLabels map[string]string, cfg *Config) []prompbmarshal.Label {
+func mergeLabels(target string, metaLabels *promutils.Labels, cfg *Config) *promutils.Labels {
 	// See https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config
-	m := make(map[string]string)
-	m["__address__"] = target
-	m["__scheme__"] = cfg.Scheme
-	m["__alerts_path__"] = path.Join("/", cfg.PathPrefix, alertManagerPath)
-	for k, v := range metaLabels {
-		m[k] = v
-	}
-	result := make([]prompbmarshal.Label, 0, len(m))
-	for k, v := range m {
-		result = append(result, prompbmarshal.Label{
-			Name:  k,
-			Value: v,
-		})
-	}
-	return result
+	m := promutils.NewLabels(3 + metaLabels.Len())
+	m.Add("__address__", target)
+	m.Add("__scheme__", cfg.Scheme)
+	m.Add("__alerts_path__", path.Join("/", cfg.PathPrefix, alertManagerPath))
+	m.AddFrom(metaLabels)
+	return m
 }
diff --git a/app/vmalert/notifier/config_watcher.go b/app/vmalert/notifier/config_watcher.go
index f70fed7c57..1172152a4b 100644
--- a/app/vmalert/notifier/config_watcher.go
+++ b/app/vmalert/notifier/config_watcher.go
@@ -9,6 +9,7 @@ import (
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promauth"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discovery/consul"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discovery/dns"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 // configWatcher supports dynamic reload of Notifier objects
@@ -123,7 +124,7 @@ func targetsFromLabels(labelsFn getLabels, cfg *Config, genFn AlertURLGenerator)
 	var errors []error
 	duplicates := make(map[string]struct{})
 	for _, labels := range metaLabels {
-		target := labels["__address__"]
+		target := labels.Get("__address__")
 		u, processedLabels, err := parseLabels(target, labels, cfg)
 		if err != nil {
 			errors = append(errors, err)
@@ -156,7 +157,7 @@ func targetsFromLabels(labelsFn getLabels, cfg *Config, genFn AlertURLGenerator)
 	return targets, errors
 }
 
-type getLabels func() ([]map[string]string, error)
+type getLabels func() ([]*promutils.Labels, error)
 
 func (cw *configWatcher) start() error {
 	if len(cw.cfg.StaticConfigs) > 0 {
@@ -182,8 +183,8 @@ func (cw *configWatcher) start() error {
 	}
 
 	if len(cw.cfg.ConsulSDConfigs) > 0 {
-		err := cw.add(TargetConsul, *consul.SDCheckInterval, func() ([]map[string]string, error) {
-			var labels []map[string]string
+		err := cw.add(TargetConsul, *consul.SDCheckInterval, func() ([]*promutils.Labels, error) {
+			var labels []*promutils.Labels
 			for i := range cw.cfg.ConsulSDConfigs {
 				sdc := &cw.cfg.ConsulSDConfigs[i]
 				targetLabels, err := sdc.GetLabels(cw.cfg.baseDir)
@@ -200,8 +201,8 @@ func (cw *configWatcher) start() error {
 	}
 
 	if len(cw.cfg.DNSSDConfigs) > 0 {
-		err := cw.add(TargetDNS, *dns.SDCheckInterval, func() ([]map[string]string, error) {
-			var labels []map[string]string
+		err := cw.add(TargetDNS, *dns.SDCheckInterval, func() ([]*promutils.Labels, error) {
+			var labels []*promutils.Labels
 			for i := range cw.cfg.DNSSDConfigs {
 				sdc := &cw.cfg.DNSSDConfigs[i]
 				targetLabels, err := sdc.GetLabels(cw.cfg.baseDir)
diff --git a/app/vmalert/notifier/init.go b/app/vmalert/notifier/init.go
index 716b1ebd68..39edcd6310 100644
--- a/app/vmalert/notifier/init.go
+++ b/app/vmalert/notifier/init.go
@@ -10,7 +10,7 @@ import (
 	"github.com/VictoriaMetrics/VictoriaMetrics/app/vmalert/templates"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/flagutil"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promauth"
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 var (
@@ -159,7 +159,7 @@ func notifiersFromFlags(gen AlertURLGenerator) ([]Notifier, error) {
 // list of labels added during discovery.
 type Target struct {
 	Notifier
-	Labels []prompbmarshal.Label
+	Labels *promutils.Labels
 }
 
 // TargetType defines how the Target was discovered
diff --git a/app/vmalert/web.qtpl b/app/vmalert/web.qtpl
index 7346a2705e..d695e7eaaa 100644
--- a/app/vmalert/web.qtpl
+++ b/app/vmalert/web.qtpl
@@ -248,7 +248,7 @@
                  {% for _, n := range ns %}
                      <tr>
                          <td>
-                              {% for _, l := range n.Labels %}
+                              {% for _, l := range n.Labels.GetLabels() %}
                                       <span class="ms-1 badge bg-primary">{%s l.Name %}={%s l.Value %}</span>
                               {% endfor %}
                           </td>
diff --git a/app/vmalert/web.qtpl.go b/app/vmalert/web.qtpl.go
index 08baf53330..8a1982bbee 100644
--- a/app/vmalert/web.qtpl.go
+++ b/app/vmalert/web.qtpl.go
@@ -824,7 +824,7 @@ func StreamListTargets(qw422016 *qt422016.Writer, r *http.Request, targets map[n
                          <td>
                               `)
 //line app/vmalert/web.qtpl:251
-				for _, l := range n.Labels {
+				for _, l := range n.Labels.GetLabels() {
 //line app/vmalert/web.qtpl:251
 					qw422016.N().S(`
                                       <span class="ms-1 badge bg-primary">`)
diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md
index 65b0f5f36c..aee1eab248 100644
--- a/docs/CHANGELOG.md
+++ b/docs/CHANGELOG.md
@@ -15,6 +15,7 @@ The following tip changes can be tested by building VictoriaMetrics components f
 
 ## tip
 
+* FEATURE: [vmagent](https://docs.victoriametrics.com/vmagent.html): improve [service discovery](https://docs.victoriametrics.com/sd_configs.html) performance when discovering big number of targets (10K and more).
 * FEATURE: [vmagent](https://docs.victoriametrics.com/vmagent.html): add `exported_` prefix to metric names exported by scrape targets if these metric names clash with [automatically generated metrics](https://docs.victoriametrics.com/vmagent.html#automatically-generated-metrics) such as `up`, `scrape_samples_scraped`, etc. This prevents from corruption of automatically generated metrics. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3406).
 * FEATURE: [VictoriaMetrics cluster](https://docs.victoriametrics.com/Cluster-VictoriaMetrics.html): improve error message when the requested path cannot be properly parsed, so users could identify the issue and properly fix the path. Now the error message links to [url format docs](https://docs.victoriametrics.com/Cluster-VictoriaMetrics.html#url-format). See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3402).
 * FEATURE: [vmctl](https://docs.victoriametrics.com/vmctl.html): add ability to copy data from sources via Prometheus `remote_read` protocol. See [these docs](https://docs.victoriametrics.com/vmctl.html#migrating-data-by-remote-read-protocol). The related issues: [one](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3132) and [two](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1101).
diff --git a/lib/bytesutil/itoa.go b/lib/bytesutil/itoa.go
new file mode 100644
index 0000000000..254db8d3c3
--- /dev/null
+++ b/lib/bytesutil/itoa.go
@@ -0,0 +1,20 @@
+package bytesutil
+
+import (
+	"strconv"
+)
+
+// Itoa returns string representation of n.
+//
+// This function doesn't allocate memory on repeated calls for the same n.
+func Itoa(n int) string {
+	bb := bbPool.Get()
+	b := bb.B[:0]
+	b = strconv.AppendInt(b, int64(n), 10)
+	s := InternString(ToUnsafeString(b))
+	bb.B = b
+	bbPool.Put(bb)
+	return s
+}
+
+var bbPool ByteBufferPool
diff --git a/lib/bytesutil/itoa_test.go b/lib/bytesutil/itoa_test.go
new file mode 100644
index 0000000000..4a2fb48ed8
--- /dev/null
+++ b/lib/bytesutil/itoa_test.go
@@ -0,0 +1,21 @@
+package bytesutil
+
+import (
+	"testing"
+)
+
+func TestItoa(t *testing.T) {
+	f := func(n int, resultExpected string) {
+		t.Helper()
+		for i := 0; i < 5; i++ {
+			result := Itoa(n)
+			if result != resultExpected {
+				t.Fatalf("unexpected result for Itoa(%d); got %q; want %q", n, result, resultExpected)
+			}
+		}
+	}
+	f(0, "0")
+	f(1, "1")
+	f(-123, "-123")
+	f(343432, "343432")
+}
diff --git a/lib/promrelabel/if_expression_test.go b/lib/promrelabel/if_expression_test.go
index 900c1da955..6e71a822f8 100644
--- a/lib/promrelabel/if_expression_test.go
+++ b/lib/promrelabel/if_expression_test.go
@@ -5,6 +5,7 @@ import (
 	"encoding/json"
 	"testing"
 
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 	"gopkg.in/yaml.v2"
 )
 
@@ -121,8 +122,8 @@ func TestIfExpressionMatch(t *testing.T) {
 		if err := yaml.UnmarshalStrict([]byte(ifExpr), &ie); err != nil {
 			t.Fatalf("unexpected error during unmarshal: %s", err)
 		}
-		labels := MustParseMetricWithLabels(metricWithLabels)
-		if !ie.Match(labels) {
+		labels := promutils.NewLabelsFromString(metricWithLabels)
+		if !ie.Match(labels.GetLabels()) {
 			t.Fatalf("unexpected mismatch of ifExpr=%s for %s", ifExpr, metricWithLabels)
 		}
 	}
@@ -155,8 +156,8 @@ func TestIfExpressionMismatch(t *testing.T) {
 		if err := yaml.UnmarshalStrict([]byte(ifExpr), &ie); err != nil {
 			t.Fatalf("unexpected error during unmarshal: %s", err)
 		}
-		labels := MustParseMetricWithLabels(metricWithLabels)
-		if ie.Match(labels) {
+		labels := promutils.NewLabelsFromString(metricWithLabels)
+		if ie.Match(labels.GetLabels()) {
 			t.Fatalf("unexpected match of ifExpr=%s for %s", ifExpr, metricWithLabels)
 		}
 	}
diff --git a/lib/promrelabel/relabel.go b/lib/promrelabel/relabel.go
index 6e1cbcfa92..6d56a37548 100644
--- a/lib/promrelabel/relabel.go
+++ b/lib/promrelabel/relabel.go
@@ -9,6 +9,7 @@ import (
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/regexutil"
 	"github.com/cespare/xxhash/v2"
 )
@@ -48,8 +49,6 @@ func (prc *parsedRelabelConfig) String() string {
 }
 
 // Apply applies pcs to labels starting from the labelsOffset.
-//
-// If isFinalize is set, then FinalizeLabels is called on the labels[labelsOffset:].
 func (pcs *ParsedConfigs) Apply(labels []prompbmarshal.Label, labelsOffset int) []prompbmarshal.Label {
 	var inStr string
 	relabelDebug := false
@@ -111,32 +110,6 @@ func removeEmptyLabels(labels []prompbmarshal.Label, labelsOffset int) []prompbm
 	return dst
 }
 
-// RemoveMetaLabels removes all the `__meta_` labels from src and puts the rest of labels to dst.
-//
-// See https://www.robustperception.io/life-of-a-label fo details.
-func RemoveMetaLabels(dst, src []prompbmarshal.Label) []prompbmarshal.Label {
-	for _, label := range src {
-		if strings.HasPrefix(label.Name, "__meta_") {
-			continue
-		}
-		dst = append(dst, label)
-	}
-	return dst
-}
-
-// RemoveLabelsWithDoubleDashPrefix removes labels with "__" prefix from src, appends the remaining lables to dst and returns the result.
-func RemoveLabelsWithDoubleDashPrefix(dst, src []prompbmarshal.Label) []prompbmarshal.Label {
-	for _, label := range src {
-		name := label.Name
-		// A hack: do not delete __vm_filepath label, since it is used by internal logic for FileSDConfig.
-		if strings.HasPrefix(name, "__") && name != "__vm_filepath" {
-			continue
-		}
-		dst = append(dst, label)
-	}
-	return dst
-}
-
 // FinalizeLabels removes labels with "__" in the beginning (except of "__name__").
 func FinalizeLabels(dst, src []prompbmarshal.Label) []prompbmarshal.Label {
 	for _, label := range src {
@@ -164,7 +137,7 @@ func (prc *parsedRelabelConfig) apply(labels []prompbmarshal.Label, labelsOffset
 	}
 	switch prc.Action {
 	case "graphite":
-		metricName := GetLabelValueByName(src, "__name__")
+		metricName := getLabelValue(src, "__name__")
 		gm := graphiteMatchesPool.Get().(*graphiteMatches)
 		var ok bool
 		gm.a, ok = prc.graphiteMatchTemplate.Match(gm.a[:0], metricName)
@@ -464,9 +437,9 @@ func areEqualLabelValues(labels []prompbmarshal.Label, labelNames []string) bool
 		logger.Panicf("BUG: expecting at least 2 labelNames; got %d", len(labelNames))
 		return false
 	}
-	labelValue := GetLabelValueByName(labels, labelNames[0])
+	labelValue := getLabelValue(labels, labelNames[0])
 	for _, labelName := range labelNames[1:] {
-		v := GetLabelValueByName(labels, labelName)
+		v := getLabelValue(labels, labelName)
 		if v != labelValue {
 			return false
 		}
@@ -500,6 +473,15 @@ func setLabelValue(labels []prompbmarshal.Label, labelsOffset int, name, value s
 	return labels
 }
 
+func getLabelValue(labels []prompbmarshal.Label, name string) string {
+	for _, label := range labels {
+		if label.Name == name {
+			return label.Value
+		}
+	}
+	return ""
+}
+
 // GetLabelByName returns label with the given name from labels.
 func GetLabelByName(labels []prompbmarshal.Label, name string) *prompbmarshal.Label {
 	for i := range labels {
@@ -511,17 +493,6 @@ func GetLabelByName(labels []prompbmarshal.Label, name string) *prompbmarshal.La
 	return nil
 }
 
-// GetLabelValueByName returns value for label with the given name from labels.
-//
-// It returns empty string for non-existing label.
-func GetLabelValueByName(labels []prompbmarshal.Label, name string) string {
-	label := GetLabelByName(labels, name)
-	if label == nil {
-		return ""
-	}
-	return label.Value
-}
-
 // CleanLabels sets label.Name and label.Value to an empty string for all the labels.
 //
 // This should help GC cleaning up label.Name and label.Value strings.
@@ -563,6 +534,14 @@ func labelsToString(labels []prompbmarshal.Label) string {
 	return string(b)
 }
 
+// SortLabels sorts labels in alphabetical order.
+func SortLabels(labels []prompbmarshal.Label) {
+	x := &promutils.Labels{
+		Labels: labels,
+	}
+	x.Sort()
+}
+
 func fillLabelReferences(dst []byte, replacement string, labels []prompbmarshal.Label) []byte {
 	s := replacement
 	for len(s) > 0 {
@@ -579,7 +558,7 @@ func fillLabelReferences(dst []byte, replacement string, labels []prompbmarshal.
 		}
 		labelName := s[:n]
 		s = s[n+2:]
-		labelValue := GetLabelValueByName(labels, labelName)
+		labelValue := getLabelValue(labels, labelName)
 		dst = append(dst, labelValue...)
 	}
 	return dst
diff --git a/lib/promrelabel/relabel_test.go b/lib/promrelabel/relabel_test.go
index 57c10e2ada..8df056e797 100644
--- a/lib/promrelabel/relabel_test.go
+++ b/lib/promrelabel/relabel_test.go
@@ -5,6 +5,7 @@ import (
 	"testing"
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 func TestSanitizeName(t *testing.T) {
@@ -77,8 +78,8 @@ func TestApplyRelabelConfigs(t *testing.T) {
 		if err != nil {
 			t.Fatalf("cannot parse %q: %s", config, err)
 		}
-		labels := MustParseMetricWithLabels(metric)
-		resultLabels := pcs.Apply(labels, 0)
+		labels := promutils.NewLabelsFromString(metric)
+		resultLabels := pcs.Apply(labels.GetLabels(), 0)
 		if isFinalize {
 			resultLabels = FinalizeLabels(resultLabels[:0], resultLabels)
 		}
@@ -725,8 +726,8 @@ func TestApplyRelabelConfigs(t *testing.T) {
 func TestFinalizeLabels(t *testing.T) {
 	f := func(metric, resultExpected string) {
 		t.Helper()
-		labels := MustParseMetricWithLabels(metric)
-		resultLabels := FinalizeLabels(nil, labels)
+		labels := promutils.NewLabelsFromString(metric)
+		resultLabels := FinalizeLabels(nil, labels.GetLabels())
 		result := labelsToString(resultLabels)
 		if result != resultExpected {
 			t.Fatalf("unexpected result; got\n%s\nwant\n%s", result, resultExpected)
@@ -738,27 +739,11 @@ func TestFinalizeLabels(t *testing.T) {
 	f(`{foo="bar",abc="def",__address__="foo.com"}`, `{abc="def",foo="bar"}`)
 }
 
-func TestRemoveMetaLabels(t *testing.T) {
-	f := func(metric, resultExpected string) {
-		t.Helper()
-		labels := MustParseMetricWithLabels(metric)
-		resultLabels := RemoveMetaLabels(nil, labels)
-		result := labelsToString(resultLabels)
-		if result != resultExpected {
-			t.Fatalf("unexpected result of RemoveMetaLabels;\ngot\n%s\nwant\n%s", result, resultExpected)
-		}
-	}
-	f(`{}`, `{}`)
-	f(`{foo="bar"}`, `{foo="bar"}`)
-	f(`{__meta_foo="bar"}`, `{}`)
-	f(`{__meta_foo="bdffr",foo="bar",__meta_xxx="basd"}`, `{foo="bar"}`)
-}
-
 func TestFillLabelReferences(t *testing.T) {
 	f := func(replacement, metric, resultExpected string) {
 		t.Helper()
-		labels := MustParseMetricWithLabels(metric)
-		result := fillLabelReferences(nil, replacement, labels)
+		labels := promutils.NewLabelsFromString(metric)
+		result := fillLabelReferences(nil, replacement, labels.GetLabels())
 		if string(result) != resultExpected {
 			t.Fatalf("unexpected result; got\n%q\nwant\n%q", result, resultExpected)
 		}
diff --git a/lib/promrelabel/sort.go b/lib/promrelabel/sort.go
deleted file mode 100644
index 6c92044b22..0000000000
--- a/lib/promrelabel/sort.go
+++ /dev/null
@@ -1,54 +0,0 @@
-package promrelabel
-
-import (
-	"sort"
-	"sync"
-
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
-)
-
-// SortLabels sorts labels.
-func SortLabels(labels []prompbmarshal.Label) {
-	if len(labels) < 2 {
-		return
-	}
-	ls := labelsSorterPool.Get().(*labelsSorter)
-	*ls = labels
-	if !sort.IsSorted(ls) {
-		sort.Sort(ls)
-	}
-	*ls = nil
-	labelsSorterPool.Put(ls)
-}
-
-// SortLabelsStable sorts labels using stable sort.
-func SortLabelsStable(labels []prompbmarshal.Label) {
-	if len(labels) < 2 {
-		return
-	}
-	ls := labelsSorterPool.Get().(*labelsSorter)
-	*ls = labels
-	if !sort.IsSorted(ls) {
-		sort.Stable(ls)
-	}
-	*ls = nil
-	labelsSorterPool.Put(ls)
-}
-
-var labelsSorterPool = &sync.Pool{
-	New: func() interface{} {
-		return &labelsSorter{}
-	},
-}
-
-type labelsSorter []prompbmarshal.Label
-
-func (ls *labelsSorter) Len() int { return len(*ls) }
-func (ls *labelsSorter) Swap(i, j int) {
-	a := *ls
-	a[i], a[j] = a[j], a[i]
-}
-func (ls *labelsSorter) Less(i, j int) bool {
-	a := *ls
-	return a[i].Name < a[j].Name
-}
diff --git a/lib/promrelabel/sort_test.go b/lib/promrelabel/sort_test.go
deleted file mode 100644
index 9c34e3329a..0000000000
--- a/lib/promrelabel/sort_test.go
+++ /dev/null
@@ -1,43 +0,0 @@
-package promrelabel
-
-import (
-	"reflect"
-	"testing"
-
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
-)
-
-func TestSortLabels(t *testing.T) {
-	labels := []prompbmarshal.Label{
-		{
-			Name:  "foo",
-			Value: "bar",
-		},
-		{
-			Name:  "aa",
-			Value: "bb",
-		},
-		{
-			Name:  "ba",
-			Value: "zz",
-		},
-	}
-	labelsExpected := []prompbmarshal.Label{
-		{
-			Name:  "aa",
-			Value: "bb",
-		},
-		{
-			Name:  "ba",
-			Value: "zz",
-		},
-		{
-			Name:  "foo",
-			Value: "bar",
-		},
-	}
-	SortLabels(labels)
-	if !reflect.DeepEqual(labels, labelsExpected) {
-		t.Fatalf("unexpected sorted labels; got\n%v\nwant\n%v", labels, labelsExpected)
-	}
-}
diff --git a/lib/promrelabel/util.go b/lib/promrelabel/util.go
deleted file mode 100644
index b93fe4c93d..0000000000
--- a/lib/promrelabel/util.go
+++ /dev/null
@@ -1,50 +0,0 @@
-package promrelabel
-
-import (
-	"fmt"
-	"strings"
-
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/prometheus"
-)
-
-// MustParseMetricWithLabels parses s, which can have the form `metric{labels}`.
-//
-// This function is indended mostly for tests.
-func MustParseMetricWithLabels(metricWithLabels string) []prompbmarshal.Label {
-	stripDummyMetric := false
-	if strings.HasPrefix(metricWithLabels, "{") {
-		// Add a dummy metric name, since the parser needs it
-		metricWithLabels = "dummy_metric" + metricWithLabels
-		stripDummyMetric = true
-	}
-	// add a value to metricWithLabels, so it could be parsed by prometheus protocol parser.
-	s := metricWithLabels + " 123"
-	var rows prometheus.Rows
-	var err error
-	rows.UnmarshalWithErrLogger(s, func(s string) {
-		err = fmt.Errorf("error during metric parse: %s", s)
-	})
-	if err != nil {
-		logger.Panicf("BUG: cannot parse %q: %s", metricWithLabels, err)
-	}
-	if len(rows.Rows) != 1 {
-		logger.Panicf("BUG: unexpected number of rows parsed; got %d; want 1", len(rows.Rows))
-	}
-	r := rows.Rows[0]
-	var lfs []prompbmarshal.Label
-	if !stripDummyMetric {
-		lfs = append(lfs, prompbmarshal.Label{
-			Name:  "__name__",
-			Value: r.Metric,
-		})
-	}
-	for _, tag := range r.Tags {
-		lfs = append(lfs, prompbmarshal.Label{
-			Name:  tag.Key,
-			Value: tag.Value,
-		})
-	}
-	return lfs
-}
diff --git a/lib/promscrape/client.go b/lib/promscrape/client.go
index 93df47862b..d6d4aac9f8 100644
--- a/lib/promscrape/client.go
+++ b/lib/promscrape/client.go
@@ -62,9 +62,21 @@ func addMissingPort(addr string, isTLS bool) string {
 		return addr
 	}
 	if isTLS {
-		return addr + ":443"
+		return concatTwoStrings(addr, ":443")
 	}
-	return addr + ":80"
+	return concatTwoStrings(addr, ":80")
+}
+
+func concatTwoStrings(x, y string) string {
+	bb := bbPool.Get()
+	b := bb.B[:0]
+	b = append(b, x...)
+	b = append(b, y...)
+	s := bytesutil.ToUnsafeString(b)
+	s = bytesutil.InternString(s)
+	bb.B = b
+	bbPool.Put(bb)
+	return s
 }
 
 func newClient(sw *ScrapeWork) *client {
diff --git a/lib/promscrape/config.go b/lib/promscrape/config.go
index d1aa47ab7e..a06686c983 100644
--- a/lib/promscrape/config.go
+++ b/lib/promscrape/config.go
@@ -9,7 +9,6 @@ import (
 	"sort"
 	"strconv"
 	"strings"
-	"sync"
 	"time"
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/auth"
@@ -19,7 +18,6 @@ import (
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/fs"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promauth"
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promrelabel"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discovery/azure"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discovery/consul"
@@ -230,23 +228,7 @@ func (cfg *Config) getJobNames() []string {
 type GlobalConfig struct {
 	ScrapeInterval *promutils.Duration `yaml:"scrape_interval,omitempty"`
 	ScrapeTimeout  *promutils.Duration `yaml:"scrape_timeout,omitempty"`
-	ExternalLabels map[string]string   `yaml:"external_labels,omitempty"`
-}
-
-func (gc *GlobalConfig) getExternalLabels() []prompbmarshal.Label {
-	externalLabels := gc.ExternalLabels
-	if len(externalLabels) == 0 {
-		return nil
-	}
-	labels := make([]prompbmarshal.Label, 0, len(externalLabels))
-	for name, value := range externalLabels {
-		labels = append(labels, prompbmarshal.Label{
-			Name:  name,
-			Value: value,
-		})
-	}
-	promrelabel.SortLabels(labels)
-	return labels
+	ExternalLabels *promutils.Labels   `yaml:"external_labels,omitempty"`
 }
 
 // ScrapeConfig represents essential parts for `scrape_config` section of Prometheus config.
@@ -301,8 +283,8 @@ type ScrapeConfig struct {
 }
 
 func (sc *ScrapeConfig) mustStart(baseDir string) {
-	swosFunc := func(metaLabels map[string]string) interface{} {
-		target := metaLabels["__address__"]
+	swosFunc := func(metaLabels *promutils.Labels) interface{} {
+		target := metaLabels.Get("__address__")
 		sw, err := sc.swc.getScrapeWork(target, nil, metaLabels)
 		if err != nil {
 			logger.Errorf("cannot create kubernetes_sd_config target %q for job_name %q: %s", target, sc.swc.jobName, err)
@@ -367,7 +349,7 @@ type FileSDConfig struct {
 // See https://prometheus.io/docs/prometheus/latest/configuration/configuration/#static_config
 type StaticConfig struct {
 	Targets []string          `yaml:"targets"`
-	Labels  map[string]string `yaml:"labels,omitempty"`
+	Labels  *promutils.Labels `yaml:"labels,omitempty"`
 }
 
 func loadStaticConfigs(path string) ([]StaticConfig, error) {
@@ -723,7 +705,7 @@ func (cfg *Config) getFileSDScrapeWork(prev []*ScrapeWork) []*ScrapeWork {
 	// Create a map for the previous scrape work.
 	swsMapPrev := make(map[string][]*ScrapeWork)
 	for _, sw := range prev {
-		filepath := promrelabel.GetLabelValueByName(sw.Labels, "__vm_filepath")
+		filepath := sw.Labels.Get("__vm_filepath")
 		if len(filepath) == 0 {
 			logger.Panicf("BUG: missing `__vm_filepath` label")
 		} else {
@@ -960,7 +942,7 @@ func getScrapeWorkConfig(sc *ScrapeConfig, baseDir string, globalCfg *GlobalConf
 	if (*streamParse || sc.StreamParse) && sc.SeriesLimit > 0 {
 		return nil, fmt.Errorf("cannot use stream parsing mode when `series_limit` is set for `job_name` %q", jobName)
 	}
-	externalLabels := globalCfg.getExternalLabels()
+	externalLabels := globalCfg.ExternalLabels
 	noStaleTracking := *noStaleMarkers
 	if sc.NoStaleMarkers != nil {
 		noStaleTracking = *sc.NoStaleMarkers
@@ -1010,7 +992,7 @@ type scrapeWorkConfig struct {
 	honorLabels          bool
 	honorTimestamps      bool
 	denyRedirects        bool
-	externalLabels       []prompbmarshal.Label
+	externalLabels       *promutils.Labels
 	relabelConfigs       *promrelabel.ParsedConfigs
 	metricRelabelConfigs *promrelabel.ParsedConfigs
 	sampleLimit          int
@@ -1024,7 +1006,7 @@ type scrapeWorkConfig struct {
 }
 
 type targetLabelsGetter interface {
-	GetLabels(baseDir string) ([]map[string]string, error)
+	GetLabels(baseDir string) ([]*promutils.Labels, error)
 }
 
 func appendSDScrapeWork(dst []*ScrapeWork, sdc targetLabelsGetter, baseDir string, swc *scrapeWorkConfig, discoveryType string) ([]*ScrapeWork, bool) {
@@ -1036,7 +1018,7 @@ func appendSDScrapeWork(dst []*ScrapeWork, sdc targetLabelsGetter, baseDir strin
 	return appendScrapeWorkForTargetLabels(dst, swc, targetLabels, discoveryType), true
 }
 
-func appendScrapeWorkForTargetLabels(dst []*ScrapeWork, swc *scrapeWorkConfig, targetLabels []map[string]string, discoveryType string) []*ScrapeWork {
+func appendScrapeWorkForTargetLabels(dst []*ScrapeWork, swc *scrapeWorkConfig, targetLabels []*promutils.Labels, discoveryType string) []*ScrapeWork {
 	startTime := time.Now()
 	// Process targetLabels in parallel in order to reduce processing time for big number of targetLabels.
 	type result struct {
@@ -1045,11 +1027,11 @@ func appendScrapeWorkForTargetLabels(dst []*ScrapeWork, swc *scrapeWorkConfig, t
 	}
 	goroutines := cgroup.AvailableCPUs()
 	resultCh := make(chan result, len(targetLabels))
-	workCh := make(chan map[string]string, goroutines)
+	workCh := make(chan *promutils.Labels, goroutines)
 	for i := 0; i < goroutines; i++ {
 		go func() {
 			for metaLabels := range workCh {
-				target := metaLabels["__address__"]
+				target := metaLabels.Get("__address__")
 				sw, err := swc.getScrapeWork(target, nil, metaLabels)
 				if err != nil {
 					err = fmt.Errorf("skipping %s target %q for job_name %q because of error: %w", discoveryType, target, swc.jobName, err)
@@ -1080,6 +1062,8 @@ func appendScrapeWorkForTargetLabels(dst []*ScrapeWork, swc *scrapeWorkConfig, t
 }
 
 func (sdc *FileSDConfig) appendScrapeWork(dst []*ScrapeWork, swsMapPrev map[string][]*ScrapeWork, baseDir string, swc *scrapeWorkConfig) []*ScrapeWork {
+	metaLabels := promutils.GetLabels()
+	defer promutils.PutLabels(metaLabels)
 	for _, file := range sdc.Files {
 		pathPattern := fs.GetFilepath(baseDir, file)
 		paths := []string{pathPattern}
@@ -1112,10 +1096,9 @@ func (sdc *FileSDConfig) appendScrapeWork(dst []*ScrapeWork, swsMapPrev map[stri
 					pathShort = pathShort[1:]
 				}
 			}
-			metaLabels := map[string]string{
-				"__meta_filepath": pathShort,
-				"__vm_filepath":   path, // This label is needed for internal promscrape logic
-			}
+			metaLabels.Reset()
+			metaLabels.Add("__meta_filepath", pathShort)
+			metaLabels.Add("__vm_filepath", path) // This label is needed for internal promscrape logic
 			for i := range stcs {
 				dst = stcs[i].appendScrapeWork(dst, swc, metaLabels)
 			}
@@ -1124,7 +1107,7 @@ func (sdc *FileSDConfig) appendScrapeWork(dst []*ScrapeWork, swsMapPrev map[stri
 	return dst
 }
 
-func (stc *StaticConfig) appendScrapeWork(dst []*ScrapeWork, swc *scrapeWorkConfig, metaLabels map[string]string) []*ScrapeWork {
+func (stc *StaticConfig) appendScrapeWork(dst []*ScrapeWork, swc *scrapeWorkConfig, metaLabels *promutils.Labels) []*ScrapeWork {
 	for _, target := range stc.Targets {
 		if target == "" {
 			// Do not return this error, since other targets may be valid
@@ -1144,8 +1127,8 @@ func (stc *StaticConfig) appendScrapeWork(dst []*ScrapeWork, swc *scrapeWorkConf
 	return dst
 }
 
-func appendScrapeWorkKey(dst []byte, labels []prompbmarshal.Label) []byte {
-	for _, label := range labels {
+func appendScrapeWorkKey(dst []byte, labels *promutils.Labels) []byte {
+	for _, label := range labels.GetLabels() {
 		// Do not use strconv.AppendQuote, since it is slow according to CPU profile.
 		dst = append(dst, label.Name...)
 		dst = append(dst, '=')
@@ -1176,45 +1159,20 @@ func needSkipScrapeWork(key string, membersCount, replicasCount, memberNum int)
 	return true
 }
 
-type labelsContext struct {
-	labels []prompbmarshal.Label
-}
-
-func getLabelsContext() *labelsContext {
-	v := labelsContextPool.Get()
-	if v == nil {
-		return &labelsContext{}
-	}
-	return v.(*labelsContext)
-}
-
-func putLabelsContext(lctx *labelsContext) {
-	labels := lctx.labels
-	for i := range labels {
-		labels[i].Name = ""
-		labels[i].Value = ""
-	}
-	lctx.labels = lctx.labels[:0]
-	labelsContextPool.Put(lctx)
-}
-
-var labelsContextPool sync.Pool
-
 var scrapeWorkKeyBufPool bytesutil.ByteBufferPool
 
-func (swc *scrapeWorkConfig) getScrapeWork(target string, extraLabels, metaLabels map[string]string) (*ScrapeWork, error) {
-	lctx := getLabelsContext()
-	defer putLabelsContext(lctx)
+func (swc *scrapeWorkConfig) getScrapeWork(target string, extraLabels, metaLabels *promutils.Labels) (*ScrapeWork, error) {
+	labels := promutils.GetLabels()
+	defer promutils.PutLabels(labels)
 
-	labels := mergeLabels(lctx.labels[:0], swc, target, extraLabels, metaLabels)
-	var originalLabels []prompbmarshal.Label
+	mergeLabels(labels, swc, target, extraLabels, metaLabels)
+	var originalLabels *promutils.Labels
 	if !*dropOriginalLabels {
-		originalLabels = append([]prompbmarshal.Label{}, labels...)
+		originalLabels = labels.Clone()
 	}
-	labels = swc.relabelConfigs.Apply(labels, 0)
+	labels.Labels = swc.relabelConfigs.Apply(labels.Labels, 0)
 	// Remove labels starting from "__meta_" prefix according to https://www.robustperception.io/life-of-a-label/
-	labels = promrelabel.RemoveMetaLabels(labels[:0], labels)
-	lctx.labels = labels
+	labels.RemoveMetaLabels()
 
 	// Verify whether the scrape work must be skipped because of `-promscrape.cluster.*` configs.
 	// Perform the verification on labels after the relabeling in order to guarantee that targets with the same set of labels
@@ -1230,25 +1188,25 @@ func (swc *scrapeWorkConfig) getScrapeWork(target string, extraLabels, metaLabel
 		}
 	}
 	if !*dropOriginalLabels {
-		promrelabel.SortLabels(originalLabels)
+		originalLabels.Sort()
 		// Reduce memory usage by interning all the strings in originalLabels.
-		internLabelStrings(originalLabels)
+		originalLabels.InternStrings()
 	}
-	if len(labels) == 0 {
+	if labels.Len() == 0 {
 		// Drop target without labels.
 		droppedTargetsMap.Register(originalLabels)
 		return nil, nil
 	}
 	// See https://www.robustperception.io/life-of-a-label
-	scheme := promrelabel.GetLabelValueByName(labels, "__scheme__")
+	scheme := labels.Get("__scheme__")
 	if len(scheme) == 0 {
 		scheme = "http"
 	}
-	metricsPath := promrelabel.GetLabelValueByName(labels, "__metrics_path__")
+	metricsPath := labels.Get("__metrics_path__")
 	if len(metricsPath) == 0 {
 		metricsPath = "/metrics"
 	}
-	address := promrelabel.GetLabelValueByName(labels, "__address__")
+	address := labels.Get("__address__")
 	if len(address) == 0 {
 		// Drop target without scrape address.
 		droppedTargetsMap.Register(originalLabels)
@@ -1271,7 +1229,7 @@ func (swc *scrapeWorkConfig) getScrapeWork(target string, extraLabels, metaLabel
 	address = addMissingPort(address, scheme == "https")
 
 	var at *auth.Token
-	tenantID := promrelabel.GetLabelValueByName(labels, "__tenant_id__")
+	tenantID := labels.Get("__tenant_id__")
 	if len(tenantID) > 0 {
 		newToken, err := auth.NewToken(tenantID)
 		if err != nil {
@@ -1292,14 +1250,14 @@ func (swc *scrapeWorkConfig) getScrapeWork(target string, extraLabels, metaLabel
 		}
 	}
 	paramsStr := url.Values(params).Encode()
-	scrapeURL := fmt.Sprintf("%s://%s%s%s%s", scheme, address, metricsPath, optionalQuestion, paramsStr)
+	scrapeURL := getScrapeURL(scheme, address, metricsPath, optionalQuestion, paramsStr)
 	if _, err := url.Parse(scrapeURL); err != nil {
 		return nil, fmt.Errorf("invalid url %q for scheme=%q, target=%q, address=%q, metrics_path=%q for job=%q: %w",
 			scrapeURL, scheme, target, address, metricsPath, swc.jobName, err)
 	}
 	// Read __scrape_interval__ and __scrape_timeout__ from labels.
 	scrapeInterval := swc.scrapeInterval
-	if s := promrelabel.GetLabelValueByName(labels, "__scrape_interval__"); len(s) > 0 {
+	if s := labels.Get("__scrape_interval__"); len(s) > 0 {
 		d, err := promutils.ParseDuration(s)
 		if err != nil {
 			return nil, fmt.Errorf("cannot parse __scrape_interval__=%q: %w", s, err)
@@ -1307,7 +1265,7 @@ func (swc *scrapeWorkConfig) getScrapeWork(target string, extraLabels, metaLabel
 		scrapeInterval = d
 	}
 	scrapeTimeout := swc.scrapeTimeout
-	if s := promrelabel.GetLabelValueByName(labels, "__scrape_timeout__"); len(s) > 0 {
+	if s := labels.Get("__scrape_timeout__"); len(s) > 0 {
 		d, err := promutils.ParseDuration(s)
 		if err != nil {
 			return nil, fmt.Errorf("cannot parse __scrape_timeout__=%q: %w", s, err)
@@ -1317,7 +1275,7 @@ func (swc *scrapeWorkConfig) getScrapeWork(target string, extraLabels, metaLabel
 	// Read series_limit option from __series_limit__ label.
 	// See https://docs.victoriametrics.com/vmagent.html#cardinality-limiter
 	seriesLimit := swc.seriesLimit
-	if s := promrelabel.GetLabelValueByName(labels, "__series_limit__"); len(s) > 0 {
+	if s := labels.Get("__series_limit__"); len(s) > 0 {
 		n, err := strconv.Atoi(s)
 		if err != nil {
 			return nil, fmt.Errorf("cannot parse __series_limit__=%q: %w", s, err)
@@ -1327,7 +1285,7 @@ func (swc *scrapeWorkConfig) getScrapeWork(target string, extraLabels, metaLabel
 	// Read stream_parse option from __stream_parse__ label.
 	// See https://docs.victoriametrics.com/vmagent.html#stream-parsing-mode
 	streamParse := swc.streamParse
-	if s := promrelabel.GetLabelValueByName(labels, "__stream_parse__"); len(s) > 0 {
+	if s := labels.Get("__stream_parse__"); len(s) > 0 {
 		b, err := strconv.ParseBool(s)
 		if err != nil {
 			return nil, fmt.Errorf("cannot parse __stream_parse__=%q: %w", s, err)
@@ -1335,22 +1293,19 @@ func (swc *scrapeWorkConfig) getScrapeWork(target string, extraLabels, metaLabel
 		streamParse = b
 	}
 	// Remove labels with "__" prefix according to https://www.robustperception.io/life-of-a-label/
-	labels = promrelabel.RemoveLabelsWithDoubleDashPrefix(labels[:0], labels)
-	// Remove references to deleted labels, so GC could clean strings for label name and label value past len(labels).
+	labels.RemoveLabelsWithDoubleUnderscorePrefix()
+	// Add missing "instance" label according to https://www.robustperception.io/life-of-a-label
+	if labels.Get("instance") == "" {
+		labels.Add("instance", address)
+	}
+	// Remove references to deleted labels, so GC could clean strings for label name and label value past len(labels.Labels).
 	// This should reduce memory usage when relabeling creates big number of temporary labels with long names and/or values.
 	// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/825 for details.
-	labelsCopy := make([]prompbmarshal.Label, len(labels)+1)
-	labels = append(labelsCopy[:0], labels...)
-	// Add missing "instance" label according to https://www.robustperception.io/life-of-a-label
-	if promrelabel.GetLabelByName(labels, "instance") == nil {
-		labels = append(labels, prompbmarshal.Label{
-			Name:  "instance",
-			Value: address,
-		})
-	}
-	promrelabel.SortLabels(labels)
+	labelsCopy := labels.Clone()
+	// Sort labels in alphabetical order of their names.
+	labelsCopy.Sort()
 	// Reduce memory usage by interning all the strings in labels.
-	internLabelStrings(labels)
+	labelsCopy.InternStrings()
 
 	sw := &ScrapeWork{
 		ScrapeURL:            scrapeURL,
@@ -1360,7 +1315,7 @@ func (swc *scrapeWorkConfig) getScrapeWork(target string, extraLabels, metaLabel
 		HonorTimestamps:      swc.honorTimestamps,
 		DenyRedirects:        swc.denyRedirects,
 		OriginalLabels:       originalLabels,
-		Labels:               labels,
+		Labels:               labelsCopy,
 		ExternalLabels:       swc.externalLabels,
 		ProxyURL:             swc.proxyURL,
 		ProxyAuthConfig:      swc.proxyAuthConfig,
@@ -1381,19 +1336,26 @@ func (swc *scrapeWorkConfig) getScrapeWork(target string, extraLabels, metaLabel
 	return sw, nil
 }
 
-func internLabelStrings(labels []prompbmarshal.Label) {
-	for i := range labels {
-		label := &labels[i]
-		label.Name = bytesutil.InternString(label.Name)
-		label.Value = bytesutil.InternString(label.Value)
-	}
+func getScrapeURL(scheme, address, metricsPath, optionalQuestion, paramsStr string) string {
+	bb := bbPool.Get()
+	b := bb.B[:0]
+	b = append(b, scheme...)
+	b = append(b, "://"...)
+	b = append(b, address...)
+	b = append(b, metricsPath...)
+	b = append(b, optionalQuestion...)
+	b = append(b, paramsStr...)
+	s := bytesutil.ToUnsafeString(b)
+	s = bytesutil.InternString(s)
+	bb.B = b
+	bbPool.Put(bb)
+	return s
 }
 
-func getParamsFromLabels(labels []prompbmarshal.Label, paramsOrig map[string][]string) map[string][]string {
+func getParamsFromLabels(labels *promutils.Labels, paramsOrig map[string][]string) map[string][]string {
 	// See https://www.robustperception.io/life-of-a-label
-	m := make(map[string][]string)
-	for i := range labels {
-		label := &labels[i]
+	var m map[string][]string
+	for _, label := range labels.GetLabels() {
 		if !strings.HasPrefix(label.Name, "__param_") {
 			continue
 		}
@@ -1402,79 +1364,36 @@ func getParamsFromLabels(labels []prompbmarshal.Label, paramsOrig map[string][]s
 		if p := paramsOrig[name]; len(p) > 1 {
 			values = append(values, p[1:]...)
 		}
+		if m == nil {
+			m = make(map[string][]string)
+		}
 		m[name] = values
 	}
 	return m
 }
 
-func mergeLabels(dst []prompbmarshal.Label, swc *scrapeWorkConfig, target string, extraLabels, metaLabels map[string]string) []prompbmarshal.Label {
-	if len(dst) > 0 {
-		logger.Panicf("BUG: len(dst) must be 0; got %d", len(dst))
+func mergeLabels(dst *promutils.Labels, swc *scrapeWorkConfig, target string, extraLabels, metaLabels *promutils.Labels) {
+	if n := dst.Len(); n > 0 {
+		logger.Panicf("BUG: len(dst.Labels) must be 0; got %d", n)
 	}
 	// See https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config
-	dst = appendLabel(dst, "job", swc.jobName)
-	dst = appendLabel(dst, "__address__", target)
-	dst = appendLabel(dst, "__scheme__", swc.scheme)
-	dst = appendLabel(dst, "__metrics_path__", swc.metricsPath)
-	dst = appendLabel(dst, "__scrape_interval__", swc.scrapeIntervalString)
-	dst = appendLabel(dst, "__scrape_timeout__", swc.scrapeTimeoutString)
+	dst.Add("job", swc.jobName)
+	dst.Add("__address__", target)
+	dst.Add("__scheme__", swc.scheme)
+	dst.Add("__metrics_path__", swc.metricsPath)
+	dst.Add("__scrape_interval__", swc.scrapeIntervalString)
+	dst.Add("__scrape_timeout__", swc.scrapeTimeoutString)
 	for k, args := range swc.params {
 		if len(args) == 0 {
 			continue
 		}
 		k = "__param_" + k
 		v := args[0]
-		dst = appendLabel(dst, k, v)
+		dst.Add(k, v)
 	}
-	for k, v := range extraLabels {
-		dst = appendLabel(dst, k, v)
-	}
-	for k, v := range metaLabels {
-		dst = appendLabel(dst, k, v)
-	}
-	if len(dst) < 2 {
-		return dst
-	}
-	// Remove duplicate labels if any.
-	// Stable sorting is needed in order to preserve the order for labels with identical names.
-	// This is needed in order to remove labels with duplicate names other than the last one.
-	promrelabel.SortLabelsStable(dst)
-	prevName := dst[0].Name
-	hasDuplicateLabels := false
-	for _, label := range dst[1:] {
-		if label.Name == prevName {
-			hasDuplicateLabels = true
-			break
-		}
-		prevName = label.Name
-	}
-	if !hasDuplicateLabels {
-		return dst
-	}
-	prevName = dst[0].Name
-	tmp := dst[:1]
-	for _, label := range dst[1:] {
-		if label.Name == prevName {
-			tmp[len(tmp)-1] = label
-		} else {
-			tmp = append(tmp, label)
-			prevName = label.Name
-		}
-	}
-	tail := dst[len(tmp):]
-	for i := range tail {
-		label := &tail[i]
-		label.Name = ""
-		label.Value = ""
-	}
-	return tmp
-}
-
-func appendLabel(dst []prompbmarshal.Label, name, value string) []prompbmarshal.Label {
-	return append(dst, prompbmarshal.Label{
-		Name:  name,
-		Value: value,
-	})
+	dst.AddFrom(extraLabels)
+	dst.AddFrom(metaLabels)
+	dst.RemoveDuplicates()
 }
 
 const (
diff --git a/lib/promscrape/config_test.go b/lib/promscrape/config_test.go
index 2ea4f0f0c3..b6c1f3bd49 100644
--- a/lib/promscrape/config_test.go
+++ b/lib/promscrape/config_test.go
@@ -10,7 +10,6 @@ import (
 	"time"
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promauth"
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promrelabel"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discovery/gce"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
@@ -18,11 +17,13 @@ import (
 )
 
 func TestMergeLabels(t *testing.T) {
-	f := func(swc *scrapeWorkConfig, target string, extraLabels, metaLabels map[string]string, resultExpected string) {
+	f := func(swc *scrapeWorkConfig, target string, extraLabelsMap, metaLabelsMap map[string]string, resultExpected string) {
 		t.Helper()
-		var labels []prompbmarshal.Label
-		labels = mergeLabels(labels[:0], swc, target, extraLabels, metaLabels)
-		result := promLabelsString(labels)
+		extraLabels := promutils.NewLabelsFromMap(extraLabelsMap)
+		metaLabels := promutils.NewLabelsFromMap(metaLabelsMap)
+		labels := promutils.NewLabels(0)
+		mergeLabels(labels, swc, target, extraLabels, metaLabels)
+		result := labels.String()
 		if result != resultExpected {
 			t.Fatalf("unexpected result;\ngot\n%s\nwant\n%s", result, resultExpected)
 		}
@@ -247,16 +248,10 @@ scrape_configs:
 			ScrapeInterval:  defaultScrapeInterval,
 			ScrapeTimeout:   defaultScrapeTimeout,
 			HonorTimestamps: true,
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "instance",
-					Value: "host1:80",
-				},
-				{
-					Name:  "job",
-					Value: "abc",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"instance": "host1:80",
+				"job":      "abc",
+			}),
 			AuthConfig:      &promauth.Config{},
 			ProxyAuthConfig: &promauth.Config{},
 			jobNameOriginal: "abc",
@@ -266,16 +261,10 @@ scrape_configs:
 			ScrapeInterval:  defaultScrapeInterval,
 			ScrapeTimeout:   defaultScrapeTimeout,
 			HonorTimestamps: true,
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "instance",
-					Value: "host2:443",
-				},
-				{
-					Name:  "job",
-					Value: "abc",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"instance": "host2:443",
+				"job":      "abc",
+			}),
 			AuthConfig:      &promauth.Config{},
 			ProxyAuthConfig: &promauth.Config{},
 			jobNameOriginal: "abc",
@@ -285,16 +274,10 @@ scrape_configs:
 			ScrapeInterval:  defaultScrapeInterval,
 			ScrapeTimeout:   defaultScrapeTimeout,
 			HonorTimestamps: true,
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "instance",
-					Value: "host3:1234",
-				},
-				{
-					Name:  "job",
-					Value: "abc",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"instance": "host3:1234",
+				"job":      "abc",
+			}),
 			AuthConfig:      &promauth.Config{},
 			ProxyAuthConfig: &promauth.Config{},
 			jobNameOriginal: "abc",
@@ -304,16 +287,10 @@ scrape_configs:
 			ScrapeInterval:  defaultScrapeInterval,
 			ScrapeTimeout:   defaultScrapeTimeout,
 			HonorTimestamps: true,
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "instance",
-					Value: "host4:1234",
-				},
-				{
-					Name:  "job",
-					Value: "abc",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"instance": "host4:1234",
+				"job":      "abc",
+			}),
 			AuthConfig:      &promauth.Config{},
 			ProxyAuthConfig: &promauth.Config{},
 			jobNameOriginal: "abc",
@@ -358,16 +335,10 @@ scrape_configs:
 		ScrapeInterval:  defaultScrapeInterval,
 		ScrapeTimeout:   defaultScrapeTimeout,
 		HonorTimestamps: true,
-		Labels: []prompbmarshal.Label{
-			{
-				Name:  "instance",
-				Value: "8.8.8.8",
-			},
-			{
-				Name:  "job",
-				Value: "blackbox",
-			},
-		},
+		Labels: promutils.NewLabelsFromMap(map[string]string{
+			"instance": "8.8.8.8",
+			"job":      "blackbox",
+		}),
 		AuthConfig:      &promauth.Config{},
 		ProxyAuthConfig: &promauth.Config{},
 		jobNameOriginal: "blackbox",
@@ -770,8 +741,9 @@ func TestGetFileSDScrapeWorkSuccess(t *testing.T) {
 
 		// Remove `__vm_filepath` label, since its value depends on the current working dir.
 		for _, sw := range sws {
-			for j := range sw.Labels {
-				label := &sw.Labels[j]
+			labels := sw.Labels.GetLabels()
+			for j := range labels {
+				label := &labels[j]
 				if label.Name == "__vm_filepath" {
 					label.Value = ""
 				}
@@ -799,24 +771,12 @@ scrape_configs:
 			ScrapeInterval:  defaultScrapeInterval,
 			ScrapeTimeout:   defaultScrapeTimeout,
 			HonorTimestamps: true,
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "__vm_filepath",
-					Value: "",
-				},
-				{
-					Name:  "instance",
-					Value: "host1:80",
-				},
-				{
-					Name:  "job",
-					Value: "foo",
-				},
-				{
-					Name:  "qwe",
-					Value: "rty",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"__vm_filepath": "",
+				"instance":      "host1:80",
+				"job":           "foo",
+				"qwe":           "rty",
+			}),
 			AuthConfig:      &promauth.Config{},
 			ProxyAuthConfig: &promauth.Config{},
 			jobNameOriginal: "foo",
@@ -826,24 +786,12 @@ scrape_configs:
 			ScrapeInterval:  defaultScrapeInterval,
 			ScrapeTimeout:   defaultScrapeTimeout,
 			HonorTimestamps: true,
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "__vm_filepath",
-					Value: "",
-				},
-				{
-					Name:  "instance",
-					Value: "host2:80",
-				},
-				{
-					Name:  "job",
-					Value: "foo",
-				},
-				{
-					Name:  "qwe",
-					Value: "rty",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"__vm_filepath": "",
+				"instance":      "host2:80",
+				"job":           "foo",
+				"qwe":           "rty",
+			}),
 			AuthConfig:      &promauth.Config{},
 			ProxyAuthConfig: &promauth.Config{},
 			jobNameOriginal: "foo",
@@ -853,24 +801,12 @@ scrape_configs:
 			ScrapeInterval:  defaultScrapeInterval,
 			ScrapeTimeout:   defaultScrapeTimeout,
 			HonorTimestamps: true,
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "__vm_filepath",
-					Value: "",
-				},
-				{
-					Name:  "instance",
-					Value: "localhost:9090",
-				},
-				{
-					Name:  "job",
-					Value: "foo",
-				},
-				{
-					Name:  "yml",
-					Value: "test",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"__vm_filepath": "",
+				"instance":      "localhost:9090",
+				"job":           "foo",
+				"yml":           "test",
+			}),
 			AuthConfig:      &promauth.Config{},
 			ProxyAuthConfig: &promauth.Config{},
 			jobNameOriginal: "foo",
@@ -902,16 +838,10 @@ scrape_configs:
 			ScrapeInterval:  defaultScrapeInterval,
 			ScrapeTimeout:   defaultScrapeTimeout,
 			HonorTimestamps: true,
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "instance",
-					Value: "foo.bar:1234",
-				},
-				{
-					Name:  "job",
-					Value: "foo",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"instance": "foo.bar:1234",
+				"job":      "foo",
+			}),
 			AuthConfig:      &promauth.Config{},
 			ProxyAuthConfig: &promauth.Config{},
 			jobNameOriginal: "foo",
@@ -932,26 +862,14 @@ scrape_configs:
 			ScrapeInterval:  defaultScrapeInterval,
 			ScrapeTimeout:   defaultScrapeTimeout,
 			HonorTimestamps: true,
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "instance",
-					Value: "foo.bar:1234",
-				},
-				{
-					Name:  "job",
-					Value: "foo",
-				},
-			},
-			ExternalLabels: []prompbmarshal.Label{
-				{
-					Name:  "datacenter",
-					Value: "foobar",
-				},
-				{
-					Name:  "jobs",
-					Value: "xxx",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"instance": "foo.bar:1234",
+				"job":      "foo",
+			}),
+			ExternalLabels: promutils.NewLabelsFromMap(map[string]string{
+				"datacenter": "foobar",
+				"jobs":       "xxx",
+			}),
 			AuthConfig:      &promauth.Config{},
 			ProxyAuthConfig: &promauth.Config{},
 			jobNameOriginal: "foo",
@@ -996,20 +914,11 @@ scrape_configs:
 			HonorLabels:     true,
 			HonorTimestamps: false,
 			DenyRedirects:   true,
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "instance",
-					Value: "foo.bar:443",
-				},
-				{
-					Name:  "job",
-					Value: "foo",
-				},
-				{
-					Name:  "x",
-					Value: "y",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"instance": "foo.bar:443",
+				"job":      "foo",
+				"x":        "y",
+			}),
 			AuthConfig:      &promauth.Config{},
 			ProxyAuthConfig: &promauth.Config{},
 			ProxyURL:        proxy.MustNewURL("http://foo.bar"),
@@ -1022,20 +931,11 @@ scrape_configs:
 			HonorLabels:     true,
 			HonorTimestamps: false,
 			DenyRedirects:   true,
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "instance",
-					Value: "aaa:443",
-				},
-				{
-					Name:  "job",
-					Value: "foo",
-				},
-				{
-					Name:  "x",
-					Value: "y",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"instance": "aaa:443",
+				"job":      "foo",
+				"x":        "y",
+			}),
 			AuthConfig:      &promauth.Config{},
 			ProxyAuthConfig: &promauth.Config{},
 			ProxyURL:        proxy.MustNewURL("http://foo.bar"),
@@ -1046,16 +946,10 @@ scrape_configs:
 			ScrapeInterval:  8 * time.Second,
 			ScrapeTimeout:   8 * time.Second,
 			HonorTimestamps: true,
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "instance",
-					Value: "1.2.3.4:80",
-				},
-				{
-					Name:  "job",
-					Value: "qwer",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"instance": "1.2.3.4:80",
+				"job":      "qwer",
+			}),
 			AuthConfig: &promauth.Config{
 				TLSServerName:         "foobar",
 				TLSInsecureSkipVerify: true,
@@ -1068,16 +962,10 @@ scrape_configs:
 			ScrapeInterval:  8 * time.Second,
 			ScrapeTimeout:   8 * time.Second,
 			HonorTimestamps: true,
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "instance",
-					Value: "foobar:80",
-				},
-				{
-					Name:  "job",
-					Value: "asdf",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"instance": "foobar:80",
+				"job":      "asdf",
+			}),
 			AuthConfig:      &promauth.Config{},
 			ProxyAuthConfig: &promauth.Config{},
 			jobNameOriginal: "asdf",
@@ -1124,24 +1012,12 @@ scrape_configs:
 			ScrapeInterval:  defaultScrapeInterval,
 			ScrapeTimeout:   defaultScrapeTimeout,
 			HonorTimestamps: true,
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "hash",
-					Value: "82",
-				},
-				{
-					Name:  "instance",
-					Value: "foo.bar:1234",
-				},
-				{
-					Name:  "prefix:url",
-					Value: "http://foo.bar:1234/metrics",
-				},
-				{
-					Name:  "url",
-					Value: "http://foo.bar:1234/metrics",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"hash":       "82",
+				"instance":   "foo.bar:1234",
+				"prefix:url": "http://foo.bar:1234/metrics",
+				"url":        "http://foo.bar:1234/metrics",
+			}),
 			AuthConfig:      &promauth.Config{},
 			ProxyAuthConfig: &promauth.Config{},
 			jobNameOriginal: "foo",
@@ -1180,16 +1056,10 @@ scrape_configs:
 			ScrapeInterval:  defaultScrapeInterval,
 			ScrapeTimeout:   defaultScrapeTimeout,
 			HonorTimestamps: true,
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "instance",
-					Value: "fake.addr",
-				},
-				{
-					Name:  "job",
-					Value: "https",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"instance": "fake.addr",
+				"job":      "https",
+			}),
 			AuthConfig:      &promauth.Config{},
 			ProxyAuthConfig: &promauth.Config{},
 			jobNameOriginal: "foo",
@@ -1221,16 +1091,10 @@ scrape_configs:
 			ScrapeInterval:  defaultScrapeInterval,
 			ScrapeTimeout:   defaultScrapeTimeout,
 			HonorTimestamps: true,
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "instance",
-					Value: "foo.bar:1234",
-				},
-				{
-					Name:  "job",
-					Value: "3",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"instance": "foo.bar:1234",
+				"job":      "3",
+			}),
 			AuthConfig:      &promauth.Config{},
 			ProxyAuthConfig: &promauth.Config{},
 			jobNameOriginal: "foo",
@@ -1251,16 +1115,10 @@ scrape_configs:
 			ScrapeInterval:  defaultScrapeInterval,
 			ScrapeTimeout:   defaultScrapeTimeout,
 			HonorTimestamps: true,
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "instance",
-					Value: "foo.bar:1234",
-				},
-				{
-					Name:  "job",
-					Value: "foo",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"instance": "foo.bar:1234",
+				"job":      "foo",
+			}),
 			AuthConfig:      &promauth.Config{},
 			ProxyAuthConfig: &promauth.Config{},
 			jobNameOriginal: "foo",
@@ -1277,16 +1135,10 @@ scrape_configs:
 			ScrapeInterval:  defaultScrapeInterval,
 			ScrapeTimeout:   defaultScrapeTimeout,
 			HonorTimestamps: true,
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "instance",
-					Value: "foo.bar:1234",
-				},
-				{
-					Name:  "job",
-					Value: "foo",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"instance": "foo.bar:1234",
+				"job":      "foo",
+			}),
 			AuthConfig:      &promauth.Config{},
 			ProxyAuthConfig: &promauth.Config{},
 			jobNameOriginal: "foo",
@@ -1303,16 +1155,10 @@ scrape_configs:
 			ScrapeInterval:  defaultScrapeInterval,
 			ScrapeTimeout:   defaultScrapeTimeout,
 			HonorTimestamps: true,
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "instance",
-					Value: "foo.bar:1234",
-				},
-				{
-					Name:  "job",
-					Value: "foo",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"instance": "foo.bar:1234",
+				"job":      "foo",
+			}),
 			AuthConfig:      &promauth.Config{},
 			ProxyAuthConfig: &promauth.Config{},
 			jobNameOriginal: "foo",
@@ -1343,42 +1189,18 @@ scrape_configs:
 			ScrapeInterval:  defaultScrapeInterval,
 			ScrapeTimeout:   defaultScrapeTimeout,
 			HonorTimestamps: true,
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "foo",
-					Value: "bar",
-				},
-				{
-					Name:  "instance",
-					Value: "pp:80",
-				},
-				{
-					Name:  "job",
-					Value: "yyy",
-				},
-			},
-			ExternalLabels: []prompbmarshal.Label{
-				{
-					Name:  "__address__",
-					Value: "aaasdf",
-				},
-				{
-					Name:  "__param_a",
-					Value: "jlfd",
-				},
-				{
-					Name:  "foo",
-					Value: "xx",
-				},
-				{
-					Name:  "job",
-					Value: "foobar",
-				},
-				{
-					Name:  "q",
-					Value: "qwe",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"foo":      "bar",
+				"instance": "pp:80",
+				"job":      "yyy",
+			}),
+			ExternalLabels: promutils.NewLabelsFromMap(map[string]string{
+				"__address__": "aaasdf",
+				"__param_a":   "jlfd",
+				"foo":         "xx",
+				"job":         "foobar",
+				"q":           "qwe",
+			}),
 			AuthConfig:      &promauth.Config{},
 			ProxyAuthConfig: &promauth.Config{},
 			jobNameOriginal: "aaa",
@@ -1434,16 +1256,10 @@ scrape_configs:
 			ScrapeInterval:  defaultScrapeInterval,
 			ScrapeTimeout:   defaultScrapeTimeout,
 			HonorTimestamps: true,
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "instance",
-					Value: "192.168.1.2",
-				},
-				{
-					Name:  "job",
-					Value: "snmp",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"instance": "192.168.1.2",
+				"job":      "snmp",
+			}),
 			AuthConfig:          ac,
 			ProxyAuthConfig:     proxyAC,
 			SampleLimit:         100,
@@ -1470,16 +1286,10 @@ scrape_configs:
 			ScrapeInterval:  defaultScrapeInterval,
 			ScrapeTimeout:   defaultScrapeTimeout,
 			HonorTimestamps: true,
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "instance",
-					Value: "foo.bar:1234",
-				},
-				{
-					Name:  "job",
-					Value: "path wo slash",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"instance": "foo.bar:1234",
+				"job":      "path wo slash",
+			}),
 			jobNameOriginal: "path wo slash",
 			AuthConfig:      &promauth.Config{},
 			ProxyAuthConfig: &promauth.Config{},
@@ -1505,16 +1315,10 @@ scrape_configs:
 			ScrapeOffset:        time.Hour * 24 * 2,
 			HonorTimestamps:     true,
 			NoStaleMarkers:      true,
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "instance",
-					Value: "foo.bar:1234",
-				},
-				{
-					Name:  "job",
-					Value: "foo",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"instance": "foo.bar:1234",
+				"job":      "foo",
+			}),
 			AuthConfig:      &promauth.Config{},
 			ProxyAuthConfig: &promauth.Config{},
 			jobNameOriginal: "foo",
diff --git a/lib/promscrape/config_timing_test.go b/lib/promscrape/config_timing_test.go
index 293e7f94ed..bf94d22531 100644
--- a/lib/promscrape/config_timing_test.go
+++ b/lib/promscrape/config_timing_test.go
@@ -1,31 +1,42 @@
 package promscrape
 
 import (
+	"fmt"
 	"testing"
 
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
-func BenchmarkInternLabelStrings(b *testing.B) {
+func BenchmarkGetScrapeWork(b *testing.B) {
+	swc := &scrapeWorkConfig{
+		jobName:              "job-1",
+		scheme:               "http",
+		metricsPath:          "/metrics",
+		scrapeIntervalString: "30s",
+		scrapeTimeoutString:  "10s",
+	}
+	target := "host1.com:1234"
+	extraLabels := promutils.NewLabelsFromMap(map[string]string{
+		"env":        "prod",
+		"datacenter": "dc-foo",
+	})
+	metaLabels := promutils.NewLabelsFromMap(map[string]string{
+		"__meta_foo":                         "bar",
+		"__meta_kubernetes_namespace":        "default",
+		"__address__":                        "foobar.com",
+		"__meta_sfdfdf_dsfds_fdfdfds_fdfdfd": "true",
+	})
 	b.ReportAllocs()
 	b.SetBytes(1)
 	b.RunParallel(func(pb *testing.PB) {
-		labels := []prompbmarshal.Label{
-			{
-				Name:  "job",
-				Value: "node-exporter",
-			},
-			{
-				Name:  "instance",
-				Value: "foo.bar.baz:1234",
-			},
-			{
-				Name:  "__meta_kubernetes_namespace",
-				Value: "default",
-			},
-		}
 		for pb.Next() {
-			internLabelStrings(labels)
+			sw, err := swc.getScrapeWork(target, extraLabels, metaLabels)
+			if err != nil {
+				panic(fmt.Errorf("BUG: getScrapeWork returned non-nil error: %w", err))
+			}
+			if sw == nil {
+				panic(fmt.Errorf("BUG: getScrapeWork returned nil ScrapeWork"))
+			}
 		}
 	})
 }
diff --git a/lib/promscrape/discovery/azure/azure.go b/lib/promscrape/discovery/azure/azure.go
index a41f77054d..d8f77e8c61 100644
--- a/lib/promscrape/discovery/azure/azure.go
+++ b/lib/promscrape/discovery/azure/azure.go
@@ -8,6 +8,7 @@ import (
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promauth"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/proxy"
 )
 
@@ -43,7 +44,7 @@ type SDConfig struct {
 }
 
 // GetLabels returns Consul labels according to sdc.
-func (sdc *SDConfig) GetLabels(baseDir string) ([]map[string]string, error) {
+func (sdc *SDConfig) GetLabels(baseDir string) ([]*promutils.Labels, error) {
 	ac, err := getAPIConfig(sdc, baseDir)
 	if err != nil {
 		return nil, fmt.Errorf("cannot get API config: %w", err)
@@ -60,8 +61,8 @@ func (sdc *SDConfig) MustStop() {
 	configMap.Delete(sdc)
 }
 
-func appendMachineLabels(vms []virtualMachine, port int, sdc *SDConfig) []map[string]string {
-	ms := make([]map[string]string, 0, len(vms))
+func appendMachineLabels(vms []virtualMachine, port int, sdc *SDConfig) []*promutils.Labels {
+	ms := make([]*promutils.Labels, 0, len(vms))
 	for i := range vms {
 		vm := &vms[i]
 		for _, ips := range vm.ipAddresses {
@@ -69,36 +70,35 @@ func appendMachineLabels(vms []virtualMachine, port int, sdc *SDConfig) []map[st
 				continue
 			}
 			addr := discoveryutils.JoinHostPort(ips.privateIP, port)
-			m := map[string]string{
-				"__address__":                     addr,
-				"__meta_azure_subscription_id":    sdc.SubscriptionID,
-				"__meta_azure_machine_id":         vm.ID,
-				"__meta_azure_machine_name":       vm.Name,
-				"__meta_azure_machine_location":   vm.Location,
-				"__meta_azure_machine_private_ip": ips.privateIP,
-			}
+			m := promutils.NewLabels(16)
+			m.Add("__address__", addr)
+			m.Add("__meta_azure_subscription_id", sdc.SubscriptionID)
+			m.Add("__meta_azure_machine_id", vm.ID)
+			m.Add("__meta_azure_machine_name", vm.Name)
+			m.Add("__meta_azure_machine_location", vm.Location)
+			m.Add("__meta_azure_machine_private_ip", ips.privateIP)
 			if sdc.TenantID != "" {
-				m["__meta_azure_tenant_id"] = sdc.TenantID
+				m.Add("__meta_azure_tenant_id", sdc.TenantID)
 			}
 			// /subscriptions/SUBSCRIPTION_ID/resourceGroups/RESOURCE_GROUP/providers/PROVIDER/TYPE/NAME
 			idPath := strings.Split(vm.ID, "/")
 			if len(idPath) > 4 {
-				m["__meta_azure_machine_resource_group"] = idPath[4]
+				m.Add("__meta_azure_machine_resource_group", idPath[4])
 			}
 			if vm.Properties.StorageProfile.OsDisk.OsType != "" {
-				m["__meta_azure_machine_os_type"] = vm.Properties.StorageProfile.OsDisk.OsType
+				m.Add("__meta_azure_machine_os_type", vm.Properties.StorageProfile.OsDisk.OsType)
 			}
 			if vm.Properties.OsProfile.ComputerName != "" {
-				m["__meta_azure_machine_computer_name"] = vm.Properties.OsProfile.ComputerName
+				m.Add("__meta_azure_machine_computer_name", vm.Properties.OsProfile.ComputerName)
 			}
 			if ips.publicIP != "" {
-				m["__meta_azure_machine_public_ip"] = ips.publicIP
+				m.Add("__meta_azure_machine_public_ip", ips.publicIP)
 			}
 			if vm.scaleSet != "" {
-				m["__meta_azure_machine_scale_set"] = vm.scaleSet
+				m.Add("__meta_azure_machine_scale_set", vm.scaleSet)
 			}
 			for k, v := range vm.Tags {
-				m[discoveryutils.SanitizeLabelName("__meta_azure_machine_tag_"+k)] = v
+				m.Add(discoveryutils.SanitizeLabelName("__meta_azure_machine_tag_"+k), v)
 			}
 			ms = append(ms, m)
 		}
diff --git a/lib/promscrape/discovery/azure/azure_test.go b/lib/promscrape/discovery/azure/azure_test.go
index 2660e2cf26..7faa79bba2 100644
--- a/lib/promscrape/discovery/azure/azure_test.go
+++ b/lib/promscrape/discovery/azure/azure_test.go
@@ -1,24 +1,17 @@
 package azure
 
 import (
-	"reflect"
 	"testing"
 
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 func TestAppendMachineLabels(t *testing.T) {
-	f := func(name string, vms []virtualMachine, expectedLabels [][]prompbmarshal.Label) {
+	f := func(name string, vms []virtualMachine, expectedLabels []*promutils.Labels) {
 		t.Run(name, func(t *testing.T) {
 			labelss := appendMachineLabels(vms, 80, &SDConfig{SubscriptionID: "some-id"})
-			var sortedLabelss [][]prompbmarshal.Label
-			for _, labels := range labelss {
-				sortedLabelss = append(sortedLabelss, discoveryutils.GetSortedLabels(labels))
-			}
-			if !reflect.DeepEqual(sortedLabelss, expectedLabels) {
-				t.Fatalf("unexpected labels:\ngot\n%v\nwant\n%v", sortedLabelss, expectedLabels)
-			}
+			discoveryutils.TestEqualLabelss(t, labelss, expectedLabels)
 		})
 	}
 	f("single vm", []virtualMachine{
@@ -33,8 +26,8 @@ func TestAppendMachineLabels(t *testing.T) {
 				{privateIP: "10.10.10.1"},
 			},
 		},
-	}, [][]prompbmarshal.Label{
-		discoveryutils.GetSortedLabels(map[string]string{
+	}, []*promutils.Labels{
+		promutils.NewLabelsFromMap(map[string]string{
 			"__address__":                        "10.10.10.1:80",
 			"__meta_azure_machine_id":            "id-2",
 			"__meta_azure_subscription_id":       "some-id",
diff --git a/lib/promscrape/discovery/consul/consul.go b/lib/promscrape/discovery/consul/consul.go
index aa4779d5f3..fb755c82df 100644
--- a/lib/promscrape/discovery/consul/consul.go
+++ b/lib/promscrape/discovery/consul/consul.go
@@ -4,6 +4,7 @@ import (
 	"fmt"
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promauth"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/proxy"
 )
 
@@ -38,7 +39,7 @@ type SDConfig struct {
 }
 
 // GetLabels returns Consul labels according to sdc.
-func (sdc *SDConfig) GetLabels(baseDir string) ([]map[string]string, error) {
+func (sdc *SDConfig) GetLabels(baseDir string) ([]*promutils.Labels, error) {
 	cfg, err := getAPIConfig(sdc, baseDir)
 	if err != nil {
 		return nil, fmt.Errorf("cannot get API config: %w", err)
diff --git a/lib/promscrape/discovery/consul/service_node.go b/lib/promscrape/discovery/consul/service_node.go
index 60a198b1a7..1f62201d48 100644
--- a/lib/promscrape/discovery/consul/service_node.go
+++ b/lib/promscrape/discovery/consul/service_node.go
@@ -7,12 +7,13 @@ import (
 	"strings"
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 // getServiceNodesLabels returns labels for Consul service nodes with given cfg.
-func getServiceNodesLabels(cfg *apiConfig) []map[string]string {
+func getServiceNodesLabels(cfg *apiConfig) []*promutils.Labels {
 	sns := cfg.consulWatcher.getServiceNodesSnapshot()
-	var ms []map[string]string
+	var ms []*promutils.Labels
 	for svc, sn := range sns {
 		for i := range sn {
 			ms = sn[i].appendTargetLabels(ms, svc, cfg.tagSeparator)
@@ -71,38 +72,37 @@ func parseServiceNodes(data []byte) ([]ServiceNode, error) {
 	return sns, nil
 }
 
-func (sn *ServiceNode) appendTargetLabels(ms []map[string]string, serviceName, tagSeparator string) []map[string]string {
+func (sn *ServiceNode) appendTargetLabels(ms []*promutils.Labels, serviceName, tagSeparator string) []*promutils.Labels {
 	var addr string
 	if sn.Service.Address != "" {
 		addr = discoveryutils.JoinHostPort(sn.Service.Address, sn.Service.Port)
 	} else {
 		addr = discoveryutils.JoinHostPort(sn.Node.Address, sn.Service.Port)
 	}
-	m := map[string]string{
-		"__address__":                   addr,
-		"__meta_consul_address":         sn.Node.Address,
-		"__meta_consul_dc":              sn.Node.Datacenter,
-		"__meta_consul_health":          aggregatedStatus(sn.Checks),
-		"__meta_consul_namespace":       sn.Service.Namespace,
-		"__meta_consul_partition":       sn.Service.Partition,
-		"__meta_consul_node":            sn.Node.Node,
-		"__meta_consul_service":         serviceName,
-		"__meta_consul_service_address": sn.Service.Address,
-		"__meta_consul_service_id":      sn.Service.ID,
-		"__meta_consul_service_port":    strconv.Itoa(sn.Service.Port),
-	}
+	m := promutils.NewLabels(16)
+	m.Add("__address__", addr)
+	m.Add("__meta_consul_address", sn.Node.Address)
+	m.Add("__meta_consul_dc", sn.Node.Datacenter)
+	m.Add("__meta_consul_health", aggregatedStatus(sn.Checks))
+	m.Add("__meta_consul_namespace", sn.Service.Namespace)
+	m.Add("__meta_consul_partition", sn.Service.Partition)
+	m.Add("__meta_consul_node", sn.Node.Node)
+	m.Add("__meta_consul_service", serviceName)
+	m.Add("__meta_consul_service_address", sn.Service.Address)
+	m.Add("__meta_consul_service_id", sn.Service.ID)
+	m.Add("__meta_consul_service_port", strconv.Itoa(sn.Service.Port))
 	// We surround the separated list with the separator as well. This way regular expressions
 	// in relabeling rules don't have to consider tag positions.
-	m["__meta_consul_tags"] = tagSeparator + strings.Join(sn.Service.Tags, tagSeparator) + tagSeparator
+	m.Add("__meta_consul_tags", tagSeparator+strings.Join(sn.Service.Tags, tagSeparator)+tagSeparator)
 
 	for k, v := range sn.Node.Meta {
-		m[discoveryutils.SanitizeLabelName("__meta_consul_metadata_"+k)] = v
+		m.Add(discoveryutils.SanitizeLabelName("__meta_consul_metadata_"+k), v)
 	}
 	for k, v := range sn.Service.Meta {
-		m[discoveryutils.SanitizeLabelName("__meta_consul_service_metadata_"+k)] = v
+		m.Add(discoveryutils.SanitizeLabelName("__meta_consul_service_metadata_"+k), v)
 	}
 	for k, v := range sn.Node.TaggedAddresses {
-		m[discoveryutils.SanitizeLabelName("__meta_consul_tagged_address_"+k)] = v
+		m.Add(discoveryutils.SanitizeLabelName("__meta_consul_tagged_address_"+k), v)
 	}
 	ms = append(ms, m)
 	return ms
diff --git a/lib/promscrape/discovery/consul/service_node_test.go b/lib/promscrape/discovery/consul/service_node_test.go
index 848181c26c..81dec65d14 100644
--- a/lib/promscrape/discovery/consul/service_node_test.go
+++ b/lib/promscrape/discovery/consul/service_node_test.go
@@ -1,11 +1,10 @@
 package consul
 
 import (
-	"reflect"
 	"testing"
 
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 func TestParseServiceNodesFailure(t *testing.T) {
@@ -108,12 +107,8 @@ func TestParseServiceNodesSuccess(t *testing.T) {
 	// Check sn.appendTargetLabels()
 	tagSeparator := ","
 	labelss := sn.appendTargetLabels(nil, "redis", tagSeparator)
-	var sortedLabelss [][]prompbmarshal.Label
-	for _, labels := range labelss {
-		sortedLabelss = append(sortedLabelss, discoveryutils.GetSortedLabels(labels))
-	}
-	expectedLabelss := [][]prompbmarshal.Label{
-		discoveryutils.GetSortedLabels(map[string]string{
+	expectedLabelss := []*promutils.Labels{
+		promutils.NewLabelsFromMap(map[string]string{
 			"__address__":                                  "10.1.10.12:8000",
 			"__meta_consul_address":                        "10.1.10.12",
 			"__meta_consul_dc":                             "dc1",
@@ -132,7 +127,5 @@ func TestParseServiceNodesSuccess(t *testing.T) {
 			"__meta_consul_tags":                           ",primary,",
 		}),
 	}
-	if !reflect.DeepEqual(sortedLabelss, expectedLabelss) {
-		t.Fatalf("unexpected labels:\ngot\n%v\nwant\n%v", sortedLabelss, expectedLabelss)
-	}
+	discoveryutils.TestEqualLabelss(t, labelss, expectedLabelss)
 }
diff --git a/lib/promscrape/discovery/digitalocean/digitalocean.go b/lib/promscrape/discovery/digitalocean/digitalocean.go
index 65a7cf7747..cf25f2da3c 100644
--- a/lib/promscrape/discovery/digitalocean/digitalocean.go
+++ b/lib/promscrape/discovery/digitalocean/digitalocean.go
@@ -10,6 +10,7 @@ import (
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promauth"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/proxy"
 )
 
@@ -30,7 +31,7 @@ type SDConfig struct {
 }
 
 // GetLabels returns Digital Ocean droplet labels according to sdc.
-func (sdc *SDConfig) GetLabels(baseDir string) ([]map[string]string, error) {
+func (sdc *SDConfig) GetLabels(baseDir string) ([]*promutils.Labels, error) {
 	cfg, err := getAPIConfig(sdc, baseDir)
 	if err != nil {
 		return nil, fmt.Errorf("cannot get API config: %w", err)
@@ -39,7 +40,6 @@ func (sdc *SDConfig) GetLabels(baseDir string) ([]map[string]string, error) {
 	if err != nil {
 		return nil, err
 	}
-
 	return addDropletLabels(droplets, cfg.port), nil
 }
 
@@ -115,8 +115,8 @@ func (r *listDropletResponse) nextURLPath() (string, error) {
 	return u.RequestURI(), nil
 }
 
-func addDropletLabels(droplets []droplet, defaultPort int) []map[string]string {
-	var ms []map[string]string
+func addDropletLabels(droplets []droplet, defaultPort int) []*promutils.Labels {
+	var ms []*promutils.Labels
 	for _, droplet := range droplets {
 		if len(droplet.Networks.V4) == 0 {
 			continue
@@ -127,27 +127,26 @@ func addDropletLabels(droplets []droplet, defaultPort int) []map[string]string {
 		publicIPv6 := droplet.getIPByNet("v6", "public")
 
 		addr := discoveryutils.JoinHostPort(publicIPv4, defaultPort)
-		m := map[string]string{
-			"__address__":                      addr,
-			"__meta_digitalocean_droplet_id":   fmt.Sprintf("%d", droplet.ID),
-			"__meta_digitalocean_droplet_name": droplet.Name,
-			"__meta_digitalocean_image":        droplet.Image.Slug,
-			"__meta_digitalocean_image_name":   droplet.Image.Name,
-			"__meta_digitalocean_private_ipv4": privateIPv4,
-			"__meta_digitalocean_public_ipv4":  publicIPv4,
-			"__meta_digitalocean_public_ipv6":  publicIPv6,
-			"__meta_digitalocean_region":       droplet.Region.Slug,
-			"__meta_digitalocean_size":         droplet.SizeSlug,
-			"__meta_digitalocean_status":       droplet.Status,
-			"__meta_digitalocean_vpc":          droplet.VpcUUID,
-		}
+		m := promutils.NewLabels(16)
+		m.Add("__address__", addr)
+		m.Add("__meta_digitalocean_droplet_id", fmt.Sprintf("%d", droplet.ID))
+		m.Add("__meta_digitalocean_droplet_name", droplet.Name)
+		m.Add("__meta_digitalocean_image", droplet.Image.Slug)
+		m.Add("__meta_digitalocean_image_name", droplet.Image.Name)
+		m.Add("__meta_digitalocean_private_ipv4", privateIPv4)
+		m.Add("__meta_digitalocean_public_ipv4", publicIPv4)
+		m.Add("__meta_digitalocean_public_ipv6", publicIPv6)
+		m.Add("__meta_digitalocean_region", droplet.Region.Slug)
+		m.Add("__meta_digitalocean_size", droplet.SizeSlug)
+		m.Add("__meta_digitalocean_status", droplet.Status)
+		m.Add("__meta_digitalocean_vpc", droplet.VpcUUID)
 		if len(droplet.Features) > 0 {
 			features := fmt.Sprintf(",%s,", strings.Join(droplet.Features, ","))
-			m["__meta_digitalocean_features"] = features
+			m.Add("__meta_digitalocean_features", features)
 		}
 		if len(droplet.Tags) > 0 {
 			tags := fmt.Sprintf(",%s,", strings.Join(droplet.Tags, ","))
-			m["__meta_digitalocean_tags"] = tags
+			m.Add("__meta_digitalocean_tags", tags)
 		}
 		ms = append(ms, m)
 	}
diff --git a/lib/promscrape/discovery/digitalocean/digitalocean_test.go b/lib/promscrape/discovery/digitalocean/digitalocean_test.go
index ecb177fbf8..05d0b5f0f4 100644
--- a/lib/promscrape/discovery/digitalocean/digitalocean_test.go
+++ b/lib/promscrape/discovery/digitalocean/digitalocean_test.go
@@ -1,11 +1,10 @@
 package digitalocean
 
 import (
-	"reflect"
 	"testing"
 
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 func Test_addDropletLabels(t *testing.T) {
@@ -16,7 +15,7 @@ func Test_addDropletLabels(t *testing.T) {
 	tests := []struct {
 		name string
 		args args
-		want [][]prompbmarshal.Label
+		want []*promutils.Labels
 	}{
 		{
 			name: "base labels add test",
@@ -62,8 +61,8 @@ func Test_addDropletLabels(t *testing.T) {
 				},
 				defaultPort: 9100,
 			},
-			want: [][]prompbmarshal.Label{
-				discoveryutils.GetSortedLabels(map[string]string{
+			want: []*promutils.Labels{
+				promutils.NewLabelsFromMap(map[string]string{
 					"__address__":                      "100.100.100.100:9100",
 					"__meta_digitalocean_droplet_id":   "15",
 					"__meta_digitalocean_droplet_name": "ubuntu-1",
@@ -85,14 +84,7 @@ func Test_addDropletLabels(t *testing.T) {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			got := addDropletLabels(tt.args.droplets, tt.args.defaultPort)
-			var sortedLabelss [][]prompbmarshal.Label
-			for _, labels := range got {
-				sortedLabelss = append(sortedLabelss, discoveryutils.GetSortedLabels(labels))
-			}
-			if !reflect.DeepEqual(sortedLabelss, tt.want) {
-				t.Errorf("addTasksLabels() \ngot  \n%v\n, \nwant \n%v\n", sortedLabelss, tt.want)
-			}
-
+			discoveryutils.TestEqualLabelss(t, got, tt.want)
 		})
 	}
 }
diff --git a/lib/promscrape/discovery/dns/dns.go b/lib/promscrape/discovery/dns/dns.go
index a0a47d072d..c087417463 100644
--- a/lib/promscrape/discovery/dns/dns.go
+++ b/lib/promscrape/discovery/dns/dns.go
@@ -11,6 +11,7 @@ import (
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 // SDCheckInterval defines interval for targets refresh.
@@ -30,7 +31,7 @@ type SDConfig struct {
 }
 
 // GetLabels returns DNS labels according to sdc.
-func (sdc *SDConfig) GetLabels(baseDir string) ([]map[string]string, error) {
+func (sdc *SDConfig) GetLabels(baseDir string) ([]*promutils.Labels, error) {
 	if len(sdc.Names) == 0 {
 		return nil, fmt.Errorf("`names` cannot be empty in `dns_sd_config`")
 	}
@@ -60,7 +61,7 @@ func (sdc *SDConfig) MustStop() {
 	// nothing to do
 }
 
-func getMXAddrLabels(ctx context.Context, sdc *SDConfig) []map[string]string {
+func getMXAddrLabels(ctx context.Context, sdc *SDConfig) []*promutils.Labels {
 	port := 25
 	if sdc.Port != nil {
 		port = *sdc.Port
@@ -81,7 +82,7 @@ func getMXAddrLabels(ctx context.Context, sdc *SDConfig) []map[string]string {
 			}
 		}(name)
 	}
-	var ms []map[string]string
+	var ms []*promutils.Labels
 	for range sdc.Names {
 		r := <-ch
 		if r.err != nil {
@@ -99,7 +100,7 @@ func getMXAddrLabels(ctx context.Context, sdc *SDConfig) []map[string]string {
 	return ms
 }
 
-func getSRVAddrLabels(ctx context.Context, sdc *SDConfig) []map[string]string {
+func getSRVAddrLabels(ctx context.Context, sdc *SDConfig) []*promutils.Labels {
 	type result struct {
 		name string
 		as   []*net.SRV
@@ -116,7 +117,7 @@ func getSRVAddrLabels(ctx context.Context, sdc *SDConfig) []map[string]string {
 			}
 		}(name)
 	}
-	var ms []map[string]string
+	var ms []*promutils.Labels
 	for range sdc.Names {
 		r := <-ch
 		if r.err != nil {
@@ -134,7 +135,7 @@ func getSRVAddrLabels(ctx context.Context, sdc *SDConfig) []map[string]string {
 	return ms
 }
 
-func getAAddrLabels(ctx context.Context, sdc *SDConfig, lookupType string) ([]map[string]string, error) {
+func getAAddrLabels(ctx context.Context, sdc *SDConfig, lookupType string) ([]*promutils.Labels, error) {
 	if sdc.Port == nil {
 		return nil, fmt.Errorf("missing `port` in `dns_sd_config` for `type: %s`", lookupType)
 	}
@@ -155,7 +156,7 @@ func getAAddrLabels(ctx context.Context, sdc *SDConfig, lookupType string) ([]ma
 			}
 		}(name)
 	}
-	var ms []map[string]string
+	var ms []*promutils.Labels
 	for range sdc.Names {
 		r := <-ch
 		if r.err != nil {
@@ -173,24 +174,22 @@ func getAAddrLabels(ctx context.Context, sdc *SDConfig, lookupType string) ([]ma
 	return ms, nil
 }
 
-func appendMXLabels(ms []map[string]string, name, target string, port int) []map[string]string {
+func appendMXLabels(ms []*promutils.Labels, name, target string, port int) []*promutils.Labels {
 	addr := discoveryutils.JoinHostPort(target, port)
-	m := map[string]string{
-		"__address__":                 addr,
-		"__meta_dns_name":             name,
-		"__meta_dns_mx_record_target": target,
-	}
+	m := promutils.NewLabels(3)
+	m.Add("__address__", addr)
+	m.Add("__meta_dns_name", name)
+	m.Add("__meta_dns_mx_record_target", target)
 	return append(ms, m)
 }
 
-func appendAddrLabels(ms []map[string]string, name, target string, port int) []map[string]string {
+func appendAddrLabels(ms []*promutils.Labels, name, target string, port int) []*promutils.Labels {
 	addr := discoveryutils.JoinHostPort(target, port)
-	m := map[string]string{
-		"__address__":                  addr,
-		"__meta_dns_name":              name,
-		"__meta_dns_srv_record_target": target,
-		"__meta_dns_srv_record_port":   strconv.Itoa(port),
-	}
+	m := promutils.NewLabels(4)
+	m.Add("__address__", addr)
+	m.Add("__meta_dns_name", name)
+	m.Add("__meta_dns_srv_record_target", target)
+	m.Add("__meta_dns_srv_record_port", strconv.Itoa(port))
 	return append(ms, m)
 }
 
diff --git a/lib/promscrape/discovery/docker/container.go b/lib/promscrape/discovery/docker/container.go
index 43444f045c..f0b0aec2ef 100644
--- a/lib/promscrape/discovery/docker/container.go
+++ b/lib/promscrape/discovery/docker/container.go
@@ -6,6 +6,7 @@ import (
 	"strconv"
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 // See https://github.com/moby/moby/blob/314759dc2f4745925d8dec6d15acc7761c6e5c92/docs/api/v1.41.yaml#L4024
@@ -30,7 +31,7 @@ type container struct {
 	}
 }
 
-func getContainersLabels(cfg *apiConfig) ([]map[string]string, error) {
+func getContainersLabels(cfg *apiConfig) ([]*promutils.Labels, error) {
 	networkLabels, err := getNetworksLabelsByNetworkID(cfg)
 	if err != nil {
 		return nil, err
@@ -58,8 +59,8 @@ func parseContainers(data []byte) ([]container, error) {
 	return containers, nil
 }
 
-func addContainersLabels(containers []container, networkLabels map[string]map[string]string, defaultPort int, hostNetworkingHost string) []map[string]string {
-	var ms []map[string]string
+func addContainersLabels(containers []container, networkLabels map[string]*promutils.Labels, defaultPort int, hostNetworkingHost string) []*promutils.Labels {
+	var ms []*promutils.Labels
 	for i := range containers {
 		c := &containers[i]
 		if len(c.Names) == 0 {
@@ -71,16 +72,16 @@ func addContainersLabels(containers []container, networkLabels map[string]map[st
 				if p.Type != "tcp" {
 					continue
 				}
-				m := map[string]string{
-					"__address__":                discoveryutils.JoinHostPort(n.IPAddress, p.PrivatePort),
-					"__meta_docker_network_ip":   n.IPAddress,
-					"__meta_docker_port_private": strconv.Itoa(p.PrivatePort),
-				}
+				m := promutils.NewLabels(16)
+				m.Add("__address__", discoveryutils.JoinHostPort(n.IPAddress, p.PrivatePort))
+				m.Add("__meta_docker_network_ip", n.IPAddress)
+				m.Add("__meta_docker_port_private", strconv.Itoa(p.PrivatePort))
 				if p.PublicPort > 0 {
-					m["__meta_docker_port_public"] = strconv.Itoa(p.PublicPort)
-					m["__meta_docker_port_public_ip"] = p.IP
+					m.Add("__meta_docker_port_public", strconv.Itoa(p.PublicPort))
+					m.Add("__meta_docker_port_public_ip", p.IP)
 				}
 				addCommonLabels(m, c, networkLabels[n.NetworkID])
+				m.RemoveDuplicates()
 				ms = append(ms, m)
 				added = true
 			}
@@ -90,11 +91,11 @@ func addContainersLabels(containers []container, networkLabels map[string]map[st
 				if c.HostConfig.NetworkMode != "host" {
 					addr = discoveryutils.JoinHostPort(n.IPAddress, defaultPort)
 				}
-				m := map[string]string{
-					"__address__":              addr,
-					"__meta_docker_network_ip": n.IPAddress,
-				}
+				m := promutils.NewLabels(16)
+				m.Add("__address__", addr)
+				m.Add("__meta_docker_network_ip", n.IPAddress)
 				addCommonLabels(m, c, networkLabels[n.NetworkID])
+				m.RemoveDuplicates()
 				ms = append(ms, m)
 			}
 		}
@@ -102,14 +103,12 @@ func addContainersLabels(containers []container, networkLabels map[string]map[st
 	return ms
 }
 
-func addCommonLabels(m map[string]string, c *container, networkLabels map[string]string) {
-	m["__meta_docker_container_id"] = c.ID
-	m["__meta_docker_container_name"] = c.Names[0]
-	m["__meta_docker_container_network_mode"] = c.HostConfig.NetworkMode
+func addCommonLabels(m *promutils.Labels, c *container, networkLabels *promutils.Labels) {
+	m.Add("__meta_docker_container_id", c.ID)
+	m.Add("__meta_docker_container_name", c.Names[0])
+	m.Add("__meta_docker_container_network_mode", c.HostConfig.NetworkMode)
 	for k, v := range c.Labels {
-		m[discoveryutils.SanitizeLabelName("__meta_docker_container_label_"+k)] = v
-	}
-	for k, v := range networkLabels {
-		m[k] = v
+		m.Add(discoveryutils.SanitizeLabelName("__meta_docker_container_label_"+k), v)
 	}
+	m.AddFrom(networkLabels)
 }
diff --git a/lib/promscrape/discovery/docker/container_test.go b/lib/promscrape/discovery/docker/container_test.go
index 95785a8415..7d4f45d95e 100644
--- a/lib/promscrape/discovery/docker/container_test.go
+++ b/lib/promscrape/discovery/docker/container_test.go
@@ -3,6 +3,9 @@ package docker
 import (
 	"reflect"
 	"testing"
+
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 func Test_parseContainers(t *testing.T) {
@@ -314,7 +317,7 @@ func Test_addContainerLabels(t *testing.T) {
 	tests := []struct {
 		name    string
 		c       container
-		want    []map[string]string
+		want    []*promutils.Labels
 		wantErr bool
 	}{
 		{
@@ -352,8 +355,8 @@ func Test_addContainerLabels(t *testing.T) {
 					},
 				},
 			},
-			want: []map[string]string{
-				{
+			want: []*promutils.Labels{
+				promutils.NewLabelsFromMap(map[string]string{
 					"__address__":                "172.17.0.2:8012",
 					"__meta_docker_container_id": "90bc3b31aa13da5c0b11af2e228d54b38428a84e25d4e249ae9e9c95e51a0700",
 					"__meta_docker_container_label_com_docker_compose_config_hash":      "c9f0bd5bb31921f94cff367d819a30a0cc08d4399080897a6c5cd74b983156ec",
@@ -370,7 +373,7 @@ func Test_addContainerLabels(t *testing.T) {
 					"__meta_docker_network_ip":                                          "172.17.0.2",
 					"__meta_docker_network_name":                                        "bridge",
 					"__meta_docker_network_scope":                                       "local",
-				},
+				}),
 			},
 		},
 		{
@@ -408,8 +411,8 @@ func Test_addContainerLabels(t *testing.T) {
 					},
 				},
 			},
-			want: []map[string]string{
-				{
+			want: []*promutils.Labels{
+				promutils.NewLabelsFromMap(map[string]string{
 					"__address__":                "foobar",
 					"__meta_docker_container_id": "90bc3b31aa13da5c0b11af2e228d54b38428a84e25d4e249ae9e9c95e51a0700",
 					"__meta_docker_container_label_com_docker_compose_config_hash":      "c9f0bd5bb31921f94cff367d819a30a0cc08d4399080897a6c5cd74b983156ec",
@@ -426,7 +429,7 @@ func Test_addContainerLabels(t *testing.T) {
 					"__meta_docker_network_ip":                                          "172.17.0.2",
 					"__meta_docker_network_name":                                        "bridge",
 					"__meta_docker_network_scope":                                       "local",
-				},
+				}),
 			},
 		},
 		{
@@ -475,8 +478,8 @@ func Test_addContainerLabels(t *testing.T) {
 					},
 				},
 			},
-			want: []map[string]string{
-				{
+			want: []*promutils.Labels{
+				promutils.NewLabelsFromMap(map[string]string{
 					"__address__":                "172.17.0.2:8080",
 					"__meta_docker_container_id": "90bc3b31aa13da5c0b11af2e228d54b38428a84e25d4e249ae9e9c95e51a0700",
 					"__meta_docker_container_label_com_docker_compose_config_hash":      "c9f0bd5bb31921f94cff367d819a30a0cc08d4399080897a6c5cd74b983156ec",
@@ -496,21 +499,19 @@ func Test_addContainerLabels(t *testing.T) {
 					"__meta_docker_port_private":                                        "8080",
 					"__meta_docker_port_public":                                         "18081",
 					"__meta_docker_port_public_ip":                                      "0.0.0.0",
-				},
+				}),
 			},
 		},
 	}
 
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			labelsMap := addContainersLabels([]container{tt.c}, networkLabels, 8012, "foobar")
+			labelss := addContainersLabels([]container{tt.c}, networkLabels, 8012, "foobar")
 			if (err != nil) != tt.wantErr {
 				t.Errorf("addContainersLabels() error = %v, wantErr %v", err, tt.wantErr)
 				return
 			}
-			if !reflect.DeepEqual(labelsMap, tt.want) {
-				t.Errorf("addContainersLabels() \ngot  %v, \nwant %v", labelsMap, tt.want)
-			}
+			discoveryutils.TestEqualLabelss(t, labelss, tt.want)
 		})
 	}
 }
diff --git a/lib/promscrape/discovery/docker/docker.go b/lib/promscrape/discovery/docker/docker.go
index d020bbb64a..6be9086541 100644
--- a/lib/promscrape/discovery/docker/docker.go
+++ b/lib/promscrape/discovery/docker/docker.go
@@ -6,6 +6,7 @@ import (
 	"time"
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promauth"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/proxy"
 )
 
@@ -36,7 +37,7 @@ type Filter struct {
 }
 
 // GetLabels returns docker labels according to sdc.
-func (sdc *SDConfig) GetLabels(baseDir string) ([]map[string]string, error) {
+func (sdc *SDConfig) GetLabels(baseDir string) ([]*promutils.Labels, error) {
 	cfg, err := getAPIConfig(sdc, baseDir)
 	if err != nil {
 		return nil, fmt.Errorf("cannot get API config: %w", err)
diff --git a/lib/promscrape/discovery/docker/network.go b/lib/promscrape/discovery/docker/network.go
index 075fae9d71..d89b468d6a 100644
--- a/lib/promscrape/discovery/docker/network.go
+++ b/lib/promscrape/discovery/docker/network.go
@@ -6,6 +6,7 @@ import (
 	"strconv"
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 // See https://docs.docker.com/engine/api/v1.40/#tag/Network
@@ -18,7 +19,7 @@ type network struct {
 	Labels   map[string]string
 }
 
-func getNetworksLabelsByNetworkID(cfg *apiConfig) (map[string]map[string]string, error) {
+func getNetworksLabelsByNetworkID(cfg *apiConfig) (map[string]*promutils.Labels, error) {
 	networks, err := getNetworks(cfg)
 	if err != nil {
 		return nil, err
@@ -42,18 +43,17 @@ func parseNetworks(data []byte) ([]network, error) {
 	return networks, nil
 }
 
-func getNetworkLabelsByNetworkID(networks []network) map[string]map[string]string {
-	ms := make(map[string]map[string]string)
+func getNetworkLabelsByNetworkID(networks []network) map[string]*promutils.Labels {
+	ms := make(map[string]*promutils.Labels)
 	for _, network := range networks {
-		m := map[string]string{
-			"__meta_docker_network_id":       network.ID,
-			"__meta_docker_network_name":     network.Name,
-			"__meta_docker_network_internal": strconv.FormatBool(network.Internal),
-			"__meta_docker_network_ingress":  strconv.FormatBool(network.Ingress),
-			"__meta_docker_network_scope":    network.Scope,
-		}
+		m := promutils.NewLabels(8)
+		m.Add("__meta_docker_network_id", network.ID)
+		m.Add("__meta_docker_network_name", network.Name)
+		m.Add("__meta_docker_network_internal", strconv.FormatBool(network.Internal))
+		m.Add("__meta_docker_network_ingress", strconv.FormatBool(network.Ingress))
+		m.Add("__meta_docker_network_scope", network.Scope)
 		for k, v := range network.Labels {
-			m[discoveryutils.SanitizeLabelName("__meta_docker_network_label_"+k)] = v
+			m.Add(discoveryutils.SanitizeLabelName("__meta_docker_network_label_"+k), v)
 		}
 		ms[network.ID] = m
 	}
diff --git a/lib/promscrape/discovery/docker/network_test.go b/lib/promscrape/discovery/docker/network_test.go
index b2be33d616..6d2996a176 100644
--- a/lib/promscrape/discovery/docker/network_test.go
+++ b/lib/promscrape/discovery/docker/network_test.go
@@ -5,8 +5,8 @@ import (
 	"sort"
 	"testing"
 
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 func Test_addNetworkLabels(t *testing.T) {
@@ -16,7 +16,7 @@ func Test_addNetworkLabels(t *testing.T) {
 	tests := []struct {
 		name string
 		args args
-		want [][]prompbmarshal.Label
+		want []*promutils.Labels
 	}{
 		{
 			name: "ingress network",
@@ -33,8 +33,8 @@ func Test_addNetworkLabels(t *testing.T) {
 					},
 				},
 			},
-			want: [][]prompbmarshal.Label{
-				discoveryutils.GetSortedLabels(map[string]string{
+			want: []*promutils.Labels{
+				promutils.NewLabelsFromMap(map[string]string{
 					"__meta_docker_network_id":         "qs0hog6ldlei9ct11pr3c77v1",
 					"__meta_docker_network_ingress":    "true",
 					"__meta_docker_network_internal":   "false",
@@ -52,14 +52,11 @@ func Test_addNetworkLabels(t *testing.T) {
 				networkIDs = append(networkIDs, networkID)
 			}
 			sort.Strings(networkIDs)
-			var sortedLabelss [][]prompbmarshal.Label
+			var labelss []*promutils.Labels
 			for _, networkID := range networkIDs {
-				labels := got[networkID]
-				sortedLabelss = append(sortedLabelss, discoveryutils.GetSortedLabels(labels))
-			}
-			if !reflect.DeepEqual(sortedLabelss, tt.want) {
-				t.Errorf("addNetworkLabels() \ngot %v, \nwant %v", sortedLabelss, tt.want)
+				labelss = append(labelss, got[networkID])
 			}
+			discoveryutils.TestEqualLabelss(t, labelss, tt.want)
 		})
 	}
 }
diff --git a/lib/promscrape/discovery/dockerswarm/dockerswarm.go b/lib/promscrape/discovery/dockerswarm/dockerswarm.go
index 9f4662bf45..bfe7a06971 100644
--- a/lib/promscrape/discovery/dockerswarm/dockerswarm.go
+++ b/lib/promscrape/discovery/dockerswarm/dockerswarm.go
@@ -6,6 +6,7 @@ import (
 	"time"
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promauth"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/proxy"
 )
 
@@ -36,7 +37,7 @@ type Filter struct {
 }
 
 // GetLabels returns dockerswarm labels according to sdc.
-func (sdc *SDConfig) GetLabels(baseDir string) ([]map[string]string, error) {
+func (sdc *SDConfig) GetLabels(baseDir string) ([]*promutils.Labels, error) {
 	cfg, err := getAPIConfig(sdc, baseDir)
 	if err != nil {
 		return nil, fmt.Errorf("cannot get API config: %w", err)
diff --git a/lib/promscrape/discovery/dockerswarm/network.go b/lib/promscrape/discovery/dockerswarm/network.go
index 8fe12f0583..fabfbf1497 100644
--- a/lib/promscrape/discovery/dockerswarm/network.go
+++ b/lib/promscrape/discovery/dockerswarm/network.go
@@ -6,6 +6,7 @@ import (
 	"strconv"
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 // See https://docs.docker.com/engine/api/v1.40/#tag/Network
@@ -18,7 +19,7 @@ type network struct {
 	Labels   map[string]string
 }
 
-func getNetworksLabelsByNetworkID(cfg *apiConfig) (map[string]map[string]string, error) {
+func getNetworksLabelsByNetworkID(cfg *apiConfig) (map[string]*promutils.Labels, error) {
 	networks, err := getNetworks(cfg)
 	if err != nil {
 		return nil, err
@@ -42,18 +43,17 @@ func parseNetworks(data []byte) ([]network, error) {
 	return networks, nil
 }
 
-func getNetworkLabelsByNetworkID(networks []network) map[string]map[string]string {
-	ms := make(map[string]map[string]string)
+func getNetworkLabelsByNetworkID(networks []network) map[string]*promutils.Labels {
+	ms := make(map[string]*promutils.Labels)
 	for _, network := range networks {
-		m := map[string]string{
-			"__meta_dockerswarm_network_id":       network.ID,
-			"__meta_dockerswarm_network_name":     network.Name,
-			"__meta_dockerswarm_network_internal": strconv.FormatBool(network.Internal),
-			"__meta_dockerswarm_network_ingress":  strconv.FormatBool(network.Ingress),
-			"__meta_dockerswarm_network_scope":    network.Scope,
-		}
+		m := promutils.NewLabels(8)
+		m.Add("__meta_dockerswarm_network_id", network.ID)
+		m.Add("__meta_dockerswarm_network_name", network.Name)
+		m.Add("__meta_dockerswarm_network_internal", strconv.FormatBool(network.Internal))
+		m.Add("__meta_dockerswarm_network_ingress", strconv.FormatBool(network.Ingress))
+		m.Add("__meta_dockerswarm_network_scope", network.Scope)
 		for k, v := range network.Labels {
-			m[discoveryutils.SanitizeLabelName("__meta_dockerswarm_network_label_"+k)] = v
+			m.Add(discoveryutils.SanitizeLabelName("__meta_dockerswarm_network_label_"+k), v)
 		}
 		ms[network.ID] = m
 	}
diff --git a/lib/promscrape/discovery/dockerswarm/network_test.go b/lib/promscrape/discovery/dockerswarm/network_test.go
index 3441bb4b71..d274cca61a 100644
--- a/lib/promscrape/discovery/dockerswarm/network_test.go
+++ b/lib/promscrape/discovery/dockerswarm/network_test.go
@@ -5,8 +5,8 @@ import (
 	"sort"
 	"testing"
 
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 func Test_addNetworkLabels(t *testing.T) {
@@ -16,7 +16,7 @@ func Test_addNetworkLabels(t *testing.T) {
 	tests := []struct {
 		name string
 		args args
-		want [][]prompbmarshal.Label
+		want []*promutils.Labels
 	}{
 		{
 			name: "ingress network",
@@ -33,8 +33,8 @@ func Test_addNetworkLabels(t *testing.T) {
 					},
 				},
 			},
-			want: [][]prompbmarshal.Label{
-				discoveryutils.GetSortedLabels(map[string]string{
+			want: []*promutils.Labels{
+				promutils.NewLabelsFromMap(map[string]string{
 					"__meta_dockerswarm_network_id":         "qs0hog6ldlei9ct11pr3c77v1",
 					"__meta_dockerswarm_network_ingress":    "true",
 					"__meta_dockerswarm_network_internal":   "false",
@@ -52,14 +52,11 @@ func Test_addNetworkLabels(t *testing.T) {
 				networkIDs = append(networkIDs, networkID)
 			}
 			sort.Strings(networkIDs)
-			var sortedLabelss [][]prompbmarshal.Label
+			var labelss []*promutils.Labels
 			for _, networkID := range networkIDs {
-				labels := got[networkID]
-				sortedLabelss = append(sortedLabelss, discoveryutils.GetSortedLabels(labels))
-			}
-			if !reflect.DeepEqual(sortedLabelss, tt.want) {
-				t.Errorf("addNetworkLabels() \ngot %v, \nwant %v", sortedLabelss, tt.want)
+				labelss = append(labelss, got[networkID])
 			}
+			discoveryutils.TestEqualLabelss(t, labelss, tt.want)
 		})
 	}
 }
diff --git a/lib/promscrape/discovery/dockerswarm/nodes.go b/lib/promscrape/discovery/dockerswarm/nodes.go
index 592141e0f4..1800e40973 100644
--- a/lib/promscrape/discovery/dockerswarm/nodes.go
+++ b/lib/promscrape/discovery/dockerswarm/nodes.go
@@ -5,6 +5,7 @@ import (
 	"fmt"
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 // See https://docs.docker.com/engine/api/v1.40/#tag/Node
@@ -37,7 +38,7 @@ type node struct {
 	}
 }
 
-func getNodesLabels(cfg *apiConfig) ([]map[string]string, error) {
+func getNodesLabels(cfg *apiConfig) ([]*promutils.Labels, error) {
 	nodes, err := getNodes(cfg)
 	if err != nil {
 		return nil, err
@@ -61,26 +62,25 @@ func parseNodes(data []byte) ([]node, error) {
 	return nodes, nil
 }
 
-func addNodeLabels(nodes []node, port int) []map[string]string {
-	var ms []map[string]string
+func addNodeLabels(nodes []node, port int) []*promutils.Labels {
+	var ms []*promutils.Labels
 	for _, node := range nodes {
-		m := map[string]string{
-			"__address__":                                   discoveryutils.JoinHostPort(node.Status.Addr, port),
-			"__meta_dockerswarm_node_address":               node.Status.Addr,
-			"__meta_dockerswarm_node_availability":          node.Spec.Availability,
-			"__meta_dockerswarm_node_engine_version":        node.Description.Engine.EngineVersion,
-			"__meta_dockerswarm_node_hostname":              node.Description.Hostname,
-			"__meta_dockerswarm_node_id":                    node.ID,
-			"__meta_dockerswarm_node_manager_address":       node.ManagerStatus.Addr,
-			"__meta_dockerswarm_node_manager_leader":        fmt.Sprintf("%t", node.ManagerStatus.Leader),
-			"__meta_dockerswarm_node_manager_reachability":  node.ManagerStatus.Reachability,
-			"__meta_dockerswarm_node_platform_architecture": node.Description.Platform.Architecture,
-			"__meta_dockerswarm_node_platform_os":           node.Description.Platform.OS,
-			"__meta_dockerswarm_node_role":                  node.Spec.Role,
-			"__meta_dockerswarm_node_status":                node.Status.State,
-		}
+		m := promutils.NewLabels(16)
+		m.Add("__address__", discoveryutils.JoinHostPort(node.Status.Addr, port))
+		m.Add("__meta_dockerswarm_node_address", node.Status.Addr)
+		m.Add("__meta_dockerswarm_node_availability", node.Spec.Availability)
+		m.Add("__meta_dockerswarm_node_engine_version", node.Description.Engine.EngineVersion)
+		m.Add("__meta_dockerswarm_node_hostname", node.Description.Hostname)
+		m.Add("__meta_dockerswarm_node_id", node.ID)
+		m.Add("__meta_dockerswarm_node_manager_address", node.ManagerStatus.Addr)
+		m.Add("__meta_dockerswarm_node_manager_leader", fmt.Sprintf("%t", node.ManagerStatus.Leader))
+		m.Add("__meta_dockerswarm_node_manager_reachability", node.ManagerStatus.Reachability)
+		m.Add("__meta_dockerswarm_node_platform_architecture", node.Description.Platform.Architecture)
+		m.Add("__meta_dockerswarm_node_platform_os", node.Description.Platform.OS)
+		m.Add("__meta_dockerswarm_node_role", node.Spec.Role)
+		m.Add("__meta_dockerswarm_node_status", node.Status.State)
 		for k, v := range node.Spec.Labels {
-			m[discoveryutils.SanitizeLabelName("__meta_dockerswarm_node_label_"+k)] = v
+			m.Add(discoveryutils.SanitizeLabelName("__meta_dockerswarm_node_label_"+k), v)
 		}
 		ms = append(ms, m)
 	}
diff --git a/lib/promscrape/discovery/dockerswarm/nodes_test.go b/lib/promscrape/discovery/dockerswarm/nodes_test.go
index c7348f9b54..a3ceda39d4 100644
--- a/lib/promscrape/discovery/dockerswarm/nodes_test.go
+++ b/lib/promscrape/discovery/dockerswarm/nodes_test.go
@@ -4,8 +4,8 @@ import (
 	"reflect"
 	"testing"
 
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 func Test_parseNodes(t *testing.T) {
@@ -112,7 +112,7 @@ func Test_addNodeLabels(t *testing.T) {
 	tests := []struct {
 		name string
 		args args
-		want [][]prompbmarshal.Label
+		want []*promutils.Labels
 	}{
 		{
 			name: "add labels to one node",
@@ -154,8 +154,8 @@ func Test_addNodeLabels(t *testing.T) {
 				},
 				port: 9100,
 			},
-			want: [][]prompbmarshal.Label{
-				discoveryutils.GetSortedLabels(map[string]string{
+			want: []*promutils.Labels{
+				promutils.NewLabelsFromMap(map[string]string{
 					"__address__":                                   "172.31.40.97:9100",
 					"__meta_dockerswarm_node_address":               "172.31.40.97",
 					"__meta_dockerswarm_node_availability":          "active",
@@ -175,14 +175,7 @@ func Test_addNodeLabels(t *testing.T) {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			got := addNodeLabels(tt.args.nodes, tt.args.port)
-
-			var sortedLabelss [][]prompbmarshal.Label
-			for _, labels := range got {
-				sortedLabelss = append(sortedLabelss, discoveryutils.GetSortedLabels(labels))
-			}
-			if !reflect.DeepEqual(sortedLabelss, tt.want) {
-				t.Errorf("addNodeLabels() \ngot  %v, \nwant %v", sortedLabelss, tt.want)
-			}
+			discoveryutils.TestEqualLabelss(t, got, tt.want)
 		})
 	}
 }
diff --git a/lib/promscrape/discovery/dockerswarm/services.go b/lib/promscrape/discovery/dockerswarm/services.go
index ac52eb3a89..431665228f 100644
--- a/lib/promscrape/discovery/dockerswarm/services.go
+++ b/lib/promscrape/discovery/dockerswarm/services.go
@@ -6,8 +6,8 @@ import (
 	"net"
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
-
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 // https://docs.docker.com/engine/api/v1.40/#tag/Service
@@ -46,7 +46,7 @@ type portConfig struct {
 	PublishedPort int
 }
 
-func getServicesLabels(cfg *apiConfig) ([]map[string]string, error) {
+func getServicesLabels(cfg *apiConfig) ([]*promutils.Labels, error) {
 	services, err := getServices(cfg)
 	if err != nil {
 		return nil, err
@@ -84,19 +84,18 @@ func getServiceMode(svc service) string {
 	return ""
 }
 
-func addServicesLabels(services []service, networksLabels map[string]map[string]string, port int) []map[string]string {
-	var ms []map[string]string
+func addServicesLabels(services []service, networksLabels map[string]*promutils.Labels, port int) []*promutils.Labels {
+	var ms []*promutils.Labels
 	for _, service := range services {
-		commonLabels := map[string]string{
-			"__meta_dockerswarm_service_id":                      service.ID,
-			"__meta_dockerswarm_service_name":                    service.Spec.Name,
-			"__meta_dockerswarm_service_mode":                    getServiceMode(service),
-			"__meta_dockerswarm_service_task_container_hostname": service.Spec.TaskTemplate.ContainerSpec.Hostname,
-			"__meta_dockerswarm_service_task_container_image":    service.Spec.TaskTemplate.ContainerSpec.Image,
-			"__meta_dockerswarm_service_updating_status":         service.UpdateStatus.State,
-		}
+		commonLabels := promutils.NewLabels(10)
+		commonLabels.Add("__meta_dockerswarm_service_id", service.ID)
+		commonLabels.Add("__meta_dockerswarm_service_name", service.Spec.Name)
+		commonLabels.Add("__meta_dockerswarm_service_mode", getServiceMode(service))
+		commonLabels.Add("__meta_dockerswarm_service_task_container_hostname", service.Spec.TaskTemplate.ContainerSpec.Hostname)
+		commonLabels.Add("__meta_dockerswarm_service_task_container_image", service.Spec.TaskTemplate.ContainerSpec.Image)
+		commonLabels.Add("__meta_dockerswarm_service_updating_status", service.UpdateStatus.State)
 		for k, v := range service.Spec.Labels {
-			commonLabels[discoveryutils.SanitizeLabelName("__meta_dockerswarm_service_label_"+k)] = v
+			commonLabels.Add(discoveryutils.SanitizeLabelName("__meta_dockerswarm_service_label_"+k), v)
 		}
 		for _, vip := range service.Endpoint.VirtualIPs {
 			// skip services without virtual address.
@@ -114,30 +113,22 @@ func addServicesLabels(services []service, networksLabels map[string]map[string]
 				if ep.Protocol != "tcp" {
 					continue
 				}
-				m := map[string]string{
-					"__address__": discoveryutils.JoinHostPort(ip.String(), ep.PublishedPort),
-					"__meta_dockerswarm_service_endpoint_port_name":         ep.Name,
-					"__meta_dockerswarm_service_endpoint_port_publish_mode": ep.PublishMode,
-				}
-				for k, v := range commonLabels {
-					m[k] = v
-				}
-				for k, v := range networksLabels[vip.NetworkID] {
-					m[k] = v
-				}
+				m := promutils.NewLabels(24)
+				m.Add("__address__", discoveryutils.JoinHostPort(ip.String(), ep.PublishedPort))
+				m.Add("__meta_dockerswarm_service_endpoint_port_name", ep.Name)
+				m.Add("__meta_dockerswarm_service_endpoint_port_publish_mode", ep.PublishMode)
+				m.AddFrom(commonLabels)
+				m.AddFrom(networksLabels[vip.NetworkID])
+				m.RemoveDuplicates()
 				added = true
 				ms = append(ms, m)
 			}
 			if !added {
-				m := map[string]string{
-					"__address__": discoveryutils.JoinHostPort(ip.String(), port),
-				}
-				for k, v := range commonLabels {
-					m[k] = v
-				}
-				for k, v := range networksLabels[vip.NetworkID] {
-					m[k] = v
-				}
+				m := promutils.NewLabels(24)
+				m.Add("__address__", discoveryutils.JoinHostPort(ip.String(), port))
+				m.AddFrom(commonLabels)
+				m.AddFrom(networksLabels[vip.NetworkID])
+				m.RemoveDuplicates()
 				ms = append(ms, m)
 			}
 		}
diff --git a/lib/promscrape/discovery/dockerswarm/services_test.go b/lib/promscrape/discovery/dockerswarm/services_test.go
index 0706f12d02..82709b77f4 100644
--- a/lib/promscrape/discovery/dockerswarm/services_test.go
+++ b/lib/promscrape/discovery/dockerswarm/services_test.go
@@ -4,8 +4,8 @@ import (
 	"reflect"
 	"testing"
 
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 func Test_parseServicesResponse(t *testing.T) {
@@ -172,27 +172,27 @@ func Test_parseServicesResponse(t *testing.T) {
 func Test_addServicesLabels(t *testing.T) {
 	type args struct {
 		services       []service
-		networksLabels map[string]map[string]string
+		networksLabels map[string]*promutils.Labels
 		port           int
 	}
 	tests := []struct {
 		name string
 		args args
-		want [][]prompbmarshal.Label
+		want []*promutils.Labels
 	}{
 		{
 			name: "add 2 services with network labels join",
 			args: args{
 				port: 9100,
-				networksLabels: map[string]map[string]string{
-					"qs0hog6ldlei9ct11pr3c77v1": {
+				networksLabels: map[string]*promutils.Labels{
+					"qs0hog6ldlei9ct11pr3c77v1": promutils.NewLabelsFromMap(map[string]string{
 						"__meta_dockerswarm_network_id":         "qs0hog6ldlei9ct11pr3c77v1",
 						"__meta_dockerswarm_network_ingress":    "true",
 						"__meta_dockerswarm_network_internal":   "false",
 						"__meta_dockerswarm_network_label_key1": "value1",
 						"__meta_dockerswarm_network_name":       "ingress",
 						"__meta_dockerswarm_network_scope":      "swarm",
-					},
+					}),
 				},
 				services: []service{
 					{
@@ -259,8 +259,8 @@ func Test_addServicesLabels(t *testing.T) {
 					},
 				},
 			},
-			want: [][]prompbmarshal.Label{
-				discoveryutils.GetSortedLabels(map[string]string{
+			want: []*promutils.Labels{
+				promutils.NewLabelsFromMap(map[string]string{
 					"__address__":                                           "10.0.0.3:0",
 					"__meta_dockerswarm_network_id":                         "qs0hog6ldlei9ct11pr3c77v1",
 					"__meta_dockerswarm_network_ingress":                    "true",
@@ -282,13 +282,7 @@ func Test_addServicesLabels(t *testing.T) {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			got := addServicesLabels(tt.args.services, tt.args.networksLabels, tt.args.port)
-			var sortedLabelss [][]prompbmarshal.Label
-			for _, labels := range got {
-				sortedLabelss = append(sortedLabelss, discoveryutils.GetSortedLabels(labels))
-			}
-			if !reflect.DeepEqual(sortedLabelss, tt.want) {
-				t.Errorf("addServicesLabels() \ngot  %v, \nwant %v", sortedLabelss, tt.want)
-			}
+			discoveryutils.TestEqualLabelss(t, got, tt.want)
 		})
 	}
 }
diff --git a/lib/promscrape/discovery/dockerswarm/tasks.go b/lib/promscrape/discovery/dockerswarm/tasks.go
index 9e17825ee6..21aafb2e6c 100644
--- a/lib/promscrape/discovery/dockerswarm/tasks.go
+++ b/lib/promscrape/discovery/dockerswarm/tasks.go
@@ -8,6 +8,7 @@ import (
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 // See https://docs.docker.com/engine/api/v1.40/#tag/Task
@@ -39,7 +40,7 @@ type task struct {
 	Slot int
 }
 
-func getTasksLabels(cfg *apiConfig) ([]map[string]string, error) {
+func getTasksLabels(cfg *apiConfig) ([]*promutils.Labels, error) {
 	tasks, err := getTasks(cfg)
 	if err != nil {
 		return nil, err
@@ -76,18 +77,17 @@ func parseTasks(data []byte) ([]task, error) {
 	return tasks, nil
 }
 
-func addTasksLabels(tasks []task, nodesLabels, servicesLabels []map[string]string, networksLabels map[string]map[string]string, services []service, port int) []map[string]string {
-	var ms []map[string]string
+func addTasksLabels(tasks []task, nodesLabels, servicesLabels []*promutils.Labels, networksLabels map[string]*promutils.Labels, services []service, port int) []*promutils.Labels {
+	var ms []*promutils.Labels
 	for _, task := range tasks {
-		commonLabels := map[string]string{
-			"__meta_dockerswarm_task_id":            task.ID,
-			"__meta_dockerswarm_task_container_id":  task.Status.ContainerStatus.ContainerID,
-			"__meta_dockerswarm_task_desired_state": task.DesiredState,
-			"__meta_dockerswarm_task_slot":          strconv.Itoa(task.Slot),
-			"__meta_dockerswarm_task_state":         task.Status.State,
-		}
+		commonLabels := promutils.NewLabels(8)
+		commonLabels.Add("__meta_dockerswarm_task_id", task.ID)
+		commonLabels.Add("__meta_dockerswarm_task_container_id", task.Status.ContainerStatus.ContainerID)
+		commonLabels.Add("__meta_dockerswarm_task_desired_state", task.DesiredState)
+		commonLabels.Add("__meta_dockerswarm_task_slot", strconv.Itoa(task.Slot))
+		commonLabels.Add("__meta_dockerswarm_task_state", task.Status.State)
 		for k, v := range task.Spec.ContainerSpec.Labels {
-			commonLabels[discoveryutils.SanitizeLabelName("__meta_dockerswarm_container_label_"+k)] = v
+			commonLabels.Add(discoveryutils.SanitizeLabelName("__meta_dockerswarm_container_label_"+k), v)
 		}
 		var svcPorts []portConfig
 		for i, v := range services {
@@ -103,12 +103,11 @@ func addTasksLabels(tasks []task, nodesLabels, servicesLabels []map[string]strin
 			if port.Protocol != "tcp" {
 				continue
 			}
-			m := make(map[string]string, len(commonLabels)+2)
-			for k, v := range commonLabels {
-				m[k] = v
-			}
-			m["__address__"] = discoveryutils.JoinHostPort(commonLabels["__meta_dockerswarm_node_address"], port.PublishedPort)
-			m["__meta_dockerswarm_task_port_publish_mode"] = port.PublishMode
+			m := promutils.NewLabels(10)
+			m.AddFrom(commonLabels)
+			m.Add("__address__", discoveryutils.JoinHostPort(commonLabels.Get("__meta_dockerswarm_node_address"), port.PublishedPort))
+			m.Add("__meta_dockerswarm_task_port_publish_mode", port.PublishMode)
+			m.RemoveDuplicates()
 			ms = append(ms, m)
 		}
 		for _, na := range task.NetworksAttachments {
@@ -124,27 +123,21 @@ func addTasksLabels(tasks []task, nodesLabels, servicesLabels []map[string]strin
 					if ep.Protocol != "tcp" {
 						continue
 					}
-					m := make(map[string]string, len(commonLabels)+len(networkLabels)+2)
-					for k, v := range commonLabels {
-						m[k] = v
-					}
-					for k, v := range networkLabels {
-						m[k] = v
-					}
-					m["__address__"] = discoveryutils.JoinHostPort(ip.String(), ep.PublishedPort)
-					m["__meta_dockerswarm_task_port_publish_mode"] = ep.PublishMode
+					m := promutils.NewLabels(20)
+					m.AddFrom(commonLabels)
+					m.AddFrom(networkLabels)
+					m.Add("__address__", discoveryutils.JoinHostPort(ip.String(), ep.PublishedPort))
+					m.Add("__meta_dockerswarm_task_port_publish_mode", ep.PublishMode)
+					m.RemoveDuplicates()
 					ms = append(ms, m)
 					added = true
 				}
 				if !added {
-					m := make(map[string]string, len(commonLabels)+len(networkLabels)+1)
-					for k, v := range commonLabels {
-						m[k] = v
-					}
-					for k, v := range networkLabels {
-						m[k] = v
-					}
-					m["__address__"] = discoveryutils.JoinHostPort(ip.String(), port)
+					m := promutils.NewLabels(20)
+					m.AddFrom(commonLabels)
+					m.AddFrom(networkLabels)
+					m.Add("__address__", discoveryutils.JoinHostPort(ip.String(), port))
+					m.RemoveDuplicates()
 					ms = append(ms, m)
 				}
 			}
@@ -154,13 +147,13 @@ func addTasksLabels(tasks []task, nodesLabels, servicesLabels []map[string]strin
 }
 
 // addLabels adds lables from src to dst if they contain the given `key: value` pair.
-func addLabels(dst map[string]string, src []map[string]string, key, value string) {
+func addLabels(dst *promutils.Labels, src []*promutils.Labels, key, value string) {
 	for _, m := range src {
-		if m[key] != value {
+		if m.Get(key) != value {
 			continue
 		}
-		for k, v := range m {
-			dst[k] = v
+		for _, label := range m.GetLabels() {
+			dst.Add(label.Name, label.Value)
 		}
 		return
 	}
diff --git a/lib/promscrape/discovery/dockerswarm/tasks_test.go b/lib/promscrape/discovery/dockerswarm/tasks_test.go
index ed019c33ea..fadabcd5d7 100644
--- a/lib/promscrape/discovery/dockerswarm/tasks_test.go
+++ b/lib/promscrape/discovery/dockerswarm/tasks_test.go
@@ -4,8 +4,8 @@ import (
 	"reflect"
 	"testing"
 
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 func Test_parseTasks(t *testing.T) {
@@ -116,16 +116,16 @@ func Test_parseTasks(t *testing.T) {
 func Test_addTasksLabels(t *testing.T) {
 	type args struct {
 		tasks          []task
-		nodesLabels    []map[string]string
-		servicesLabels []map[string]string
-		networksLabels map[string]map[string]string
+		nodesLabels    []*promutils.Labels
+		servicesLabels []*promutils.Labels
+		networksLabels map[string]*promutils.Labels
 		services       []service
 		port           int
 	}
 	tests := []struct {
 		name string
 		args args
-		want [][]prompbmarshal.Label
+		want []*promutils.Labels
 	}{
 		{
 			name: "adds 1 task with nodes labels",
@@ -159,8 +159,8 @@ func Test_addTasksLabels(t *testing.T) {
 							}},
 					},
 				},
-				nodesLabels: []map[string]string{
-					{
+				nodesLabels: []*promutils.Labels{
+					promutils.NewLabelsFromMap(map[string]string{
 						"__address__":                                   "172.31.40.97:9100",
 						"__meta_dockerswarm_node_address":               "172.31.40.97",
 						"__meta_dockerswarm_node_availability":          "active",
@@ -171,11 +171,11 @@ func Test_addTasksLabels(t *testing.T) {
 						"__meta_dockerswarm_node_platform_os":           "linux",
 						"__meta_dockerswarm_node_role":                  "manager",
 						"__meta_dockerswarm_node_status":                "ready",
-					},
+					}),
 				},
 			},
-			want: [][]prompbmarshal.Label{
-				discoveryutils.GetSortedLabels(map[string]string{
+			want: []*promutils.Labels{
+				promutils.NewLabelsFromMap(map[string]string{
 					"__address__":                                   "172.31.40.97:6379",
 					"__meta_dockerswarm_node_address":               "172.31.40.97",
 					"__meta_dockerswarm_node_availability":          "active",
@@ -230,18 +230,18 @@ func Test_addTasksLabels(t *testing.T) {
 							PortStatus: struct{ Ports []portConfig }{}},
 					},
 				},
-				networksLabels: map[string]map[string]string{
-					"qs0hog6ldlei9ct11pr3c77v1": {
+				networksLabels: map[string]*promutils.Labels{
+					"qs0hog6ldlei9ct11pr3c77v1": promutils.NewLabelsFromMap(map[string]string{
 						"__meta_dockerswarm_network_id":         "qs0hog6ldlei9ct11pr3c77v1",
 						"__meta_dockerswarm_network_ingress":    "true",
 						"__meta_dockerswarm_network_internal":   "false",
 						"__meta_dockerswarm_network_label_key1": "value1",
 						"__meta_dockerswarm_network_name":       "ingress",
 						"__meta_dockerswarm_network_scope":      "swarm",
-					},
+					}),
 				},
-				nodesLabels: []map[string]string{
-					{
+				nodesLabels: []*promutils.Labels{
+					promutils.NewLabelsFromMap(map[string]string{
 						"__address__":                                   "172.31.40.97:9100",
 						"__meta_dockerswarm_node_address":               "172.31.40.97",
 						"__meta_dockerswarm_node_availability":          "active",
@@ -252,7 +252,7 @@ func Test_addTasksLabels(t *testing.T) {
 						"__meta_dockerswarm_node_platform_os":           "linux",
 						"__meta_dockerswarm_node_role":                  "manager",
 						"__meta_dockerswarm_node_status":                "ready",
-					},
+					}),
 				},
 				services: []service{
 					{
@@ -320,10 +320,10 @@ func Test_addTasksLabels(t *testing.T) {
 						},
 					},
 				},
-				servicesLabels: []map[string]string{},
+				servicesLabels: []*promutils.Labels{},
 			},
-			want: [][]prompbmarshal.Label{
-				discoveryutils.GetSortedLabels(map[string]string{
+			want: []*promutils.Labels{
+				promutils.NewLabelsFromMap(map[string]string{
 					"__address__":                                   "10.10.15.15:6379",
 					"__meta_dockerswarm_network_id":                 "qs0hog6ldlei9ct11pr3c77v1",
 					"__meta_dockerswarm_network_ingress":            "true",
@@ -353,13 +353,7 @@ func Test_addTasksLabels(t *testing.T) {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			got := addTasksLabels(tt.args.tasks, tt.args.nodesLabels, tt.args.servicesLabels, tt.args.networksLabels, tt.args.services, tt.args.port)
-			var sortedLabelss [][]prompbmarshal.Label
-			for _, labels := range got {
-				sortedLabelss = append(sortedLabelss, discoveryutils.GetSortedLabels(labels))
-			}
-			if !reflect.DeepEqual(sortedLabelss, tt.want) {
-				t.Errorf("addTasksLabels() \ngot  %v, \nwant %v", sortedLabelss, tt.want)
-			}
+			discoveryutils.TestEqualLabelss(t, got, tt.want)
 		})
 	}
 }
diff --git a/lib/promscrape/discovery/ec2/ec2.go b/lib/promscrape/discovery/ec2/ec2.go
index 871ec77ac5..afed1bde38 100644
--- a/lib/promscrape/discovery/ec2/ec2.go
+++ b/lib/promscrape/discovery/ec2/ec2.go
@@ -7,6 +7,7 @@ import (
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/awsapi"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promauth"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 // SDCheckInterval defines interval for targets refresh.
@@ -34,7 +35,7 @@ type SDConfig struct {
 }
 
 // GetLabels returns ec2 labels according to sdc.
-func (sdc *SDConfig) GetLabels(baseDir string) ([]map[string]string, error) {
+func (sdc *SDConfig) GetLabels(baseDir string) ([]*promutils.Labels, error) {
 	cfg, err := getAPIConfig(sdc)
 	if err != nil {
 		return nil, fmt.Errorf("cannot get API config: %w", err)
diff --git a/lib/promscrape/discovery/ec2/instance.go b/lib/promscrape/discovery/ec2/instance.go
index e00f1fb6ef..a9cf5147e1 100644
--- a/lib/promscrape/discovery/ec2/instance.go
+++ b/lib/promscrape/discovery/ec2/instance.go
@@ -7,17 +7,18 @@ import (
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/awsapi"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 // getInstancesLabels returns labels for ec2 instances obtained from the given cfg
-func getInstancesLabels(cfg *apiConfig) ([]map[string]string, error) {
+func getInstancesLabels(cfg *apiConfig) ([]*promutils.Labels, error) {
 	rs, err := getReservations(cfg)
 	if err != nil {
 		return nil, err
 	}
 	azMap := getAZMap(cfg)
 	region := cfg.awsConfig.GetRegion()
-	var ms []map[string]string
+	var ms []*promutils.Labels
 	for _, r := range rs {
 		for _, inst := range r.InstanceSet.Items {
 			ms = inst.appendTargetLabels(ms, r.OwnerID, region, cfg.port, azMap)
@@ -135,32 +136,31 @@ func parseInstancesResponse(data []byte) (*InstancesResponse, error) {
 	return &v, nil
 }
 
-func (inst *Instance) appendTargetLabels(ms []map[string]string, ownerID, region string, port int, azMap map[string]string) []map[string]string {
+func (inst *Instance) appendTargetLabels(ms []*promutils.Labels, ownerID, region string, port int, azMap map[string]string) []*promutils.Labels {
 	if len(inst.PrivateIPAddress) == 0 {
 		// Cannot scrape instance without private IP address
 		return ms
 	}
 	addr := discoveryutils.JoinHostPort(inst.PrivateIPAddress, port)
-	m := map[string]string{
-		"__address__":                     addr,
-		"__meta_ec2_architecture":         inst.Architecture,
-		"__meta_ec2_ami":                  inst.ImageID,
-		"__meta_ec2_availability_zone":    inst.Placement.AvailabilityZone,
-		"__meta_ec2_availability_zone_id": azMap[inst.Placement.AvailabilityZone],
-		"__meta_ec2_instance_id":          inst.ID,
-		"__meta_ec2_instance_lifecycle":   inst.Lifecycle,
-		"__meta_ec2_instance_state":       inst.State.Name,
-		"__meta_ec2_instance_type":        inst.Type,
-		"__meta_ec2_owner_id":             ownerID,
-		"__meta_ec2_platform":             inst.Platform,
-		"__meta_ec2_primary_subnet_id":    inst.SubnetID,
-		"__meta_ec2_private_dns_name":     inst.PrivateDNSName,
-		"__meta_ec2_private_ip":           inst.PrivateIPAddress,
-		"__meta_ec2_public_dns_name":      inst.PublicDNSName,
-		"__meta_ec2_public_ip":            inst.PublicIPAddress,
-		"__meta_ec2_region":               region,
-		"__meta_ec2_vpc_id":               inst.VPCID,
-	}
+	m := promutils.NewLabels(24)
+	m.Add("__address__", addr)
+	m.Add("__meta_ec2_architecture", inst.Architecture)
+	m.Add("__meta_ec2_ami", inst.ImageID)
+	m.Add("__meta_ec2_availability_zone", inst.Placement.AvailabilityZone)
+	m.Add("__meta_ec2_availability_zone_id", azMap[inst.Placement.AvailabilityZone])
+	m.Add("__meta_ec2_instance_id", inst.ID)
+	m.Add("__meta_ec2_instance_lifecycle", inst.Lifecycle)
+	m.Add("__meta_ec2_instance_state", inst.State.Name)
+	m.Add("__meta_ec2_instance_type", inst.Type)
+	m.Add("__meta_ec2_owner_id", ownerID)
+	m.Add("__meta_ec2_platform", inst.Platform)
+	m.Add("__meta_ec2_primary_subnet_id", inst.SubnetID)
+	m.Add("__meta_ec2_private_dns_name", inst.PrivateDNSName)
+	m.Add("__meta_ec2_private_ip", inst.PrivateIPAddress)
+	m.Add("__meta_ec2_public_dns_name", inst.PublicDNSName)
+	m.Add("__meta_ec2_public_ip", inst.PublicIPAddress)
+	m.Add("__meta_ec2_region", region)
+	m.Add("__meta_ec2_vpc_id", inst.VPCID)
 	if len(inst.VPCID) > 0 {
 		subnets := make([]string, 0, len(inst.NetworkInterfaceSet.Items))
 		seenSubnets := make(map[string]bool, len(inst.NetworkInterfaceSet.Items))
@@ -179,16 +179,16 @@ func (inst *Instance) appendTargetLabels(ms []map[string]string, ownerID, region
 		}
 		// We surround the separated list with the separator as well. This way regular expressions
 		// in relabeling rules don't have to consider tag positions.
-		m["__meta_ec2_subnet_id"] = "," + strings.Join(subnets, ",") + ","
+		m.Add("__meta_ec2_subnet_id", ","+strings.Join(subnets, ",")+",")
 		if len(ipv6Addrs) > 0 {
-			m["__meta_ec2_ipv6_addresses"] = "," + strings.Join(ipv6Addrs, ",") + ","
+			m.Add("__meta_ec2_ipv6_addresses", ","+strings.Join(ipv6Addrs, ",")+",")
 		}
 	}
 	for _, t := range inst.TagSet.Items {
 		if len(t.Key) == 0 || len(t.Value) == 0 {
 			continue
 		}
-		m[discoveryutils.SanitizeLabelName("__meta_ec2_tag_"+t.Key)] = t.Value
+		m.Add(discoveryutils.SanitizeLabelName("__meta_ec2_tag_"+t.Key), t.Value)
 	}
 	ms = append(ms, m)
 	return ms
diff --git a/lib/promscrape/discovery/ec2/instance_test.go b/lib/promscrape/discovery/ec2/instance_test.go
index b6667db89f..86137db234 100644
--- a/lib/promscrape/discovery/ec2/instance_test.go
+++ b/lib/promscrape/discovery/ec2/instance_test.go
@@ -4,8 +4,8 @@ import (
 	"reflect"
 	"testing"
 
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 func TestDescribeAvailabilityZonesResponse(t *testing.T) {
@@ -241,12 +241,8 @@ func TestParseInstancesResponse(t *testing.T) {
 	labelss := inst.appendTargetLabels(nil, ownerID, "region-a", port, map[string]string{
 		"eu-west-2c": "foobar-zone",
 	})
-	var sortedLabelss [][]prompbmarshal.Label
-	for _, labels := range labelss {
-		sortedLabelss = append(sortedLabelss, discoveryutils.GetSortedLabels(labels))
-	}
-	expectedLabels := [][]prompbmarshal.Label{
-		discoveryutils.GetSortedLabels(map[string]string{
+	expectedLabels := []*promutils.Labels{
+		promutils.NewLabelsFromMap(map[string]string{
 			"__address__":                     "172.31.11.152:423",
 			"__meta_ec2_architecture":         "x86_64",
 			"__meta_ec2_availability_zone":    "eu-west-2c",
@@ -269,7 +265,5 @@ func TestParseInstancesResponse(t *testing.T) {
 			"__meta_ec2_vpc_id":               "vpc-f1eaad99",
 		}),
 	}
-	if !reflect.DeepEqual(sortedLabelss, expectedLabels) {
-		t.Fatalf("unexpected labels:\ngot\n%v\nwant\n%v", sortedLabelss, expectedLabels)
-	}
+	discoveryutils.TestEqualLabelss(t, labelss, expectedLabels)
 }
diff --git a/lib/promscrape/discovery/eureka/eureka.go b/lib/promscrape/discovery/eureka/eureka.go
index f2390f6d45..4b73cf81c4 100644
--- a/lib/promscrape/discovery/eureka/eureka.go
+++ b/lib/promscrape/discovery/eureka/eureka.go
@@ -9,6 +9,7 @@ import (
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promauth"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/proxy"
 )
 
@@ -82,7 +83,7 @@ type DataCenterInfo struct {
 }
 
 // GetLabels returns Eureka labels according to sdc.
-func (sdc *SDConfig) GetLabels(baseDir string) ([]map[string]string, error) {
+func (sdc *SDConfig) GetLabels(baseDir string) ([]*promutils.Labels, error) {
 	cfg, err := getAPIConfig(sdc, baseDir)
 	if err != nil {
 		return nil, fmt.Errorf("cannot get API config: %w", err)
@@ -103,8 +104,8 @@ func (sdc *SDConfig) MustStop() {
 	configMap.Delete(sdc)
 }
 
-func addInstanceLabels(apps *applications) []map[string]string {
-	var ms []map[string]string
+func addInstanceLabels(apps *applications) []*promutils.Labels {
+	var ms []*promutils.Labels
 	for _, app := range apps.Applications {
 		for _, instance := range app.Instances {
 			instancePort := 80
@@ -112,38 +113,37 @@ func addInstanceLabels(apps *applications) []map[string]string {
 				instancePort = instance.Port.Port
 			}
 			targetAddress := discoveryutils.JoinHostPort(instance.HostName, instancePort)
-			m := map[string]string{
-				"__address__":                                   targetAddress,
-				"instance":                                      instance.InstanceID,
-				"__meta_eureka_app_name":                        app.Name,
-				"__meta_eureka_app_instance_hostname":           instance.HostName,
-				"__meta_eureka_app_instance_homepage_url":       instance.HomePageURL,
-				"__meta_eureka_app_instance_statuspage_url":     instance.StatusPageURL,
-				"__meta_eureka_app_instance_healthcheck_url":    instance.HealthCheckURL,
-				"__meta_eureka_app_instance_ip_addr":            instance.IPAddr,
-				"__meta_eureka_app_instance_vip_address":        instance.VipAddress,
-				"__meta_eureka_app_instance_secure_vip_address": instance.SecureVipAddress,
-				"__meta_eureka_app_instance_status":             instance.Status,
-				"__meta_eureka_app_instance_country_id":         strconv.Itoa(instance.CountryID),
-				"__meta_eureka_app_instance_id":                 instance.InstanceID,
-			}
+			m := promutils.NewLabels(24)
+			m.Add("__address__", targetAddress)
+			m.Add("instance", instance.InstanceID)
+			m.Add("__meta_eureka_app_name", app.Name)
+			m.Add("__meta_eureka_app_instance_hostname", instance.HostName)
+			m.Add("__meta_eureka_app_instance_homepage_url", instance.HomePageURL)
+			m.Add("__meta_eureka_app_instance_statuspage_url", instance.StatusPageURL)
+			m.Add("__meta_eureka_app_instance_healthcheck_url", instance.HealthCheckURL)
+			m.Add("__meta_eureka_app_instance_ip_addr", instance.IPAddr)
+			m.Add("__meta_eureka_app_instance_vip_address", instance.VipAddress)
+			m.Add("__meta_eureka_app_instance_secure_vip_address", instance.SecureVipAddress)
+			m.Add("__meta_eureka_app_instance_status", instance.Status)
+			m.Add("__meta_eureka_app_instance_country_id", strconv.Itoa(instance.CountryID))
+			m.Add("__meta_eureka_app_instance_id", instance.InstanceID)
 			if instance.Port.Port != 0 {
-				m["__meta_eureka_app_instance_port"] = strconv.Itoa(instance.Port.Port)
-				m["__meta_eureka_app_instance_port_enabled"] = strconv.FormatBool(instance.Port.Enabled)
+				m.Add("__meta_eureka_app_instance_port", strconv.Itoa(instance.Port.Port))
+				m.Add("__meta_eureka_app_instance_port_enabled", strconv.FormatBool(instance.Port.Enabled))
 			}
 			if instance.SecurePort.Port != 0 {
-				m["__meta_eureka_app_instance_secure_port"] = strconv.Itoa(instance.SecurePort.Port)
-				m["__meta_eureka_app_instance_secure_port_enabled"] = strconv.FormatBool(instance.SecurePort.Enabled)
+				m.Add("__meta_eureka_app_instance_secure_port", strconv.Itoa(instance.SecurePort.Port))
+				m.Add("__meta_eureka_app_instance_secure_port_enabled", strconv.FormatBool(instance.SecurePort.Enabled))
 
 			}
 			if len(instance.DataCenterInfo.Name) > 0 {
-				m["__meta_eureka_app_instance_datacenterinfo_name"] = instance.DataCenterInfo.Name
+				m.Add("__meta_eureka_app_instance_datacenterinfo_name", instance.DataCenterInfo.Name)
 				for _, tag := range instance.DataCenterInfo.Metadata.Items {
-					m[discoveryutils.SanitizeLabelName("__meta_eureka_app_instance_datacenterinfo_metadata_"+tag.XMLName.Local)] = tag.Content
+					m.Add(discoveryutils.SanitizeLabelName("__meta_eureka_app_instance_datacenterinfo_metadata_"+tag.XMLName.Local), tag.Content)
 				}
 			}
 			for _, tag := range instance.Metadata.Items {
-				m[discoveryutils.SanitizeLabelName("__meta_eureka_app_instance_metadata_"+tag.XMLName.Local)] = tag.Content
+				m.Add(discoveryutils.SanitizeLabelName("__meta_eureka_app_instance_metadata_"+tag.XMLName.Local), tag.Content)
 			}
 			ms = append(ms, m)
 		}
diff --git a/lib/promscrape/discovery/eureka/eureka_test.go b/lib/promscrape/discovery/eureka/eureka_test.go
index 26bc0988ce..2900640964 100644
--- a/lib/promscrape/discovery/eureka/eureka_test.go
+++ b/lib/promscrape/discovery/eureka/eureka_test.go
@@ -1,11 +1,10 @@
 package eureka
 
 import (
-	"reflect"
 	"testing"
 
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 func Test_addInstanceLabels(t *testing.T) {
@@ -15,7 +14,7 @@ func Test_addInstanceLabels(t *testing.T) {
 	tests := []struct {
 		name string
 		args args
-		want [][]prompbmarshal.Label
+		want []*promutils.Labels
 	}{
 		{
 			name: "1 application",
@@ -50,8 +49,8 @@ func Test_addInstanceLabels(t *testing.T) {
 					},
 				},
 			},
-			want: [][]prompbmarshal.Label{
-				discoveryutils.GetSortedLabels(map[string]string{
+			want: []*promutils.Labels{
+				promutils.NewLabelsFromMap(map[string]string{
 					"__address__":                                   "host-1:9100",
 					"instance":                                      "some-id",
 					"__meta_eureka_app_instance_hostname":           "host-1",
@@ -75,13 +74,7 @@ func Test_addInstanceLabels(t *testing.T) {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			got := addInstanceLabels(tt.args.applications)
-			var sortedLabelss [][]prompbmarshal.Label
-			for _, labels := range got {
-				sortedLabelss = append(sortedLabelss, discoveryutils.GetSortedLabels(labels))
-			}
-			if !reflect.DeepEqual(sortedLabelss, tt.want) {
-				t.Fatalf("unexpected labels \ngot : %v, \nwant: %v", got, tt.want)
-			}
+			discoveryutils.TestEqualLabelss(t, got, tt.want)
 		})
 	}
 }
diff --git a/lib/promscrape/discovery/gce/gce.go b/lib/promscrape/discovery/gce/gce.go
index f8b5dfe38d..70ece8a04f 100644
--- a/lib/promscrape/discovery/gce/gce.go
+++ b/lib/promscrape/discovery/gce/gce.go
@@ -4,6 +4,8 @@ import (
 	"flag"
 	"fmt"
 	"time"
+
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 // SDCheckInterval defines interval for targets refresh.
@@ -60,7 +62,7 @@ func (z ZoneYAML) MarshalYAML() (interface{}, error) {
 }
 
 // GetLabels returns gce labels according to sdc.
-func (sdc *SDConfig) GetLabels(baseDir string) ([]map[string]string, error) {
+func (sdc *SDConfig) GetLabels(baseDir string) ([]*promutils.Labels, error) {
 	cfg, err := getAPIConfig(sdc)
 	if err != nil {
 		return nil, fmt.Errorf("cannot get API config: %w", err)
diff --git a/lib/promscrape/discovery/gce/instance.go b/lib/promscrape/discovery/gce/instance.go
index 2c16a9c377..cb1d6596ab 100644
--- a/lib/promscrape/discovery/gce/instance.go
+++ b/lib/promscrape/discovery/gce/instance.go
@@ -8,12 +8,13 @@ import (
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 // getInstancesLabels returns labels for gce instances obtained from the given cfg
-func getInstancesLabels(cfg *apiConfig) []map[string]string {
+func getInstancesLabels(cfg *apiConfig) []*promutils.Labels {
 	insts := getInstances(cfg)
-	var ms []map[string]string
+	var ms []*promutils.Labels
 	for _, inst := range insts {
 		ms = inst.appendTargetLabels(ms, cfg.project, cfg.tagSeparator, cfg.port)
 	}
@@ -88,7 +89,7 @@ type Instance struct {
 	NetworkInterfaces []NetworkInterface
 	Tags              TagList
 	Metadata          MetadataList
-	Labels            discoveryutils.SortedLabels
+	Labels            *promutils.Labels
 }
 
 // NetworkInterface is network interface from https://cloud.google.com/compute/docs/reference/rest/v1/instances/list
@@ -131,42 +132,41 @@ func parseInstanceList(data []byte) (*InstanceList, error) {
 	return &il, nil
 }
 
-func (inst *Instance) appendTargetLabels(ms []map[string]string, project, tagSeparator string, port int) []map[string]string {
+func (inst *Instance) appendTargetLabels(ms []*promutils.Labels, project, tagSeparator string, port int) []*promutils.Labels {
 	if len(inst.NetworkInterfaces) == 0 {
 		return ms
 	}
 	iface := inst.NetworkInterfaces[0]
 	addr := discoveryutils.JoinHostPort(iface.NetworkIP, port)
-	m := map[string]string{
-		"__address__":                addr,
-		"__meta_gce_instance_id":     inst.ID,
-		"__meta_gce_instance_status": inst.Status,
-		"__meta_gce_instance_name":   inst.Name,
-		"__meta_gce_machine_type":    inst.MachineType,
-		"__meta_gce_network":         iface.Network,
-		"__meta_gce_private_ip":      iface.NetworkIP,
-		"__meta_gce_project":         project,
-		"__meta_gce_subnetwork":      iface.Subnetwork,
-		"__meta_gce_zone":            inst.Zone,
-	}
+	m := promutils.NewLabels(24)
+	m.Add("__address__", addr)
+	m.Add("__meta_gce_instance_id", inst.ID)
+	m.Add("__meta_gce_instance_status", inst.Status)
+	m.Add("__meta_gce_instance_name", inst.Name)
+	m.Add("__meta_gce_machine_type", inst.MachineType)
+	m.Add("__meta_gce_network", iface.Network)
+	m.Add("__meta_gce_private_ip", iface.NetworkIP)
+	m.Add("__meta_gce_project", project)
+	m.Add("__meta_gce_subnetwork", iface.Subnetwork)
+	m.Add("__meta_gce_zone", inst.Zone)
 	for _, iface := range inst.NetworkInterfaces {
-		m[discoveryutils.SanitizeLabelName("__meta_gce_interface_ipv4_"+iface.Name)] = iface.NetworkIP
+		m.Add(discoveryutils.SanitizeLabelName("__meta_gce_interface_ipv4_"+iface.Name), iface.NetworkIP)
 	}
 	if len(inst.Tags.Items) > 0 {
 		// We surround the separated list with the separator as well. This way regular expressions
 		// in relabeling rules don't have to consider tag positions.
-		m["__meta_gce_tags"] = tagSeparator + strings.Join(inst.Tags.Items, tagSeparator) + tagSeparator
+		m.Add("__meta_gce_tags", tagSeparator+strings.Join(inst.Tags.Items, tagSeparator)+tagSeparator)
 	}
 	for _, item := range inst.Metadata.Items {
-		m[discoveryutils.SanitizeLabelName("__meta_gce_metadata_"+item.Key)] = item.Value
+		m.Add(discoveryutils.SanitizeLabelName("__meta_gce_metadata_"+item.Key), item.Value)
 	}
-	for _, label := range inst.Labels {
-		m[discoveryutils.SanitizeLabelName("__meta_gce_label_"+label.Name)] = label.Value
+	for _, label := range inst.Labels.Labels {
+		m.Add(discoveryutils.SanitizeLabelName("__meta_gce_label_"+label.Name), label.Value)
 	}
 	if len(iface.AccessConfigs) > 0 {
 		ac := iface.AccessConfigs[0]
 		if ac.Type == "ONE_TO_ONE_NAT" {
-			m["__meta_gce_public_ip"] = ac.NatIP
+			m.Add("__meta_gce_public_ip", ac.NatIP)
 		}
 	}
 	ms = append(ms, m)
diff --git a/lib/promscrape/discovery/gce/instance_test.go b/lib/promscrape/discovery/gce/instance_test.go
index 0364ae6ef2..7d3912b0ff 100644
--- a/lib/promscrape/discovery/gce/instance_test.go
+++ b/lib/promscrape/discovery/gce/instance_test.go
@@ -1,11 +1,10 @@
 package gce
 
 import (
-	"reflect"
 	"testing"
 
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 func TestParseInstanceListFailure(t *testing.T) {
@@ -148,12 +147,8 @@ func TestParseInstanceListSuccess(t *testing.T) {
 	tagSeparator := ","
 	port := 80
 	labelss := inst.appendTargetLabels(nil, project, tagSeparator, port)
-	var sortedLabelss [][]prompbmarshal.Label
-	for _, labels := range labelss {
-		sortedLabelss = append(sortedLabelss, discoveryutils.GetSortedLabels(labels))
-	}
-	expectedLabelss := [][]prompbmarshal.Label{
-		discoveryutils.GetSortedLabels(map[string]string{
+	expectedLabelss := []*promutils.Labels{
+		promutils.NewLabelsFromMap(map[string]string{
 			"__address__":                                   "10.11.2.7:80",
 			"__meta_gce_instance_id":                        "7897352091592122",
 			"__meta_gce_instance_name":                      "play-1m-1-vmagent",
@@ -174,7 +169,5 @@ func TestParseInstanceListSuccess(t *testing.T) {
 			"__meta_gce_zone":                               "https://www.googleapis.com/compute/v1/projects/victoriametrics-test/zones/us-east1-b",
 		}),
 	}
-	if !reflect.DeepEqual(sortedLabelss, expectedLabelss) {
-		t.Fatalf("unexpected labels:\ngot\n%v\nwant\n%v", sortedLabelss, expectedLabelss)
-	}
+	discoveryutils.TestEqualLabelss(t, labelss, expectedLabelss)
 }
diff --git a/lib/promscrape/discovery/http/api.go b/lib/promscrape/discovery/http/api.go
index 40d9d20f97..667a8dc64d 100644
--- a/lib/promscrape/discovery/http/api.go
+++ b/lib/promscrape/discovery/http/api.go
@@ -7,6 +7,7 @@ import (
 	"strconv"
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 	"github.com/VictoriaMetrics/fasthttp"
 	"github.com/VictoriaMetrics/metrics"
 )
@@ -25,7 +26,7 @@ type apiConfig struct {
 // https://prometheus.io/docs/prometheus/latest/http_sd/
 type httpGroupTarget struct {
 	Targets []string          `json:"targets"`
-	Labels  map[string]string `json:"labels"`
+	Labels  *promutils.Labels `json:"labels"`
 }
 
 func newAPIConfig(sdc *SDConfig, baseDir string) (*apiConfig, error) {
diff --git a/lib/promscrape/discovery/http/api_test.go b/lib/promscrape/discovery/http/api_test.go
index 22c66a717a..eb33d3cc29 100644
--- a/lib/promscrape/discovery/http/api_test.go
+++ b/lib/promscrape/discovery/http/api_test.go
@@ -3,6 +3,8 @@ package http
 import (
 	"reflect"
 	"testing"
+
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 func Test_parseAPIResponse(t *testing.T) {
@@ -28,7 +30,7 @@ func Test_parseAPIResponse(t *testing.T) {
 			},
 			want: []httpGroupTarget{
 				{
-					Labels:  map[string]string{"label-1": "value-1"},
+					Labels:  promutils.NewLabelsFromMap(map[string]string{"label-1": "value-1"}),
 					Targets: []string{"http://target-1:9100", "http://target-2:9150"},
 				},
 			},
diff --git a/lib/promscrape/discovery/http/http.go b/lib/promscrape/discovery/http/http.go
index 1f924d1ab5..a6eb180c7a 100644
--- a/lib/promscrape/discovery/http/http.go
+++ b/lib/promscrape/discovery/http/http.go
@@ -6,6 +6,7 @@ import (
 	"time"
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promauth"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/proxy"
 )
 
@@ -25,7 +26,7 @@ type SDConfig struct {
 }
 
 // GetLabels returns http service discovery labels according to sdc.
-func (sdc *SDConfig) GetLabels(baseDir string) ([]map[string]string, error) {
+func (sdc *SDConfig) GetLabels(baseDir string) ([]*promutils.Labels, error) {
 	cfg, err := getAPIConfig(sdc, baseDir)
 	if err != nil {
 		return nil, fmt.Errorf("cannot get API config: %w", err)
@@ -37,17 +38,16 @@ func (sdc *SDConfig) GetLabels(baseDir string) ([]map[string]string, error) {
 	return addHTTPTargetLabels(hts, sdc.URL), nil
 }
 
-func addHTTPTargetLabels(src []httpGroupTarget, sourceURL string) []map[string]string {
-	ms := make([]map[string]string, 0, len(src))
+func addHTTPTargetLabels(src []httpGroupTarget, sourceURL string) []*promutils.Labels {
+	ms := make([]*promutils.Labels, 0, len(src))
 	for _, targetGroup := range src {
 		labels := targetGroup.Labels
 		for _, target := range targetGroup.Targets {
-			m := make(map[string]string, len(labels))
-			for k, v := range labels {
-				m[k] = v
-			}
-			m["__address__"] = target
-			m["__meta_url"] = sourceURL
+			m := promutils.NewLabels(2 + labels.Len())
+			m.AddFrom(labels)
+			m.Add("__address__", target)
+			m.Add("__meta_url", sourceURL)
+			m.RemoveDuplicates()
 			ms = append(ms, m)
 		}
 	}
diff --git a/lib/promscrape/discovery/http/http_test.go b/lib/promscrape/discovery/http/http_test.go
index 3ed48f0829..444571bd97 100644
--- a/lib/promscrape/discovery/http/http_test.go
+++ b/lib/promscrape/discovery/http/http_test.go
@@ -1,11 +1,10 @@
 package http
 
 import (
-	"reflect"
 	"testing"
 
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 func Test_addHTTPTargetLabels(t *testing.T) {
@@ -15,7 +14,7 @@ func Test_addHTTPTargetLabels(t *testing.T) {
 	tests := []struct {
 		name string
 		args args
-		want [][]prompbmarshal.Label
+		want []*promutils.Labels
 	}{
 		{
 			name: "add ok",
@@ -23,18 +22,18 @@ func Test_addHTTPTargetLabels(t *testing.T) {
 				src: []httpGroupTarget{
 					{
 						Targets: []string{"127.0.0.1:9100", "127.0.0.2:91001"},
-						Labels:  map[string]string{"__meta_kubernetes_pod": "pod-1", "__meta_consul_dc": "dc-2"},
+						Labels:  promutils.NewLabelsFromMap(map[string]string{"__meta_kubernetes_pod": "pod-1", "__meta_consul_dc": "dc-2"}),
 					},
 				},
 			},
-			want: [][]prompbmarshal.Label{
-				discoveryutils.GetSortedLabels(map[string]string{
+			want: []*promutils.Labels{
+				promutils.NewLabelsFromMap(map[string]string{
 					"__address__":           "127.0.0.1:9100",
 					"__meta_kubernetes_pod": "pod-1",
 					"__meta_consul_dc":      "dc-2",
 					"__meta_url":            "http://foo.bar/baz?aaa=bb",
 				}),
-				discoveryutils.GetSortedLabels(map[string]string{
+				promutils.NewLabelsFromMap(map[string]string{
 					"__address__":           "127.0.0.2:91001",
 					"__meta_kubernetes_pod": "pod-1",
 					"__meta_consul_dc":      "dc-2",
@@ -46,13 +45,7 @@ func Test_addHTTPTargetLabels(t *testing.T) {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			got := addHTTPTargetLabels(tt.args.src, "http://foo.bar/baz?aaa=bb")
-			var sortedLabelss [][]prompbmarshal.Label
-			for _, labels := range got {
-				sortedLabelss = append(sortedLabelss, discoveryutils.GetSortedLabels(labels))
-			}
-			if !reflect.DeepEqual(sortedLabelss, tt.want) {
-				t.Errorf("addHTTPTargetLabels() \ngot  \n%v\n, \nwant \n%v\n", sortedLabelss, tt.want)
-			}
+			discoveryutils.TestEqualLabelss(t, got, tt.want)
 		})
 	}
 }
diff --git a/lib/promscrape/discovery/kubernetes/api_watcher.go b/lib/promscrape/discovery/kubernetes/api_watcher.go
index dc152979b6..932264f89e 100644
--- a/lib/promscrape/discovery/kubernetes/api_watcher.go
+++ b/lib/promscrape/discovery/kubernetes/api_watcher.go
@@ -19,6 +19,7 @@ import (
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/cgroup"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promauth"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 	"github.com/VictoriaMetrics/metrics"
 )
 
@@ -37,7 +38,7 @@ type object interface {
 	key() string
 
 	// getTargetLabels must be called under gw.mu lock.
-	getTargetLabels(gw *groupWatcher) []map[string]string
+	getTargetLabels(gw *groupWatcher) []*promutils.Labels
 }
 
 // parseObjectFunc must parse object from the given data.
@@ -136,8 +137,8 @@ func (aw *apiWatcher) updateScrapeWorks(uw *urlWatcher, swosByKey map[string][]i
 	aw.swosByURLWatcherLock.Unlock()
 }
 
-func (aw *apiWatcher) setScrapeWorks(uw *urlWatcher, key string, labels []map[string]string) {
-	swos := getScrapeWorkObjectsForLabels(aw.swcFunc, labels)
+func (aw *apiWatcher) setScrapeWorks(uw *urlWatcher, key string, labelss []*promutils.Labels) {
+	swos := getScrapeWorkObjectsForLabels(aw.swcFunc, labelss)
 	aw.swosByURLWatcherLock.Lock()
 	swosByKey := aw.swosByURLWatcher[uw]
 	if swosByKey == nil {
@@ -163,7 +164,7 @@ func (aw *apiWatcher) removeScrapeWorks(uw *urlWatcher, key string) {
 	aw.swosByURLWatcherLock.Unlock()
 }
 
-func getScrapeWorkObjectsForLabels(swcFunc ScrapeWorkConstructorFunc, labelss []map[string]string) []interface{} {
+func getScrapeWorkObjectsForLabels(swcFunc ScrapeWorkConstructorFunc, labelss []*promutils.Labels) []interface{} {
 	// Do not pre-allocate swos, since it is likely the swos will be empty because of relabeling
 	var swos []interface{}
 	for _, labels := range labelss {
@@ -299,24 +300,31 @@ func (gw *groupWatcher) getScrapeWorkObjectsByAPIWatcherLocked(objectsByKey map[
 	var wg sync.WaitGroup
 	limiterCh := make(chan struct{}, cgroup.AvailableCPUs())
 	for key, o := range objectsByKey {
-		labels := o.getTargetLabels(gw)
+		labelss := o.getTargetLabels(gw)
 		wg.Add(1)
 		limiterCh <- struct{}{}
-		go func(key string, labels []map[string]string) {
+		go func(key string, labelss []*promutils.Labels) {
 			for aw, e := range swosByAPIWatcher {
-				swos := getScrapeWorkObjectsForLabels(aw.swcFunc, labels)
+				swos := getScrapeWorkObjectsForLabels(aw.swcFunc, labelss)
 				e.mu.Lock()
 				e.swosByKey[key] = swos
 				e.mu.Unlock()
 			}
+			putLabelssToPool(labelss)
 			wg.Done()
 			<-limiterCh
-		}(key, labels)
+		}(key, labelss)
 	}
 	wg.Wait()
 	return swosByAPIWatcher
 }
 
+func putLabelssToPool(labelss []*promutils.Labels) {
+	for _, labels := range labelss {
+		promutils.PutLabels(labels)
+	}
+}
+
 func (gw *groupWatcher) getObjectByRoleLocked(role, namespace, name string) object {
 	if role == "node" {
 		// Node objects have no namespace
@@ -764,10 +772,11 @@ func (uw *urlWatcher) updateObjectLocked(key string, o object) {
 		uw.objectsUpdated.Inc()
 	}
 	if len(uw.aws) > 0 {
-		labels := o.getTargetLabels(uw.gw)
+		labelss := o.getTargetLabels(uw.gw)
 		for aw := range uw.aws {
-			aw.setScrapeWorks(uw, key, labels)
+			aw.setScrapeWorks(uw, key, labelss)
 		}
+		putLabelssToPool(labelss)
 	}
 	uw.maybeUpdateDependedScrapeWorksLocked()
 }
diff --git a/lib/promscrape/discovery/kubernetes/api_watcher_test.go b/lib/promscrape/discovery/kubernetes/api_watcher_test.go
index f59e84833d..e767c3a8f0 100644
--- a/lib/promscrape/discovery/kubernetes/api_watcher_test.go
+++ b/lib/promscrape/discovery/kubernetes/api_watcher_test.go
@@ -8,6 +8,8 @@ import (
 	"sync"
 	"testing"
 	"time"
+
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 func TestGetAPIPathsWithNamespaces(t *testing.T) {
@@ -919,10 +921,10 @@ func TestGetScrapeWorkObjects(t *testing.T) {
 			}
 			testAPIServer := httptest.NewServer(mux)
 			tc.sdc.APIServer = testAPIServer.URL
-			ac, err := newAPIConfig(tc.sdc, "", func(metaLabels map[string]string) interface{} {
+			ac, err := newAPIConfig(tc.sdc, "", func(metaLabels *promutils.Labels) interface{} {
 				var res []interface{}
-				for k := range metaLabels {
-					res = append(res, k)
+				for _, label := range metaLabels.Labels {
+					res = append(res, label.Name)
 				}
 				return res
 			})
diff --git a/lib/promscrape/discovery/kubernetes/common_types.go b/lib/promscrape/discovery/kubernetes/common_types.go
index c2479ca196..a268ecb174 100644
--- a/lib/promscrape/discovery/kubernetes/common_types.go
+++ b/lib/promscrape/discovery/kubernetes/common_types.go
@@ -1,7 +1,9 @@
 package kubernetes
 
 import (
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 // ObjectMeta represents ObjectMeta from k8s API.
@@ -11,8 +13,8 @@ type ObjectMeta struct {
 	Name            string
 	Namespace       string
 	UID             string
-	Labels          discoveryutils.SortedLabels
-	Annotations     discoveryutils.SortedLabels
+	Labels          *promutils.Labels
+	Annotations     *promutils.Labels
 	OwnerReferences []OwnerReference
 }
 
@@ -26,15 +28,38 @@ type ListMeta struct {
 	ResourceVersion string
 }
 
-func (om *ObjectMeta) registerLabelsAndAnnotations(prefix string, m map[string]string) {
-	for _, lb := range om.Labels {
-		m[discoveryutils.SanitizeLabelName(prefix+"_label_"+lb.Name)] = lb.Value
-		m[discoveryutils.SanitizeLabelName(prefix+"_labelpresent_"+lb.Name)] = "true"
+func (om *ObjectMeta) registerLabelsAndAnnotations(prefix string, m *promutils.Labels) {
+	bb := bbPool.Get()
+	b := bb.B
+	for _, lb := range om.Labels.GetLabels() {
+		b = appendThreeStrings(b[:0], prefix, "_label_", lb.Name)
+		labelName := bytesutil.ToUnsafeString(b)
+		m.Add(discoveryutils.SanitizeLabelName(labelName), lb.Value)
+
+		b = appendThreeStrings(b[:0], prefix, "_labelpresent_", lb.Name)
+		labelName = bytesutil.ToUnsafeString(b)
+		m.Add(discoveryutils.SanitizeLabelName(labelName), "true")
 	}
-	for _, a := range om.Annotations {
-		m[discoveryutils.SanitizeLabelName(prefix+"_annotation_"+a.Name)] = a.Value
-		m[discoveryutils.SanitizeLabelName(prefix+"_annotationpresent_"+a.Name)] = "true"
+	for _, a := range om.Annotations.GetLabels() {
+		b = appendThreeStrings(b[:0], prefix, "_annotation_", a.Name)
+		labelName := bytesutil.ToUnsafeString(b)
+		m.Add(discoveryutils.SanitizeLabelName(labelName), a.Value)
+
+		b = appendThreeStrings(b[:0], prefix, "_annotationpresent_", a.Name)
+		labelName = bytesutil.ToUnsafeString(b)
+		m.Add(discoveryutils.SanitizeLabelName(labelName), "true")
 	}
+	bb.B = b
+	bbPool.Put(bb)
+}
+
+var bbPool bytesutil.ByteBufferPool
+
+func appendThreeStrings(dst []byte, a, b, c string) []byte {
+	dst = append(dst, a...)
+	dst = append(dst, b...)
+	dst = append(dst, c...)
+	return dst
 }
 
 // OwnerReference represents OwnerReferense from k8s API.
diff --git a/lib/promscrape/discovery/kubernetes/endpoints.go b/lib/promscrape/discovery/kubernetes/endpoints.go
index a32e79e878..cff09bec72 100644
--- a/lib/promscrape/discovery/kubernetes/endpoints.go
+++ b/lib/promscrape/discovery/kubernetes/endpoints.go
@@ -7,6 +7,7 @@ import (
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 func (eps *Endpoints) key() string {
@@ -91,13 +92,13 @@ type EndpointPort struct {
 // getTargetLabels returns labels for each endpoint in eps.
 //
 // See https://prometheus.io/docs/prometheus/latest/configuration/configuration/#endpoints
-func (eps *Endpoints) getTargetLabels(gw *groupWatcher) []map[string]string {
+func (eps *Endpoints) getTargetLabels(gw *groupWatcher) []*promutils.Labels {
 	var svc *Service
 	if o := gw.getObjectByRoleLocked("service", eps.Metadata.Namespace, eps.Metadata.Name); o != nil {
 		svc = o.(*Service)
 	}
 	podPortsSeen := make(map[*Pod][]int)
-	var ms []map[string]string
+	var ms []*promutils.Labels
 	for _, ess := range eps.Subsets {
 		for _, epp := range ess.Ports {
 			ms = appendEndpointLabelsForAddresses(ms, gw, podPortsSeen, eps, ess.Addresses, epp, svc, "true")
@@ -106,7 +107,7 @@ func (eps *Endpoints) getTargetLabels(gw *groupWatcher) []map[string]string {
 	}
 	// See https://kubernetes.io/docs/reference/labels-annotations-taints/#endpoints-kubernetes-io-over-capacity
 	// and https://github.com/kubernetes/kubernetes/pull/99975
-	switch eps.Metadata.Annotations.GetByName("endpoints.kubernetes.io/over-capacity") {
+	switch eps.Metadata.Annotations.Get("endpoints.kubernetes.io/over-capacity") {
 	case "truncated":
 		logger.Warnf(`the number of targets for "role: endpoints" %q exceeds 1000 and has been truncated; please use "role: endpointslice" instead`, eps.Metadata.key())
 	case "warning":
@@ -129,14 +130,14 @@ func (eps *Endpoints) getTargetLabels(gw *groupWatcher) []map[string]string {
 					continue
 				}
 				addr := discoveryutils.JoinHostPort(p.Status.PodIP, cp.ContainerPort)
-				m := map[string]string{
-					"__address__": addr,
-				}
+				m := promutils.GetLabels()
+				m.Add("__address__", addr)
 				p.appendCommonLabels(m, gw)
 				p.appendContainerLabels(m, c, &cp)
 				if svc != nil {
 					svc.appendCommonLabels(m)
 				}
+				m.RemoveDuplicates()
 				ms = append(ms, m)
 			}
 		}
@@ -144,8 +145,8 @@ func (eps *Endpoints) getTargetLabels(gw *groupWatcher) []map[string]string {
 	return ms
 }
 
-func appendEndpointLabelsForAddresses(ms []map[string]string, gw *groupWatcher, podPortsSeen map[*Pod][]int, eps *Endpoints,
-	eas []EndpointAddress, epp EndpointPort, svc *Service, ready string) []map[string]string {
+func appendEndpointLabelsForAddresses(ms []*promutils.Labels, gw *groupWatcher, podPortsSeen map[*Pod][]int, eps *Endpoints,
+	eas []EndpointAddress, epp EndpointPort, svc *Service, ready string) []*promutils.Labels {
 	for _, ea := range eas {
 		var p *Pod
 		if ea.TargetRef.Name != "" {
@@ -154,13 +155,14 @@ func appendEndpointLabelsForAddresses(ms []map[string]string, gw *groupWatcher,
 			}
 		}
 		m := getEndpointLabelsForAddressAndPort(gw, podPortsSeen, eps, ea, epp, p, svc, ready)
+		m.RemoveDuplicates()
 		ms = append(ms, m)
 	}
 	return ms
 }
 
 func getEndpointLabelsForAddressAndPort(gw *groupWatcher, podPortsSeen map[*Pod][]int, eps *Endpoints, ea EndpointAddress, epp EndpointPort,
-	p *Pod, svc *Service, ready string) map[string]string {
+	p *Pod, svc *Service, ready string) *promutils.Labels {
 	m := getEndpointLabels(eps.Metadata, ea, epp, ready)
 	if svc != nil {
 		svc.appendCommonLabels(m)
@@ -188,26 +190,24 @@ func getEndpointLabelsForAddressAndPort(gw *groupWatcher, podPortsSeen map[*Pod]
 	return m
 }
 
-func getEndpointLabels(om ObjectMeta, ea EndpointAddress, epp EndpointPort, ready string) map[string]string {
+func getEndpointLabels(om ObjectMeta, ea EndpointAddress, epp EndpointPort, ready string) *promutils.Labels {
 	addr := discoveryutils.JoinHostPort(ea.IP, epp.Port)
-	m := map[string]string{
-		"__address__":                      addr,
-		"__meta_kubernetes_namespace":      om.Namespace,
-		"__meta_kubernetes_endpoints_name": om.Name,
-
-		"__meta_kubernetes_endpoint_ready":         ready,
-		"__meta_kubernetes_endpoint_port_name":     epp.Name,
-		"__meta_kubernetes_endpoint_port_protocol": epp.Protocol,
-	}
+	m := promutils.GetLabels()
+	m.Add("__address__", addr)
+	m.Add("__meta_kubernetes_namespace", om.Namespace)
+	m.Add("__meta_kubernetes_endpoints_name", om.Name)
+	m.Add("__meta_kubernetes_endpoint_ready", ready)
+	m.Add("__meta_kubernetes_endpoint_port_name", epp.Name)
+	m.Add("__meta_kubernetes_endpoint_port_protocol", epp.Protocol)
 	if ea.TargetRef.Kind != "" {
-		m["__meta_kubernetes_endpoint_address_target_kind"] = ea.TargetRef.Kind
-		m["__meta_kubernetes_endpoint_address_target_name"] = ea.TargetRef.Name
+		m.Add("__meta_kubernetes_endpoint_address_target_kind", ea.TargetRef.Kind)
+		m.Add("__meta_kubernetes_endpoint_address_target_name", ea.TargetRef.Name)
 	}
 	if ea.NodeName != "" {
-		m["__meta_kubernetes_endpoint_node_name"] = ea.NodeName
+		m.Add("__meta_kubernetes_endpoint_node_name", ea.NodeName)
 	}
 	if ea.Hostname != "" {
-		m["__meta_kubernetes_endpoint_hostname"] = ea.Hostname
+		m.Add("__meta_kubernetes_endpoint_hostname", ea.Hostname)
 	}
 	return m
 }
diff --git a/lib/promscrape/discovery/kubernetes/endpoints_test.go b/lib/promscrape/discovery/kubernetes/endpoints_test.go
index c238de6c43..402bb18edc 100644
--- a/lib/promscrape/discovery/kubernetes/endpoints_test.go
+++ b/lib/promscrape/discovery/kubernetes/endpoints_test.go
@@ -4,8 +4,7 @@ import (
 	"bytes"
 	"testing"
 
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 func TestParseEndpointsListFailure(t *testing.T) {
@@ -91,8 +90,8 @@ func TestParseEndpointsListSuccess(t *testing.T) {
 	}
 
 	sortedLabelss := getSortedLabelss(objectsByKey)
-	expectedLabelss := [][]prompbmarshal.Label{
-		discoveryutils.GetSortedLabels(map[string]string{
+	expectedLabelss := []*promutils.Labels{
+		promutils.NewLabelsFromMap(map[string]string{
 			"__address__": "172.17.0.2:8443",
 			"__meta_kubernetes_endpoint_address_target_kind":  "Pod",
 			"__meta_kubernetes_endpoint_address_target_name":  "coredns-6955765f44-lnp6t",
@@ -119,7 +118,7 @@ func TestGetEndpointsLabels(t *testing.T) {
 		containerPorts map[string][]ContainerPort
 		endpointPorts  []EndpointPort
 	}
-	f := func(t *testing.T, args testArgs, wantLabels [][]prompbmarshal.Label) {
+	f := func(t *testing.T, args testArgs, wantLabels []*promutils.Labels) {
 		t.Helper()
 		eps := Endpoints{
 			Metadata: ObjectMeta{
@@ -175,12 +174,7 @@ func TestGetEndpointsLabels(t *testing.T) {
 		}
 		node := Node{
 			Metadata: ObjectMeta{
-				Labels: []prompbmarshal.Label{
-					{
-						Name:  "node-label",
-						Value: "xyz",
-					},
-				},
+				Labels: promutils.NewLabelsFromMap(map[string]string{"node-label": "xyz"}),
 			},
 		}
 		for cn, ports := range args.containerPorts {
@@ -212,10 +206,11 @@ func TestGetEndpointsLabels(t *testing.T) {
 			},
 		}
 		gw.attachNodeMetadata = true
-		var sortedLabelss [][]prompbmarshal.Label
+		var sortedLabelss []*promutils.Labels
 		gotLabels := eps.getTargetLabels(&gw)
 		for _, lbs := range gotLabels {
-			sortedLabelss = append(sortedLabelss, discoveryutils.GetSortedLabels(lbs))
+			lbs.Sort()
+			sortedLabelss = append(sortedLabelss, lbs)
 		}
 		if !areEqualLabelss(sortedLabelss, wantLabels) {
 			t.Fatalf("unexpected labels:\ngot\n%v\nwant\n%v", sortedLabelss, wantLabels)
@@ -231,8 +226,8 @@ func TestGetEndpointsLabels(t *testing.T) {
 					Protocol: "foobar",
 				},
 			},
-		}, [][]prompbmarshal.Label{
-			discoveryutils.GetSortedLabels(map[string]string{
+		}, []*promutils.Labels{
+			promutils.NewLabelsFromMap(map[string]string{
 				"__address__": "10.13.15.15:8081",
 				"__meta_kubernetes_endpoint_address_target_kind": "Pod",
 				"__meta_kubernetes_endpoint_address_target_name": "test-pod",
@@ -272,8 +267,8 @@ func TestGetEndpointsLabels(t *testing.T) {
 					Protocol: "https",
 				},
 			},
-		}, [][]prompbmarshal.Label{
-			discoveryutils.GetSortedLabels(map[string]string{
+		}, []*promutils.Labels{
+			promutils.NewLabelsFromMap(map[string]string{
 				"__address__": "10.13.15.15:8081",
 				"__meta_kubernetes_endpoint_address_target_kind": "Pod",
 				"__meta_kubernetes_endpoint_address_target_name": "test-pod",
@@ -296,7 +291,7 @@ func TestGetEndpointsLabels(t *testing.T) {
 				"__meta_kubernetes_service_name":                 "test-eps",
 				"__meta_kubernetes_service_type":                 "service-type",
 			}),
-			discoveryutils.GetSortedLabels(map[string]string{
+			promutils.NewLabelsFromMap(map[string]string{
 				"__address__":                                    "192.168.15.1:8428",
 				"__meta_kubernetes_namespace":                    "default",
 				"__meta_kubernetes_node_label_node_label":        "xyz",
@@ -335,8 +330,8 @@ func TestGetEndpointsLabels(t *testing.T) {
 					Protocol: "xabc",
 				},
 			},
-		}, [][]prompbmarshal.Label{
-			discoveryutils.GetSortedLabels(map[string]string{
+		}, []*promutils.Labels{
+			promutils.NewLabelsFromMap(map[string]string{
 				"__address__": "10.13.15.15:8428",
 				"__meta_kubernetes_endpoint_address_target_kind": "Pod",
 				"__meta_kubernetes_endpoint_address_target_name": "test-pod",
diff --git a/lib/promscrape/discovery/kubernetes/endpointslice.go b/lib/promscrape/discovery/kubernetes/endpointslice.go
index 8e376865c0..a7506b184b 100644
--- a/lib/promscrape/discovery/kubernetes/endpointslice.go
+++ b/lib/promscrape/discovery/kubernetes/endpointslice.go
@@ -7,6 +7,7 @@ import (
 	"strconv"
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 func (eps *EndpointSlice) key() string {
@@ -37,16 +38,16 @@ func parseEndpointSlice(data []byte) (object, error) {
 // getTargetLabels returns labels for eps.
 //
 // See https://prometheus.io/docs/prometheus/latest/configuration/configuration/#endpointslices
-func (eps *EndpointSlice) getTargetLabels(gw *groupWatcher) []map[string]string {
+func (eps *EndpointSlice) getTargetLabels(gw *groupWatcher) []*promutils.Labels {
 	// The associated service name is stored in kubernetes.io/service-name label.
 	// See https://kubernetes.io/docs/reference/labels-annotations-taints/#kubernetesioservice-name
-	svcName := eps.Metadata.Labels.GetByName("kubernetes.io/service-name")
+	svcName := eps.Metadata.Labels.Get("kubernetes.io/service-name")
 	var svc *Service
 	if o := gw.getObjectByRoleLocked("service", eps.Metadata.Namespace, svcName); o != nil {
 		svc = o.(*Service)
 	}
 	podPortsSeen := make(map[*Pod][]int)
-	var ms []map[string]string
+	var ms []*promutils.Labels
 	for _, ess := range eps.Endpoints {
 		var p *Pod
 		if o := gw.getObjectByRoleLocked("pod", ess.TargetRef.Namespace, ess.TargetRef.Name); o != nil {
@@ -55,6 +56,7 @@ func (eps *EndpointSlice) getTargetLabels(gw *groupWatcher) []map[string]string
 		for _, epp := range eps.Ports {
 			for _, addr := range ess.Addresses {
 				m := getEndpointSliceLabelsForAddressAndPort(gw, podPortsSeen, addr, eps, ess, epp, p, svc)
+				m.RemoveDuplicates()
 				ms = append(ms, m)
 			}
 
@@ -77,14 +79,14 @@ func (eps *EndpointSlice) getTargetLabels(gw *groupWatcher) []map[string]string
 					continue
 				}
 				addr := discoveryutils.JoinHostPort(p.Status.PodIP, cp.ContainerPort)
-				m := map[string]string{
-					"__address__": addr,
-				}
+				m := promutils.GetLabels()
+				m.Add("__address__", addr)
 				p.appendCommonLabels(m, gw)
 				p.appendContainerLabels(m, c, &cp)
 				if svc != nil {
 					svc.appendCommonLabels(m)
 				}
+				m.RemoveDuplicates()
 				ms = append(ms, m)
 			}
 		}
@@ -98,7 +100,7 @@ func (eps *EndpointSlice) getTargetLabels(gw *groupWatcher) []map[string]string
 // p appended to seen Ports
 // if TargetRef matches
 func getEndpointSliceLabelsForAddressAndPort(gw *groupWatcher, podPortsSeen map[*Pod][]int, addr string, eps *EndpointSlice, ea Endpoint, epp EndpointPort,
-	p *Pod, svc *Service) map[string]string {
+	p *Pod, svc *Service) *promutils.Labels {
 	m := getEndpointSliceLabels(eps, addr, ea, epp)
 	if svc != nil {
 		svc.appendCommonLabels(m)
@@ -128,31 +130,30 @@ func getEndpointSliceLabelsForAddressAndPort(gw *groupWatcher, podPortsSeen map[
 }
 
 // //getEndpointSliceLabels builds labels for given EndpointSlice
-func getEndpointSliceLabels(eps *EndpointSlice, addr string, ea Endpoint, epp EndpointPort) map[string]string {
+func getEndpointSliceLabels(eps *EndpointSlice, addr string, ea Endpoint, epp EndpointPort) *promutils.Labels {
 	addr = discoveryutils.JoinHostPort(addr, epp.Port)
-	m := map[string]string{
-		"__address__":                                               addr,
-		"__meta_kubernetes_namespace":                               eps.Metadata.Namespace,
-		"__meta_kubernetes_endpointslice_name":                      eps.Metadata.Name,
-		"__meta_kubernetes_endpointslice_address_type":              eps.AddressType,
-		"__meta_kubernetes_endpointslice_endpoint_conditions_ready": strconv.FormatBool(ea.Conditions.Ready),
-		"__meta_kubernetes_endpointslice_port_name":                 epp.Name,
-		"__meta_kubernetes_endpointslice_port_protocol":             epp.Protocol,
-		"__meta_kubernetes_endpointslice_port":                      strconv.Itoa(epp.Port),
-	}
+	m := promutils.GetLabels()
+	m.Add("__address__", addr)
+	m.Add("__meta_kubernetes_namespace", eps.Metadata.Namespace)
+	m.Add("__meta_kubernetes_endpointslice_name", eps.Metadata.Name)
+	m.Add("__meta_kubernetes_endpointslice_address_type", eps.AddressType)
+	m.Add("__meta_kubernetes_endpointslice_endpoint_conditions_ready", strconv.FormatBool(ea.Conditions.Ready))
+	m.Add("__meta_kubernetes_endpointslice_port_name", epp.Name)
+	m.Add("__meta_kubernetes_endpointslice_port_protocol", epp.Protocol)
+	m.Add("__meta_kubernetes_endpointslice_port", strconv.Itoa(epp.Port))
 	if epp.AppProtocol != "" {
-		m["__meta_kubernetes_endpointslice_port_app_protocol"] = epp.AppProtocol
+		m.Add("__meta_kubernetes_endpointslice_port_app_protocol", epp.AppProtocol)
 	}
 	if ea.TargetRef.Kind != "" {
-		m["__meta_kubernetes_endpointslice_address_target_kind"] = ea.TargetRef.Kind
-		m["__meta_kubernetes_endpointslice_address_target_name"] = ea.TargetRef.Name
+		m.Add("__meta_kubernetes_endpointslice_address_target_kind", ea.TargetRef.Kind)
+		m.Add("__meta_kubernetes_endpointslice_address_target_name", ea.TargetRef.Name)
 	}
 	if ea.Hostname != "" {
-		m["__meta_kubernetes_endpointslice_endpoint_hostname"] = ea.Hostname
+		m.Add("__meta_kubernetes_endpointslice_endpoint_hostname", ea.Hostname)
 	}
 	for k, v := range ea.Topology {
-		m[discoveryutils.SanitizeLabelName("__meta_kubernetes_endpointslice_endpoint_topology_"+k)] = v
-		m[discoveryutils.SanitizeLabelName("__meta_kubernetes_endpointslice_endpoint_topology_present_"+k)] = "true"
+		m.Add(discoveryutils.SanitizeLabelName("__meta_kubernetes_endpointslice_endpoint_topology_"+k), v)
+		m.Add(discoveryutils.SanitizeLabelName("__meta_kubernetes_endpointslice_endpoint_topology_present_"+k), "true")
 	}
 	return m
 }
diff --git a/lib/promscrape/discovery/kubernetes/endpointslice_test.go b/lib/promscrape/discovery/kubernetes/endpointslice_test.go
index e789843f46..ef5c51e6ac 100644
--- a/lib/promscrape/discovery/kubernetes/endpointslice_test.go
+++ b/lib/promscrape/discovery/kubernetes/endpointslice_test.go
@@ -4,8 +4,7 @@ import (
 	"bytes"
 	"testing"
 
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 func TestParseEndpointSliceListFail(t *testing.T) {
@@ -165,8 +164,8 @@ func TestParseEndpointSliceListSuccess(t *testing.T) {
 		t.Fatalf("unexpected resource version; got %s; want %s", meta.ResourceVersion, expectedResourceVersion)
 	}
 	sortedLabelss := getSortedLabelss(objectsByKey)
-	expectedLabelss := [][]prompbmarshal.Label{
-		discoveryutils.GetSortedLabels(map[string]string{
+	expectedLabelss := []*promutils.Labels{
+		promutils.NewLabelsFromMap(map[string]string{
 			"__address__": "10.244.0.3:53",
 			"__meta_kubernetes_endpointslice_address_target_kind":                                                "Pod",
 			"__meta_kubernetes_endpointslice_address_target_name":                                                "coredns-66bff467f8-z8czk",
@@ -186,7 +185,7 @@ func TestParseEndpointSliceListSuccess(t *testing.T) {
 			"__meta_kubernetes_endpointslice_port_protocol":                                                      "UDP",
 			"__meta_kubernetes_namespace":                                                                        "kube-system",
 		}),
-		discoveryutils.GetSortedLabels(map[string]string{
+		promutils.NewLabelsFromMap(map[string]string{
 			"__address__": "10.244.0.3:9153",
 			"__meta_kubernetes_endpointslice_address_target_kind":                                                "Pod",
 			"__meta_kubernetes_endpointslice_address_target_name":                                                "coredns-66bff467f8-z8czk",
@@ -206,7 +205,7 @@ func TestParseEndpointSliceListSuccess(t *testing.T) {
 			"__meta_kubernetes_endpointslice_port_protocol":                                                      "TCP",
 			"__meta_kubernetes_namespace":                                                                        "kube-system",
 		}),
-		discoveryutils.GetSortedLabels(map[string]string{
+		promutils.NewLabelsFromMap(map[string]string{
 			"__address__": "172.18.0.2:6443",
 			"__meta_kubernetes_endpointslice_address_type":                            "IPv4",
 			"__meta_kubernetes_endpointslice_endpoint_conditions_ready":               "true",
@@ -230,13 +229,13 @@ func TestGetEndpointsliceLabels(t *testing.T) {
 		containerPorts map[string][]ContainerPort
 		endpointPorts  []EndpointPort
 	}
-	f := func(t *testing.T, args testArgs, wantLabels [][]prompbmarshal.Label) {
+	f := func(t *testing.T, args testArgs, wantLabels []*promutils.Labels) {
 		t.Helper()
 		eps := EndpointSlice{
 			Metadata: ObjectMeta{
 				Name:      "test-eps",
 				Namespace: "default",
-				Labels: discoveryutils.GetSortedLabels(map[string]string{
+				Labels: promutils.NewLabelsFromMap(map[string]string{
 					"kubernetes.io/service-name": "test-svc",
 				}),
 			},
@@ -295,12 +294,7 @@ func TestGetEndpointsliceLabels(t *testing.T) {
 		}
 		node := Node{
 			Metadata: ObjectMeta{
-				Labels: []prompbmarshal.Label{
-					{
-						Name:  "node-label",
-						Value: "xyz",
-					},
-				},
+				Labels: promutils.NewLabelsFromMap(map[string]string{"node-label": "xyz"}),
 			},
 		}
 		for cn, ports := range args.containerPorts {
@@ -332,10 +326,11 @@ func TestGetEndpointsliceLabels(t *testing.T) {
 			},
 		}
 		gw.attachNodeMetadata = true
-		var sortedLabelss [][]prompbmarshal.Label
+		var sortedLabelss []*promutils.Labels
 		gotLabels := eps.getTargetLabels(&gw)
 		for _, lbs := range gotLabels {
-			sortedLabelss = append(sortedLabelss, discoveryutils.GetSortedLabels(lbs))
+			lbs.Sort()
+			sortedLabelss = append(sortedLabelss, lbs)
 		}
 		if !areEqualLabelss(sortedLabelss, wantLabels) {
 			t.Fatalf("unexpected labels:\ngot\n%v\nwant\n%v", sortedLabelss, wantLabels)
@@ -351,8 +346,8 @@ func TestGetEndpointsliceLabels(t *testing.T) {
 					Protocol: "foobar",
 				},
 			},
-		}, [][]prompbmarshal.Label{
-			discoveryutils.GetSortedLabels(map[string]string{
+		}, []*promutils.Labels{
+			promutils.NewLabelsFromMap(map[string]string{
 				"__address__": "10.13.15.15:8081",
 				"__meta_kubernetes_endpointslice_address_target_kind":                     "Pod",
 				"__meta_kubernetes_endpointslice_address_target_name":                     "test-pod",
@@ -399,8 +394,8 @@ func TestGetEndpointsliceLabels(t *testing.T) {
 					Protocol: "https",
 				},
 			},
-		}, [][]prompbmarshal.Label{
-			discoveryutils.GetSortedLabels(map[string]string{
+		}, []*promutils.Labels{
+			promutils.NewLabelsFromMap(map[string]string{
 				"__address__": "10.13.15.15:8081",
 				"__meta_kubernetes_endpointslice_address_target_kind":                     "Pod",
 				"__meta_kubernetes_endpointslice_address_target_name":                     "test-pod",
@@ -430,7 +425,7 @@ func TestGetEndpointsliceLabels(t *testing.T) {
 				"__meta_kubernetes_service_name":                                          "test-svc",
 				"__meta_kubernetes_service_type":                                          "service-type",
 			}),
-			discoveryutils.GetSortedLabels(map[string]string{
+			promutils.NewLabelsFromMap(map[string]string{
 				"__address__":                                    "192.168.15.1:8428",
 				"__meta_kubernetes_namespace":                    "default",
 				"__meta_kubernetes_node_label_node_label":        "xyz",
@@ -469,8 +464,8 @@ func TestGetEndpointsliceLabels(t *testing.T) {
 					Protocol: "xabc",
 				},
 			},
-		}, [][]prompbmarshal.Label{
-			discoveryutils.GetSortedLabels(map[string]string{
+		}, []*promutils.Labels{
+			promutils.NewLabelsFromMap(map[string]string{
 				"__address__": "10.13.15.15:8428",
 				"__meta_kubernetes_endpointslice_address_target_kind":                     "Pod",
 				"__meta_kubernetes_endpointslice_address_target_name":                     "test-pod",
diff --git a/lib/promscrape/discovery/kubernetes/ingress.go b/lib/promscrape/discovery/kubernetes/ingress.go
index 7247c68ac6..59ff909040 100644
--- a/lib/promscrape/discovery/kubernetes/ingress.go
+++ b/lib/promscrape/discovery/kubernetes/ingress.go
@@ -5,6 +5,8 @@ import (
 	"fmt"
 	"io"
 	"strings"
+
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 func (ig *Ingress) key() string {
@@ -89,8 +91,8 @@ type HTTPIngressPath struct {
 // getTargetLabels returns labels for ig.
 //
 // See https://prometheus.io/docs/prometheus/latest/configuration/configuration/#ingress
-func (ig *Ingress) getTargetLabels(gw *groupWatcher) []map[string]string {
-	var ms []map[string]string
+func (ig *Ingress) getTargetLabels(gw *groupWatcher) []*promutils.Labels {
+	var ms []*promutils.Labels
 	for _, r := range ig.Spec.Rules {
 		paths := getIngressRulePaths(r.HTTP.Paths)
 		scheme := getSchemeForHost(r.Host, ig.Spec.TLS)
@@ -129,16 +131,15 @@ func matchesHostPattern(pattern, host string) bool {
 	return pattern == host
 }
 
-func getLabelsForIngressPath(ig *Ingress, scheme, host, path string) map[string]string {
-	m := map[string]string{
-		"__address__":                          host,
-		"__meta_kubernetes_namespace":          ig.Metadata.Namespace,
-		"__meta_kubernetes_ingress_name":       ig.Metadata.Name,
-		"__meta_kubernetes_ingress_scheme":     scheme,
-		"__meta_kubernetes_ingress_host":       host,
-		"__meta_kubernetes_ingress_path":       path,
-		"__meta_kubernetes_ingress_class_name": ig.Spec.IngressClassName,
-	}
+func getLabelsForIngressPath(ig *Ingress, scheme, host, path string) *promutils.Labels {
+	m := promutils.GetLabels()
+	m.Add("__address__", host)
+	m.Add("__meta_kubernetes_namespace", ig.Metadata.Namespace)
+	m.Add("__meta_kubernetes_ingress_name", ig.Metadata.Name)
+	m.Add("__meta_kubernetes_ingress_scheme", scheme)
+	m.Add("__meta_kubernetes_ingress_host", host)
+	m.Add("__meta_kubernetes_ingress_path", path)
+	m.Add("__meta_kubernetes_ingress_class_name", ig.Spec.IngressClassName)
 	ig.Metadata.registerLabelsAndAnnotations("__meta_kubernetes_ingress", m)
 	return m
 }
diff --git a/lib/promscrape/discovery/kubernetes/ingress_test.go b/lib/promscrape/discovery/kubernetes/ingress_test.go
index 004c9abd16..058adb8292 100644
--- a/lib/promscrape/discovery/kubernetes/ingress_test.go
+++ b/lib/promscrape/discovery/kubernetes/ingress_test.go
@@ -4,8 +4,7 @@ import (
 	"bytes"
 	"testing"
 
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 func TestMatchesHostPattern(t *testing.T) {
@@ -103,8 +102,8 @@ func TestParseIngressListSuccess(t *testing.T) {
 		t.Fatalf("unexpected resource version; got %s; want %s", meta.ResourceVersion, expectedResourceVersion)
 	}
 	sortedLabelss := getSortedLabelss(objectsByKey)
-	expectedLabelss := [][]prompbmarshal.Label{
-		discoveryutils.GetSortedLabels(map[string]string{
+	expectedLabelss := []*promutils.Labels{
+		promutils.NewLabelsFromMap(map[string]string{
 			"__address__": "foobar",
 			"__meta_kubernetes_ingress_annotation_kubectl_kubernetes_io_last_applied_configuration":        `{"apiVersion":"networking.k8s.io/v1","kind":"Ingress","metadata":{"annotations":{},"name":"test-ingress","namespace":"default"},"spec":{"backend":{"serviceName":"testsvc","servicePort":80}}}` + "\n",
 			"__meta_kubernetes_ingress_annotationpresent_kubectl_kubernetes_io_last_applied_configuration": "true",
diff --git a/lib/promscrape/discovery/kubernetes/kubernetes.go b/lib/promscrape/discovery/kubernetes/kubernetes.go
index f587ce2281..e65a9f5dcf 100644
--- a/lib/promscrape/discovery/kubernetes/kubernetes.go
+++ b/lib/promscrape/discovery/kubernetes/kubernetes.go
@@ -6,6 +6,7 @@ import (
 	"time"
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promauth"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/proxy"
 )
 
@@ -69,7 +70,7 @@ type Selector struct {
 }
 
 // ScrapeWorkConstructorFunc must construct ScrapeWork object for the given metaLabels.
-type ScrapeWorkConstructorFunc func(metaLabels map[string]string) interface{}
+type ScrapeWorkConstructorFunc func(metaLabels *promutils.Labels) interface{}
 
 // GetScrapeWorkObjects returns ScrapeWork objects for the given sdc.
 //
diff --git a/lib/promscrape/discovery/kubernetes/node.go b/lib/promscrape/discovery/kubernetes/node.go
index 812c7f3013..c5d5938cd8 100644
--- a/lib/promscrape/discovery/kubernetes/node.go
+++ b/lib/promscrape/discovery/kubernetes/node.go
@@ -6,6 +6,7 @@ import (
 	"io"
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 // getNodesLabels returns labels for k8s nodes obtained from the given cfg
@@ -84,19 +85,18 @@ type NodeDaemonEndpoints struct {
 // getTargetLabels returs labels for the given n.
 //
 // See https://prometheus.io/docs/prometheus/latest/configuration/configuration/#node
-func (n *Node) getTargetLabels(gw *groupWatcher) []map[string]string {
+func (n *Node) getTargetLabels(gw *groupWatcher) []*promutils.Labels {
 	addr := getNodeAddr(n.Status.Addresses)
 	if len(addr) == 0 {
 		// Skip node without address
 		return nil
 	}
 	addr = discoveryutils.JoinHostPort(addr, n.Status.DaemonEndpoints.KubeletEndpoint.Port)
-	m := map[string]string{
-		"__address__":                        addr,
-		"instance":                           n.Metadata.Name,
-		"__meta_kubernetes_node_name":        n.Metadata.Name,
-		"__meta_kubernetes_node_provider_id": n.Spec.ProviderID,
-	}
+	m := promutils.GetLabels()
+	m.Add("__address__", addr)
+	m.Add("instance", n.Metadata.Name)
+	m.Add("__meta_kubernetes_node_name", n.Metadata.Name)
+	m.Add("__meta_kubernetes_node_provider_id", n.Spec.ProviderID)
 	n.Metadata.registerLabelsAndAnnotations("__meta_kubernetes_node", m)
 	addrTypesUsed := make(map[string]bool, len(n.Status.Addresses))
 	for _, a := range n.Status.Addresses {
@@ -104,9 +104,9 @@ func (n *Node) getTargetLabels(gw *groupWatcher) []map[string]string {
 			continue
 		}
 		addrTypesUsed[a.Type] = true
-		m[discoveryutils.SanitizeLabelName("__meta_kubernetes_node_address_"+a.Type)] = a.Address
+		m.Add(discoveryutils.SanitizeLabelName("__meta_kubernetes_node_address_"+a.Type), a.Address)
 	}
-	return []map[string]string{m}
+	return []*promutils.Labels{m}
 }
 
 func getNodeAddr(nas []NodeAddress) string {
diff --git a/lib/promscrape/discovery/kubernetes/node_test.go b/lib/promscrape/discovery/kubernetes/node_test.go
index eca21b7d71..263ea03a44 100644
--- a/lib/promscrape/discovery/kubernetes/node_test.go
+++ b/lib/promscrape/discovery/kubernetes/node_test.go
@@ -7,8 +7,7 @@ import (
 	"strconv"
 	"testing"
 
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 func TestParseNodeListFailure(t *testing.T) {
@@ -242,8 +241,8 @@ func TestParseNodeListSuccess(t *testing.T) {
 		t.Fatalf("unexpected resource version; got %s; want %s", meta.ResourceVersion, expectedResourceVersion)
 	}
 	sortedLabelss := getSortedLabelss(objectsByKey)
-	expectedLabelss := [][]prompbmarshal.Label{
-		discoveryutils.GetSortedLabels(map[string]string{
+	expectedLabelss := []*promutils.Labels{
+		promutils.NewLabelsFromMap(map[string]string{
 			"instance":                           "m01",
 			"__address__":                        "172.17.0.2:10250",
 			"__meta_kubernetes_node_name":        "m01",
@@ -288,13 +287,14 @@ func TestParseNodeListSuccess(t *testing.T) {
 	}
 }
 
-func getSortedLabelss(objectsByKey map[string]object) [][]prompbmarshal.Label {
+func getSortedLabelss(objectsByKey map[string]object) []*promutils.Labels {
 	gw := newTestGroupWatcher()
-	var result [][]prompbmarshal.Label
+	var result []*promutils.Labels
 	for _, o := range objectsByKey {
 		labelss := o.getTargetLabels(gw)
 		for _, labels := range labelss {
-			result = append(result, discoveryutils.GetSortedLabels(labels))
+			labels.Sort()
+			result = append(result, labels)
 		}
 	}
 	return result
@@ -308,12 +308,7 @@ func newTestGroupWatcher() *groupWatcher {
 			objectsByKey: map[string]object{
 				"/test-node": &Node{
 					Metadata: ObjectMeta{
-						Labels: []prompbmarshal.Label{
-							{
-								Name:  "node-label",
-								Value: "xyz",
-							},
-						},
+						Labels: promutils.NewLabelsFromMap(map[string]string{"node-label": "xyz"}),
 					},
 				},
 			},
@@ -323,21 +318,21 @@ func newTestGroupWatcher() *groupWatcher {
 	return &gw
 }
 
-func areEqualLabelss(a, b [][]prompbmarshal.Label) bool {
+func areEqualLabelss(a, b []*promutils.Labels) bool {
 	sortLabelss(a)
 	sortLabelss(b)
 	return reflect.DeepEqual(a, b)
 }
 
-func sortLabelss(a [][]prompbmarshal.Label) {
+func sortLabelss(a []*promutils.Labels) {
 	sort.Slice(a, func(i, j int) bool {
 		return marshalLabels(a[i]) < marshalLabels(a[j])
 	})
 }
 
-func marshalLabels(a []prompbmarshal.Label) string {
+func marshalLabels(a *promutils.Labels) string {
 	var b []byte
-	for _, label := range a {
+	for _, label := range a.Labels {
 		b = strconv.AppendQuote(b, label.Name)
 		b = append(b, ':')
 		b = strconv.AppendQuote(b, label.Value)
diff --git a/lib/promscrape/discovery/kubernetes/pod.go b/lib/promscrape/discovery/kubernetes/pod.go
index 02f821a861..77c82f1df9 100644
--- a/lib/promscrape/discovery/kubernetes/pod.go
+++ b/lib/promscrape/discovery/kubernetes/pod.go
@@ -4,10 +4,11 @@ import (
 	"encoding/json"
 	"fmt"
 	"io"
-	"strconv"
 	"strings"
 
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 func (p *Pod) key() string {
@@ -98,18 +99,18 @@ type PodCondition struct {
 // getTargetLabels returns labels for each port of the given p.
 //
 // See https://prometheus.io/docs/prometheus/latest/configuration/configuration/#pod
-func (p *Pod) getTargetLabels(gw *groupWatcher) []map[string]string {
+func (p *Pod) getTargetLabels(gw *groupWatcher) []*promutils.Labels {
 	if len(p.Status.PodIP) == 0 {
 		// Skip pod without IP
 		return nil
 	}
-	var ms []map[string]string
+	var ms []*promutils.Labels
 	ms = appendPodLabels(ms, gw, p, p.Spec.Containers, "false")
 	ms = appendPodLabels(ms, gw, p, p.Spec.InitContainers, "true")
 	return ms
 }
 
-func appendPodLabels(ms []map[string]string, gw *groupWatcher, p *Pod, cs []Container, isInit string) []map[string]string {
+func appendPodLabels(ms []*promutils.Labels, gw *groupWatcher, p *Pod, cs []Container, isInit string) []*promutils.Labels {
 	for _, c := range cs {
 		for _, cp := range c.Ports {
 			ms = appendPodLabelsInternal(ms, gw, p, c, &cp, isInit)
@@ -121,53 +122,52 @@ func appendPodLabels(ms []map[string]string, gw *groupWatcher, p *Pod, cs []Cont
 	return ms
 }
 
-func appendPodLabelsInternal(ms []map[string]string, gw *groupWatcher, p *Pod, c Container, cp *ContainerPort, isInit string) []map[string]string {
+func appendPodLabelsInternal(ms []*promutils.Labels, gw *groupWatcher, p *Pod, c Container, cp *ContainerPort, isInit string) []*promutils.Labels {
 	addr := p.Status.PodIP
 	if cp != nil {
 		addr = discoveryutils.JoinHostPort(addr, cp.ContainerPort)
 	}
-	m := map[string]string{
-		"__address__":                          addr,
-		"__meta_kubernetes_pod_container_init": isInit,
-	}
+	m := promutils.GetLabels()
+	m.Add("__address__", addr)
+	m.Add("__meta_kubernetes_pod_container_init", isInit)
 	p.appendCommonLabels(m, gw)
 	p.appendContainerLabels(m, c, cp)
 	return append(ms, m)
 }
 
-func (p *Pod) appendContainerLabels(m map[string]string, c Container, cp *ContainerPort) {
-	m["__meta_kubernetes_pod_container_image"] = c.Image
-	m["__meta_kubernetes_pod_container_name"] = c.Name
+func (p *Pod) appendContainerLabels(m *promutils.Labels, c Container, cp *ContainerPort) {
+	m.Add("__meta_kubernetes_pod_container_image", c.Image)
+	m.Add("__meta_kubernetes_pod_container_name", c.Name)
 	if cp != nil {
-		m["__meta_kubernetes_pod_container_port_name"] = cp.Name
-		m["__meta_kubernetes_pod_container_port_number"] = strconv.Itoa(cp.ContainerPort)
-		m["__meta_kubernetes_pod_container_port_protocol"] = cp.Protocol
+		m.Add("__meta_kubernetes_pod_container_port_name", cp.Name)
+		m.Add("__meta_kubernetes_pod_container_port_number", bytesutil.Itoa(cp.ContainerPort))
+		m.Add("__meta_kubernetes_pod_container_port_protocol", cp.Protocol)
 	}
 }
 
-func (p *Pod) appendCommonLabels(m map[string]string, gw *groupWatcher) {
+func (p *Pod) appendCommonLabels(m *promutils.Labels, gw *groupWatcher) {
 	if gw.attachNodeMetadata {
-		m["__meta_kubernetes_node_name"] = p.Spec.NodeName
+		m.Add("__meta_kubernetes_node_name", p.Spec.NodeName)
 		o := gw.getObjectByRoleLocked("node", p.Metadata.Namespace, p.Spec.NodeName)
 		if o != nil {
 			n := o.(*Node)
 			n.Metadata.registerLabelsAndAnnotations("__meta_kubernetes_node", m)
 		}
 	}
-	m["__meta_kubernetes_pod_name"] = p.Metadata.Name
-	m["__meta_kubernetes_pod_ip"] = p.Status.PodIP
-	m["__meta_kubernetes_pod_ready"] = getPodReadyStatus(p.Status.Conditions)
-	m["__meta_kubernetes_pod_phase"] = p.Status.Phase
-	m["__meta_kubernetes_pod_node_name"] = p.Spec.NodeName
-	m["__meta_kubernetes_pod_host_ip"] = p.Status.HostIP
-	m["__meta_kubernetes_pod_uid"] = p.Metadata.UID
-	m["__meta_kubernetes_namespace"] = p.Metadata.Namespace
+	m.Add("__meta_kubernetes_pod_name", p.Metadata.Name)
+	m.Add("__meta_kubernetes_pod_ip", p.Status.PodIP)
+	m.Add("__meta_kubernetes_pod_ready", getPodReadyStatus(p.Status.Conditions))
+	m.Add("__meta_kubernetes_pod_phase", p.Status.Phase)
+	m.Add("__meta_kubernetes_pod_node_name", p.Spec.NodeName)
+	m.Add("__meta_kubernetes_pod_host_ip", p.Status.HostIP)
+	m.Add("__meta_kubernetes_pod_uid", p.Metadata.UID)
+	m.Add("__meta_kubernetes_namespace", p.Metadata.Namespace)
 	if pc := getPodController(p.Metadata.OwnerReferences); pc != nil {
 		if pc.Kind != "" {
-			m["__meta_kubernetes_pod_controller_kind"] = pc.Kind
+			m.Add("__meta_kubernetes_pod_controller_kind", pc.Kind)
 		}
 		if pc.Name != "" {
-			m["__meta_kubernetes_pod_controller_name"] = pc.Name
+			m.Add("__meta_kubernetes_pod_controller_name", pc.Name)
 		}
 	}
 	p.Metadata.registerLabelsAndAnnotations("__meta_kubernetes_pod", m)
@@ -185,8 +185,10 @@ func getPodController(ors []OwnerReference) *OwnerReference {
 func getPodReadyStatus(conds []PodCondition) string {
 	for _, c := range conds {
 		if c.Type == "Ready" {
-			return strings.ToLower(c.Status)
+			return toLowerConverter.Transform(c.Status)
 		}
 	}
 	return "unknown"
 }
+
+var toLowerConverter = bytesutil.NewFastStringTransformer(strings.ToLower)
diff --git a/lib/promscrape/discovery/kubernetes/pod_test.go b/lib/promscrape/discovery/kubernetes/pod_test.go
index 5d5bc81d89..4311c29e64 100644
--- a/lib/promscrape/discovery/kubernetes/pod_test.go
+++ b/lib/promscrape/discovery/kubernetes/pod_test.go
@@ -4,8 +4,7 @@ import (
 	"bytes"
 	"testing"
 
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 func TestParsePodListFailure(t *testing.T) {
@@ -240,8 +239,8 @@ func TestParsePodListSuccess(t *testing.T) {
 		t.Fatalf("unexpected resource version; got %s; want %s", meta.ResourceVersion, expectedResourceVersion)
 	}
 	sortedLabelss := getSortedLabelss(objectsByKey)
-	expectedLabelss := [][]prompbmarshal.Label{
-		discoveryutils.GetSortedLabels(map[string]string{
+	expectedLabelss := []*promutils.Labels{
+		promutils.NewLabelsFromMap(map[string]string{
 			"__address__": "172.17.0.2:1234",
 
 			"__meta_kubernetes_namespace":                    "kube-system",
diff --git a/lib/promscrape/discovery/kubernetes/pod_timing_test.go b/lib/promscrape/discovery/kubernetes/pod_timing_test.go
index 5d8d7b260a..6f9841f4d5 100644
--- a/lib/promscrape/discovery/kubernetes/pod_timing_test.go
+++ b/lib/promscrape/discovery/kubernetes/pod_timing_test.go
@@ -29,6 +29,7 @@ func BenchmarkPodGetTargetLabels(b *testing.B) {
 			if len(labelss) != 1 {
 				panic(fmt.Errorf("BUG: unexpected number of labelss returned: %d; want 1", len(labelss)))
 			}
+			putLabelssToPool(labelss)
 		}
 	})
 }
diff --git a/lib/promscrape/discovery/kubernetes/service.go b/lib/promscrape/discovery/kubernetes/service.go
index 77956d76bc..1306673be4 100644
--- a/lib/promscrape/discovery/kubernetes/service.go
+++ b/lib/promscrape/discovery/kubernetes/service.go
@@ -7,6 +7,7 @@ import (
 	"strconv"
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 func (s *Service) key() string {
@@ -72,31 +73,30 @@ type ServicePort struct {
 // getTargetLabels returns labels for each port of the given s.
 //
 // See https://prometheus.io/docs/prometheus/latest/configuration/configuration/#service
-func (s *Service) getTargetLabels(gw *groupWatcher) []map[string]string {
+func (s *Service) getTargetLabels(gw *groupWatcher) []*promutils.Labels {
 	host := fmt.Sprintf("%s.%s.svc", s.Metadata.Name, s.Metadata.Namespace)
-	var ms []map[string]string
+	var ms []*promutils.Labels
 	for _, sp := range s.Spec.Ports {
 		addr := discoveryutils.JoinHostPort(host, sp.Port)
-		m := map[string]string{
-			"__address__":                             addr,
-			"__meta_kubernetes_service_port_name":     sp.Name,
-			"__meta_kubernetes_service_port_number":   strconv.Itoa(sp.Port),
-			"__meta_kubernetes_service_port_protocol": sp.Protocol,
-		}
+		m := promutils.GetLabels()
+		m.Add("__address__", addr)
+		m.Add("__meta_kubernetes_service_port_name", sp.Name)
+		m.Add("__meta_kubernetes_service_port_number", strconv.Itoa(sp.Port))
+		m.Add("__meta_kubernetes_service_port_protocol", sp.Protocol)
 		s.appendCommonLabels(m)
 		ms = append(ms, m)
 	}
 	return ms
 }
 
-func (s *Service) appendCommonLabels(m map[string]string) {
-	m["__meta_kubernetes_namespace"] = s.Metadata.Namespace
-	m["__meta_kubernetes_service_name"] = s.Metadata.Name
-	m["__meta_kubernetes_service_type"] = s.Spec.Type
+func (s *Service) appendCommonLabels(m *promutils.Labels) {
+	m.Add("__meta_kubernetes_namespace", s.Metadata.Namespace)
+	m.Add("__meta_kubernetes_service_name", s.Metadata.Name)
+	m.Add("__meta_kubernetes_service_type", s.Spec.Type)
 	if s.Spec.Type != "ExternalName" {
-		m["__meta_kubernetes_service_cluster_ip"] = s.Spec.ClusterIP
+		m.Add("__meta_kubernetes_service_cluster_ip", s.Spec.ClusterIP)
 	} else {
-		m["__meta_kubernetes_service_external_name"] = s.Spec.ExternalName
+		m.Add("__meta_kubernetes_service_external_name", s.Spec.ExternalName)
 	}
 	s.Metadata.registerLabelsAndAnnotations("__meta_kubernetes_service", m)
 }
diff --git a/lib/promscrape/discovery/kubernetes/service_test.go b/lib/promscrape/discovery/kubernetes/service_test.go
index d4ff4949f6..b86c879a59 100644
--- a/lib/promscrape/discovery/kubernetes/service_test.go
+++ b/lib/promscrape/discovery/kubernetes/service_test.go
@@ -4,8 +4,7 @@ import (
 	"bytes"
 	"testing"
 
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 func TestParseServiceListFailure(t *testing.T) {
@@ -100,8 +99,8 @@ func TestParseServiceListSuccess(t *testing.T) {
 		t.Fatalf("unexpected resource version; got %s; want %s", meta.ResourceVersion, expectedResourceVersion)
 	}
 	sortedLabelss := getSortedLabelss(objectsByKey)
-	expectedLabelss := [][]prompbmarshal.Label{
-		discoveryutils.GetSortedLabels(map[string]string{
+	expectedLabelss := []*promutils.Labels{
+		promutils.NewLabelsFromMap(map[string]string{
 			"__address__":                             "kube-dns.kube-system.svc:53",
 			"__meta_kubernetes_namespace":             "kube-system",
 			"__meta_kubernetes_service_name":          "kube-dns",
@@ -125,7 +124,7 @@ func TestParseServiceListSuccess(t *testing.T) {
 			"__meta_kubernetes_service_annotationpresent_prometheus_io_port":   "true",
 			"__meta_kubernetes_service_annotationpresent_prometheus_io_scrape": "true",
 		}),
-		discoveryutils.GetSortedLabels(map[string]string{
+		promutils.NewLabelsFromMap(map[string]string{
 			"__address__":                             "kube-dns.kube-system.svc:53",
 			"__meta_kubernetes_namespace":             "kube-system",
 			"__meta_kubernetes_service_name":          "kube-dns",
@@ -149,7 +148,7 @@ func TestParseServiceListSuccess(t *testing.T) {
 			"__meta_kubernetes_service_annotationpresent_prometheus_io_port":   "true",
 			"__meta_kubernetes_service_annotationpresent_prometheus_io_scrape": "true",
 		}),
-		discoveryutils.GetSortedLabels(map[string]string{
+		promutils.NewLabelsFromMap(map[string]string{
 			"__address__":                             "kube-dns.kube-system.svc:9153",
 			"__meta_kubernetes_namespace":             "kube-system",
 			"__meta_kubernetes_service_name":          "kube-dns",
diff --git a/lib/promscrape/discovery/openstack/hypervisor.go b/lib/promscrape/discovery/openstack/hypervisor.go
index e9b48cdba3..04c0d9dc6c 100644
--- a/lib/promscrape/discovery/openstack/hypervisor.go
+++ b/lib/promscrape/discovery/openstack/hypervisor.go
@@ -7,6 +7,7 @@ import (
 	"strconv"
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 // See https://docs.openstack.org/api-ref/compute/#list-hypervisors-details
@@ -61,25 +62,24 @@ func (cfg *apiConfig) getHypervisors() ([]hypervisor, error) {
 	}
 }
 
-func addHypervisorLabels(hvs []hypervisor, port int) []map[string]string {
-	var ms []map[string]string
+func addHypervisorLabels(hvs []hypervisor, port int) []*promutils.Labels {
+	var ms []*promutils.Labels
 	for _, hv := range hvs {
 		addr := discoveryutils.JoinHostPort(hv.HostIP, port)
-		m := map[string]string{
-			"__address__":                          addr,
-			"__meta_openstack_hypervisor_type":     hv.Type,
-			"__meta_openstack_hypervisor_status":   hv.Status,
-			"__meta_openstack_hypervisor_hostname": hv.Hostname,
-			"__meta_openstack_hypervisor_state":    hv.State,
-			"__meta_openstack_hypervisor_host_ip":  hv.HostIP,
-			"__meta_openstack_hypervisor_id":       strconv.Itoa(hv.ID),
-		}
+		m := promutils.NewLabels(8)
+		m.Add("__address__", addr)
+		m.Add("__meta_openstack_hypervisor_type", hv.Type)
+		m.Add("__meta_openstack_hypervisor_status", hv.Status)
+		m.Add("__meta_openstack_hypervisor_hostname", hv.Hostname)
+		m.Add("__meta_openstack_hypervisor_state", hv.State)
+		m.Add("__meta_openstack_hypervisor_host_ip", hv.HostIP)
+		m.Add("__meta_openstack_hypervisor_id", strconv.Itoa(hv.ID))
 		ms = append(ms, m)
 	}
 	return ms
 }
 
-func getHypervisorLabels(cfg *apiConfig) ([]map[string]string, error) {
+func getHypervisorLabels(cfg *apiConfig) ([]*promutils.Labels, error) {
 	hvs, err := cfg.getHypervisors()
 	if err != nil {
 		return nil, fmt.Errorf("cannot get hypervisors: %w", err)
diff --git a/lib/promscrape/discovery/openstack/hypervisor_test.go b/lib/promscrape/discovery/openstack/hypervisor_test.go
index 81376aba08..12f6a0ad1b 100644
--- a/lib/promscrape/discovery/openstack/hypervisor_test.go
+++ b/lib/promscrape/discovery/openstack/hypervisor_test.go
@@ -4,8 +4,8 @@ import (
 	"reflect"
 	"testing"
 
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 func Test_parseHypervisorDetail(t *testing.T) {
@@ -107,7 +107,7 @@ func Test_addHypervisorLabels(t *testing.T) {
 	tests := []struct {
 		name string
 		args args
-		want [][]prompbmarshal.Label
+		want []*promutils.Labels
 	}{
 		{
 			name: "",
@@ -124,8 +124,8 @@ func Test_addHypervisorLabels(t *testing.T) {
 					},
 				},
 			},
-			want: [][]prompbmarshal.Label{
-				discoveryutils.GetSortedLabels(map[string]string{
+			want: []*promutils.Labels{
+				promutils.NewLabelsFromMap(map[string]string{
 					"__address__":                          "1.2.2.2:9100",
 					"__meta_openstack_hypervisor_host_ip":  "1.2.2.2",
 					"__meta_openstack_hypervisor_hostname": "fakehost",
@@ -140,13 +140,7 @@ func Test_addHypervisorLabels(t *testing.T) {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			got := addHypervisorLabels(tt.args.hvs, tt.args.port)
-			var sortedLabelss [][]prompbmarshal.Label
-			for _, labels := range got {
-				sortedLabelss = append(sortedLabelss, discoveryutils.GetSortedLabels(labels))
-			}
-			if !reflect.DeepEqual(sortedLabelss, tt.want) {
-				t.Errorf("addHypervisorLabels() = %v, want %v", sortedLabelss, tt.want)
-			}
+			discoveryutils.TestEqualLabelss(t, got, tt.want)
 		})
 	}
 }
diff --git a/lib/promscrape/discovery/openstack/instance.go b/lib/promscrape/discovery/openstack/instance.go
index 5f628d4203..06c338aadb 100644
--- a/lib/promscrape/discovery/openstack/instance.go
+++ b/lib/promscrape/discovery/openstack/instance.go
@@ -8,6 +8,7 @@ import (
 	"strconv"
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 // See https://docs.openstack.org/api-ref/compute/#list-servers
@@ -45,19 +46,18 @@ func parseServersDetail(data []byte) (*serversDetail, error) {
 	return &srvd, nil
 }
 
-func addInstanceLabels(servers []server, port int) []map[string]string {
-	var ms []map[string]string
+func addInstanceLabels(servers []server, port int) []*promutils.Labels {
+	var ms []*promutils.Labels
 	for _, server := range servers {
-		m := map[string]string{
-			"__meta_openstack_instance_id":     server.ID,
-			"__meta_openstack_instance_status": server.Status,
-			"__meta_openstack_instance_name":   server.Name,
-			"__meta_openstack_project_id":      server.TenantID,
-			"__meta_openstack_user_id":         server.UserID,
-			"__meta_openstack_instance_flavor": server.Flavor.ID,
-		}
+		commonLabels := promutils.NewLabels(16)
+		commonLabels.Add("__meta_openstack_instance_id", server.ID)
+		commonLabels.Add("__meta_openstack_instance_status", server.Status)
+		commonLabels.Add("__meta_openstack_instance_name", server.Name)
+		commonLabels.Add("__meta_openstack_project_id", server.TenantID)
+		commonLabels.Add("__meta_openstack_user_id", server.UserID)
+		commonLabels.Add("__meta_openstack_instance_flavor", server.Flavor.ID)
 		for k, v := range server.Metadata {
-			m[discoveryutils.SanitizeLabelName("__meta_openstack_tag_"+k)] = v
+			commonLabels.Add(discoveryutils.SanitizeLabelName("__meta_openstack_tag_"+k), v)
 		}
 		// Traverse server.Addresses in alphabetical order of pool name
 		// in order to return targets in deterministic order.
@@ -87,17 +87,15 @@ func addInstanceLabels(servers []server, port int) []map[string]string {
 					continue
 				}
 				// copy labels
-				lbls := make(map[string]string, len(m))
-				for k, v := range m {
-					lbls[k] = v
-				}
-				lbls["__meta_openstack_address_pool"] = pool
-				lbls["__meta_openstack_private_ip"] = ip.Address
+				m := promutils.NewLabels(20)
+				m.AddFrom(commonLabels)
+				m.Add("__meta_openstack_address_pool", pool)
+				m.Add("__meta_openstack_private_ip", ip.Address)
 				if len(publicIP) > 0 {
-					lbls["__meta_openstack_public_ip"] = publicIP
+					m.Add("__meta_openstack_public_ip", publicIP)
 				}
-				lbls["__address__"] = discoveryutils.JoinHostPort(ip.Address, port)
-				ms = append(ms, lbls)
+				m.Add("__address__", discoveryutils.JoinHostPort(ip.Address, port))
+				ms = append(ms, m)
 			}
 		}
 	}
@@ -133,7 +131,7 @@ func (cfg *apiConfig) getServers() ([]server, error) {
 	}
 }
 
-func getInstancesLabels(cfg *apiConfig) ([]map[string]string, error) {
+func getInstancesLabels(cfg *apiConfig) ([]*promutils.Labels, error) {
 	srv, err := cfg.getServers()
 	if err != nil {
 		return nil, err
diff --git a/lib/promscrape/discovery/openstack/instance_test.go b/lib/promscrape/discovery/openstack/instance_test.go
index 017d69b8f3..7a5e34ccdb 100644
--- a/lib/promscrape/discovery/openstack/instance_test.go
+++ b/lib/promscrape/discovery/openstack/instance_test.go
@@ -4,8 +4,8 @@ import (
 	"reflect"
 	"testing"
 
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 func Test_addInstanceLabels(t *testing.T) {
@@ -16,7 +16,7 @@ func Test_addInstanceLabels(t *testing.T) {
 	tests := []struct {
 		name string
 		args args
-		want [][]prompbmarshal.Label
+		want []*promutils.Labels
 	}{
 		{
 			name: "empty_response",
@@ -55,8 +55,8 @@ func Test_addInstanceLabels(t *testing.T) {
 					},
 				},
 			},
-			want: [][]prompbmarshal.Label{
-				discoveryutils.GetSortedLabels(map[string]string{
+			want: []*promutils.Labels{
+				promutils.NewLabelsFromMap(map[string]string{
 					"__address__":                      "192.168.0.1:9100",
 					"__meta_openstack_address_pool":    "test",
 					"__meta_openstack_instance_flavor": "5",
@@ -112,8 +112,8 @@ func Test_addInstanceLabels(t *testing.T) {
 					},
 				},
 			},
-			want: [][]prompbmarshal.Label{
-				discoveryutils.GetSortedLabels(map[string]string{
+			want: []*promutils.Labels{
+				promutils.NewLabelsFromMap(map[string]string{
 					"__address__":                      "10.10.0.1:9100",
 					"__meta_openstack_address_pool":    "internal",
 					"__meta_openstack_instance_flavor": "5",
@@ -124,7 +124,7 @@ func Test_addInstanceLabels(t *testing.T) {
 					"__meta_openstack_project_id":      "some-tenant-id",
 					"__meta_openstack_user_id":         "some-user-id",
 				}),
-				discoveryutils.GetSortedLabels(map[string]string{
+				promutils.NewLabelsFromMap(map[string]string{
 					"__address__":                      "192.168.0.1:9100",
 					"__meta_openstack_address_pool":    "test",
 					"__meta_openstack_instance_flavor": "5",
@@ -142,13 +142,7 @@ func Test_addInstanceLabels(t *testing.T) {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			got := addInstanceLabels(tt.args.servers, tt.args.port)
-			var sortedLabelss [][]prompbmarshal.Label
-			for _, labels := range got {
-				sortedLabelss = append(sortedLabelss, discoveryutils.GetSortedLabels(labels))
-			}
-			if !reflect.DeepEqual(sortedLabelss, tt.want) {
-				t.Errorf("addInstanceLabels() = \n got: %v,\nwant: %v", sortedLabelss, tt.want)
-			}
+			discoveryutils.TestEqualLabelss(t, got, tt.want)
 		})
 	}
 }
diff --git a/lib/promscrape/discovery/openstack/openstack.go b/lib/promscrape/discovery/openstack/openstack.go
index 788bcb2d2a..df26b92b1c 100644
--- a/lib/promscrape/discovery/openstack/openstack.go
+++ b/lib/promscrape/discovery/openstack/openstack.go
@@ -6,6 +6,7 @@ import (
 	"time"
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promauth"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 // SDCheckInterval defines interval for targets refresh.
@@ -39,7 +40,7 @@ type SDConfig struct {
 }
 
 // GetLabels returns OpenStack labels according to sdc.
-func (sdc *SDConfig) GetLabels(baseDir string) ([]map[string]string, error) {
+func (sdc *SDConfig) GetLabels(baseDir string) ([]*promutils.Labels, error) {
 	cfg, err := getAPIConfig(sdc, baseDir)
 	if err != nil {
 		return nil, fmt.Errorf("cannot get API config: %w", err)
diff --git a/lib/promscrape/discovery/yandexcloud/instance.go b/lib/promscrape/discovery/yandexcloud/instance.go
index f780365960..7a0997e0d5 100644
--- a/lib/promscrape/discovery/yandexcloud/instance.go
+++ b/lib/promscrape/discovery/yandexcloud/instance.go
@@ -5,9 +5,10 @@ import (
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
-func getInstancesLabels(cfg *apiConfig) ([]map[string]string, error) {
+func getInstancesLabels(cfg *apiConfig) ([]*promutils.Labels, error) {
 	organizations, err := cfg.getOrganizations()
 	if err != nil {
 		return nil, err
@@ -35,46 +36,40 @@ func getInstancesLabels(cfg *apiConfig) ([]map[string]string, error) {
 	return addInstanceLabels(instances), nil
 }
 
-func addInstanceLabels(instances []instance) []map[string]string {
-	var ms []map[string]string
+func addInstanceLabels(instances []instance) []*promutils.Labels {
+	var ms []*promutils.Labels
 	for _, server := range instances {
-		m := map[string]string{
-			"__address__":                                         server.FQDN,
-			"__meta_yandexcloud_instance_name":                    server.Name,
-			"__meta_yandexcloud_instance_fqdn":                    server.FQDN,
-			"__meta_yandexcloud_instance_id":                      server.ID,
-			"__meta_yandexcloud_instance_status":                  server.Status,
-			"__meta_yandexcloud_instance_platform_id":             server.PlatformID,
-			"__meta_yandexcloud_instance_resources_cores":         server.Resources.Cores,
-			"__meta_yandexcloud_instance_resources_core_fraction": server.Resources.CoreFraction,
-			"__meta_yandexcloud_instance_resources_memory":        server.Resources.Memory,
-			"__meta_yandexcloud_folder_id":                        server.FolderID,
-		}
+		m := promutils.NewLabels(24)
+		m.Add("__address__", server.FQDN)
+		m.Add("__meta_yandexcloud_instance_name", server.Name)
+		m.Add("__meta_yandexcloud_instance_fqdn", server.FQDN)
+		m.Add("__meta_yandexcloud_instance_id", server.ID)
+		m.Add("__meta_yandexcloud_instance_status", server.Status)
+		m.Add("__meta_yandexcloud_instance_platform_id", server.PlatformID)
+		m.Add("__meta_yandexcloud_instance_resources_cores", server.Resources.Cores)
+		m.Add("__meta_yandexcloud_instance_resources_core_fraction", server.Resources.CoreFraction)
+		m.Add("__meta_yandexcloud_instance_resources_memory", server.Resources.Memory)
+		m.Add("__meta_yandexcloud_folder_id", server.FolderID)
 		for k, v := range server.Labels {
-			m[discoveryutils.SanitizeLabelName("__meta_yandexcloud_instance_label_"+k)] = v
+			m.Add(discoveryutils.SanitizeLabelName("__meta_yandexcloud_instance_label_"+k), v)
 		}
-
 		for _, ni := range server.NetworkInterfaces {
 			privateIPLabel := fmt.Sprintf("__meta_yandexcloud_instance_private_ip_%s", ni.Index)
-			m[privateIPLabel] = ni.PrimaryV4Address.Address
+			m.Add(privateIPLabel, ni.PrimaryV4Address.Address)
 			if len(ni.PrimaryV4Address.OneToOneNat.Address) > 0 {
 				publicIPLabel := fmt.Sprintf("__meta_yandexcloud_instance_public_ip_%s", ni.Index)
-				m[publicIPLabel] = ni.PrimaryV4Address.OneToOneNat.Address
+				m.Add(publicIPLabel, ni.PrimaryV4Address.OneToOneNat.Address)
 			}
-
 			for j, dnsRecord := range ni.PrimaryV4Address.DNSRecords {
 				dnsRecordLabel := fmt.Sprintf("__meta_yandexcloud_instance_private_dns_%d", j)
-				m[dnsRecordLabel] = dnsRecord.FQDN
+				m.Add(dnsRecordLabel, dnsRecord.FQDN)
 			}
-
 			for j, dnsRecord := range ni.PrimaryV4Address.OneToOneNat.DNSRecords {
 				dnsRecordLabel := fmt.Sprintf("__meta_yandexcloud_instance_public_dns_%d", j)
-				m[dnsRecordLabel] = dnsRecord.FQDN
+				m.Add(dnsRecordLabel, dnsRecord.FQDN)
 			}
 		}
-
 		ms = append(ms, m)
 	}
-
 	return ms
 }
diff --git a/lib/promscrape/discovery/yandexcloud/instance_test.go b/lib/promscrape/discovery/yandexcloud/instance_test.go
index c0468ddc21..d9161cfc9e 100644
--- a/lib/promscrape/discovery/yandexcloud/instance_test.go
+++ b/lib/promscrape/discovery/yandexcloud/instance_test.go
@@ -1,11 +1,10 @@
 package yandexcloud
 
 import (
-	"reflect"
 	"testing"
 
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 func Test_addInstanceLabels(t *testing.T) {
@@ -15,7 +14,7 @@ func Test_addInstanceLabels(t *testing.T) {
 	tests := []struct {
 		name string
 		args args
-		want [][]prompbmarshal.Label
+		want []*promutils.Labels
 	}{
 		{
 			name: "empty_response",
@@ -48,8 +47,8 @@ func Test_addInstanceLabels(t *testing.T) {
 					},
 				},
 			},
-			want: [][]prompbmarshal.Label{
-				discoveryutils.GetSortedLabels(map[string]string{
+			want: []*promutils.Labels{
+				promutils.NewLabelsFromMap(map[string]string{
 					"__address__":                                         "server-1.ru-central1.internal",
 					"__meta_yandexcloud_instance_name":                    "server-1",
 					"__meta_yandexcloud_instance_fqdn":                    "server-1.ru-central1.internal",
@@ -94,8 +93,8 @@ func Test_addInstanceLabels(t *testing.T) {
 					},
 				},
 			},
-			want: [][]prompbmarshal.Label{
-				discoveryutils.GetSortedLabels(map[string]string{
+			want: []*promutils.Labels{
+				promutils.NewLabelsFromMap(map[string]string{
 					"__address__":                                         "server-1.ru-central1.internal",
 					"__meta_yandexcloud_instance_fqdn":                    "server-1.ru-central1.internal",
 					"__meta_yandexcloud_instance_name":                    "server-1",
@@ -147,8 +146,8 @@ func Test_addInstanceLabels(t *testing.T) {
 					},
 				},
 			},
-			want: [][]prompbmarshal.Label{
-				discoveryutils.GetSortedLabels(map[string]string{
+			want: []*promutils.Labels{
+				promutils.NewLabelsFromMap(map[string]string{
 					"__address__":                                         "server-1.ru-central1.internal",
 					"__meta_yandexcloud_instance_name":                    "server-1",
 					"__meta_yandexcloud_instance_fqdn":                    "server-1.ru-central1.internal",
@@ -170,13 +169,7 @@ func Test_addInstanceLabels(t *testing.T) {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			got := addInstanceLabels(tt.args.instances)
-			var sortedLabelss [][]prompbmarshal.Label
-			for _, labels := range got {
-				sortedLabelss = append(sortedLabelss, discoveryutils.GetSortedLabels(labels))
-			}
-			if !reflect.DeepEqual(sortedLabelss, tt.want) {
-				t.Errorf("addInstanceLabels() = \n got: %v,\nwant: %v", sortedLabelss, tt.want)
-			}
+			discoveryutils.TestEqualLabelss(t, got, tt.want)
 		})
 	}
 }
diff --git a/lib/promscrape/discovery/yandexcloud/yandexcloud.go b/lib/promscrape/discovery/yandexcloud/yandexcloud.go
index 6a9fcba112..baf659bfc7 100644
--- a/lib/promscrape/discovery/yandexcloud/yandexcloud.go
+++ b/lib/promscrape/discovery/yandexcloud/yandexcloud.go
@@ -8,6 +8,7 @@ import (
 	"time"
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promauth"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 // SDCheckInterval defines interval for targets refresh.
@@ -24,7 +25,7 @@ type SDConfig struct {
 }
 
 // GetLabels returns labels for Yandex Cloud according to service discover config.
-func (sdc *SDConfig) GetLabels(baseDir string) ([]map[string]string, error) {
+func (sdc *SDConfig) GetLabels(baseDir string) ([]*promutils.Labels, error) {
 	cfg, err := getAPIConfig(sdc, baseDir)
 	if err != nil {
 		return nil, fmt.Errorf("cannot get API config: %w", err)
diff --git a/lib/promscrape/discoveryutils/utils.go b/lib/promscrape/discoveryutils/utils.go
index e0dd7fd784..2a50a19710 100644
--- a/lib/promscrape/discoveryutils/utils.go
+++ b/lib/promscrape/discoveryutils/utils.go
@@ -1,14 +1,14 @@
 package discoveryutils
 
 import (
-	"encoding/json"
-	"net"
+	"reflect"
 	"regexp"
-	"sort"
 	"strconv"
+	"strings"
+	"testing"
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil"
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
 // SanitizeLabelName replaces anything that doesn't match
@@ -29,44 +29,37 @@ var invalidLabelCharRE = regexp.MustCompile(`[^a-zA-Z0-9_]`)
 //
 // Host may be dns name, ipv4 or ipv6 address.
 func JoinHostPort(host string, port int) string {
-	portStr := strconv.Itoa(port)
-	return net.JoinHostPort(host, portStr)
-}
-
-// SortedLabels represents sorted labels.
-type SortedLabels []prompbmarshal.Label
-
-// GetByName returns the label with the given name from sls.
-func (sls *SortedLabels) GetByName(name string) string {
-	for _, lb := range *sls {
-		if lb.Name == name {
-			return lb.Value
-		}
+	bb := bbPool.Get()
+	b := bb.B[:0]
+	isIPv6 := strings.IndexByte(host, ':') >= 0
+	if isIPv6 {
+		b = append(b, '[')
 	}
-	return ""
+	b = append(b, host...)
+	if isIPv6 {
+		b = append(b, ']')
+	}
+	b = append(b, ':')
+	b = strconv.AppendInt(b, int64(port), 10)
+	s := bytesutil.ToUnsafeString(b)
+	s = bytesutil.InternString(s)
+	bb.B = b
+	bbPool.Put(bb)
+	return s
 }
 
-// UnmarshalJSON unmarshals JSON from data.
-func (sls *SortedLabels) UnmarshalJSON(data []byte) error {
-	var m map[string]string
-	if err := json.Unmarshal(data, &m); err != nil {
-		return err
-	}
-	*sls = GetSortedLabels(m)
-	return nil
-}
+var bbPool bytesutil.ByteBufferPool
 
-// GetSortedLabels returns SortedLabels built from m.
-func GetSortedLabels(m map[string]string) SortedLabels {
-	a := make([]prompbmarshal.Label, 0, len(m))
-	for k, v := range m {
-		a = append(a, prompbmarshal.Label{
-			Name:  k,
-			Value: v,
-		})
+// TestEqualLabelss tests whether got are equal to want.
+func TestEqualLabelss(t *testing.T, got, want []*promutils.Labels) {
+	t.Helper()
+	var gotCopy []*promutils.Labels
+	for _, labels := range got {
+		labels = labels.Clone()
+		labels.Sort()
+		gotCopy = append(gotCopy, labels)
+	}
+	if !reflect.DeepEqual(gotCopy, want) {
+		t.Fatalf("unexpected labels:\ngot\n%v\nwant\n%v", gotCopy, want)
 	}
-	sort.Slice(a, func(i, j int) bool {
-		return a[i].Name < a[j].Name
-	})
-	return a
 }
diff --git a/lib/promscrape/discoveryutils/utils_test.go b/lib/promscrape/discoveryutils/utils_test.go
index 21bf3100a8..b63817b180 100644
--- a/lib/promscrape/discoveryutils/utils_test.go
+++ b/lib/promscrape/discoveryutils/utils_test.go
@@ -6,6 +6,20 @@ import (
 	"time"
 )
 
+func TestJoinHostPort(t *testing.T) {
+	f := func(host string, port int, resultExpected string) {
+		t.Helper()
+		for i := 0; i < 5; i++ {
+			result := JoinHostPort(host, port)
+			if result != resultExpected {
+				t.Fatalf("unexpected result for JoinHostPort(%q, %d); got %q; want %q", host, port, result, resultExpected)
+			}
+		}
+	}
+	f("foo", 123, "foo:123")
+	f("1:32::43", 80, "[1:32::43]:80")
+}
+
 func TestSanitizeLabelNameSerial(t *testing.T) {
 	if err := testSanitizeLabelName(); err != nil {
 		t.Fatalf("unexpected error: %s", err)
diff --git a/lib/promscrape/scraper.go b/lib/promscrape/scraper.go
index 470a387bd5..a6b59070b9 100644
--- a/lib/promscrape/scraper.go
+++ b/lib/promscrape/scraper.go
@@ -27,6 +27,7 @@ import (
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discovery/kubernetes"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discovery/openstack"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discovery/yandexcloud"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 	"github.com/VictoriaMetrics/metrics"
 )
 
@@ -351,7 +352,7 @@ func (sg *scraperGroup) update(sws []*ScrapeWork) {
 
 	additionsCount := 0
 	deletionsCount := 0
-	swsMap := make(map[string][]prompbmarshal.Label, len(sws))
+	swsMap := make(map[string]*promutils.Labels, len(sws))
 	var swsToStart []*ScrapeWork
 	for _, sw := range sws {
 		key := sw.key()
@@ -362,7 +363,7 @@ func (sg *scraperGroup) update(sws []*ScrapeWork) {
 					"make sure service discovery and relabeling is set up properly; "+
 					"see also https://docs.victoriametrics.com/vmagent.html#troubleshooting; "+
 					"original labels for target1: %s; original labels for target2: %s",
-					sw.ScrapeURL, sw.LabelsString(), promLabelsString(originalLabels), promLabelsString(sw.OriginalLabels))
+					sw.ScrapeURL, sw.LabelsString(), originalLabels.String(), sw.OriginalLabels.String())
 			}
 			droppedTargetsMap.Register(sw.OriginalLabels)
 			continue
diff --git a/lib/promscrape/scrapework.go b/lib/promscrape/scrapework.go
index 97c6f460a4..31332cd9a5 100644
--- a/lib/promscrape/scrapework.go
+++ b/lib/promscrape/scrapework.go
@@ -7,7 +7,6 @@ import (
 	"io"
 	"math"
 	"math/bits"
-	"strconv"
 	"strings"
 	"sync"
 	"time"
@@ -23,6 +22,7 @@ import (
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promauth"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promrelabel"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 	parser "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/prometheus"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/proxy"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/timerpool"
@@ -69,7 +69,7 @@ type ScrapeWork struct {
 	// These labels are needed for relabeling troubleshooting at /targets page.
 	//
 	// OriginalLabels are sorted by name.
-	OriginalLabels []prompbmarshal.Label
+	OriginalLabels *promutils.Labels
 
 	// Labels to add to the scraped metrics.
 	//
@@ -82,7 +82,7 @@ type ScrapeWork struct {
 	// See also https://prometheus.io/docs/concepts/jobs_instances/
 	//
 	// Labels are sorted by name.
-	Labels []prompbmarshal.Label
+	Labels *promutils.Labels
 
 	// ExternalLabels contains labels from global->external_labels section of -promscrape.config
 	//
@@ -90,7 +90,7 @@ type ScrapeWork struct {
 	// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3137
 	//
 	// ExternalLabels are sorted by name.
-	ExternalLabels []prompbmarshal.Label
+	ExternalLabels *promutils.Labels
 
 	// ProxyURL HTTP proxy url
 	ProxyURL *proxy.URL
@@ -153,7 +153,7 @@ func (sw *ScrapeWork) key() string {
 		"ProxyURL=%s, ProxyAuthConfig=%s, AuthConfig=%s, MetricRelabelConfigs=%s, SampleLimit=%d, DisableCompression=%v, DisableKeepAlive=%v, StreamParse=%v, "+
 		"ScrapeAlignInterval=%s, ScrapeOffset=%s, SeriesLimit=%d, NoStaleMarkers=%v",
 		sw.jobNameOriginal, sw.ScrapeURL, sw.ScrapeInterval, sw.ScrapeTimeout, sw.HonorLabels, sw.HonorTimestamps, sw.DenyRedirects, sw.LabelsString(),
-		promLabelsString(sw.ExternalLabels),
+		sw.ExternalLabels.String(),
 		sw.ProxyURL.String(), sw.ProxyAuthConfig.String(),
 		sw.AuthConfig.String(), sw.MetricRelabelConfigs.String(), sw.SampleLimit, sw.DisableCompression, sw.DisableKeepAlive, sw.StreamParse,
 		sw.ScrapeAlignInterval, sw.ScrapeOffset, sw.SeriesLimit, sw.NoStaleMarkers)
@@ -162,33 +162,12 @@ func (sw *ScrapeWork) key() string {
 
 // Job returns job for the ScrapeWork
 func (sw *ScrapeWork) Job() string {
-	return promrelabel.GetLabelValueByName(sw.Labels, "job")
+	return sw.Labels.Get("job")
 }
 
 // LabelsString returns labels in Prometheus format for the given sw.
 func (sw *ScrapeWork) LabelsString() string {
-	return promLabelsString(sw.Labels)
-}
-
-func promLabelsString(labels []prompbmarshal.Label) string {
-	// Calculate the required memory for storing serialized labels.
-	n := 2 // for `{...}`
-	for _, label := range labels {
-		n += len(label.Name) + len(label.Value)
-		n += 4 // for `="...",`
-	}
-	b := make([]byte, 0, n)
-	b = append(b, '{')
-	for i, label := range labels {
-		b = append(b, label.Name...)
-		b = append(b, '=')
-		b = strconv.AppendQuote(b, label.Value)
-		if i+1 < len(labels) {
-			b = append(b, ',')
-		}
-	}
-	b = append(b, '}')
-	return bytesutil.ToUnsafeString(b)
+	return sw.Labels.String()
 }
 
 type scrapeWork struct {
@@ -863,7 +842,8 @@ func (sw *scrapeWork) addRowToTimeseries(wc *writeRequestCtx, r *parser.Row, tim
 		bbPool.Put(bb)
 	}
 	labelsLen := len(wc.labels)
-	wc.labels = appendLabels(wc.labels, metric, r.Tags, sw.Config.Labels, sw.Config.HonorLabels)
+	targetLabels := sw.Config.Labels.GetLabels()
+	wc.labels = appendLabels(wc.labels, metric, r.Tags, targetLabels, sw.Config.HonorLabels)
 	if needRelabel {
 		wc.labels = sw.Config.MetricRelabelConfigs.Apply(wc.labels, labelsLen)
 	}
@@ -874,7 +854,8 @@ func (sw *scrapeWork) addRowToTimeseries(wc *writeRequestCtx, r *parser.Row, tim
 	}
 	// Add labels from `global->external_labels` section after the relabeling like Prometheus does.
 	// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3137
-	wc.labels = appendExtraLabels(wc.labels, sw.Config.ExternalLabels, labelsLen, sw.Config.HonorLabels)
+	externalLabels := sw.Config.ExternalLabels.GetLabels()
+	wc.labels = appendExtraLabels(wc.labels, externalLabels, labelsLen, sw.Config.HonorLabels)
 	sampleTimestamp := r.Timestamp
 	if !sw.Config.HonorTimestamps || sampleTimestamp == 0 {
 		sampleTimestamp = timestamp
diff --git a/lib/promscrape/scrapework_test.go b/lib/promscrape/scrapework_test.go
index f068044652..20ab892f4b 100644
--- a/lib/promscrape/scrapework_test.go
+++ b/lib/promscrape/scrapework_test.go
@@ -9,6 +9,7 @@ import (
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/auth"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promrelabel"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 	parser "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/prometheus"
 )
 
@@ -39,10 +40,11 @@ func TestIsAutoMetric(t *testing.T) {
 func TestAppendExtraLabels(t *testing.T) {
 	f := func(sourceLabels, extraLabels string, honorLabels bool, resultExpected string) {
 		t.Helper()
-		src := promrelabel.MustParseMetricWithLabels(sourceLabels)
-		extra := promrelabel.MustParseMetricWithLabels(extraLabels)
-		labels := appendExtraLabels(src, extra, 0, honorLabels)
-		result := promLabelsString(labels)
+		src := promutils.NewLabelsFromString(sourceLabels)
+		extra := promutils.NewLabelsFromString(extraLabels)
+		var labels promutils.Labels
+		labels.Labels = appendExtraLabels(src.GetLabels(), extra.GetLabels(), 0, honorLabels)
+		result := labels.String()
 		if result != resultExpected {
 			t.Fatalf("unexpected result; got\n%s\nwant\n%s", result, resultExpected)
 		}
@@ -69,33 +71,6 @@ func TestAppendExtraLabels(t *testing.T) {
 	f(`{foo="a",exported_foo="b"}`, `{exported_foo="c",foo="d"}`, false, `{exported_foo="a",exported_exported_foo="b",exported_foo="c",foo="d"}`)
 }
 
-func TestPromLabelsString(t *testing.T) {
-	f := func(labels []prompbmarshal.Label, resultExpected string) {
-		t.Helper()
-		result := promLabelsString(labels)
-		if result != resultExpected {
-			t.Fatalf("unexpected result; got\n%s\nwant\n%s", result, resultExpected)
-		}
-	}
-	f([]prompbmarshal.Label{}, "{}")
-	f([]prompbmarshal.Label{
-		{
-			Name:  "foo",
-			Value: "bar",
-		},
-	}, `{foo="bar"}`)
-	f([]prompbmarshal.Label{
-		{
-			Name:  "foo",
-			Value: "bar",
-		},
-		{
-			Name:  "a",
-			Value: `"b"`,
-		},
-	}, `{foo="bar",a="\"b\""}`)
-}
-
 func TestScrapeWorkScrapeInternalFailure(t *testing.T) {
 	dataExpected := `
 		up 0 123
@@ -226,12 +201,9 @@ func TestScrapeWorkScrapeInternalSuccess(t *testing.T) {
 	`, &ScrapeWork{
 		ScrapeTimeout:   time.Second * 42,
 		HonorTimestamps: true,
-		Labels: []prompbmarshal.Label{
-			{
-				Name:  "foo",
-				Value: "x",
-			},
-		},
+		Labels: promutils.NewLabelsFromMap(map[string]string{
+			"foo": "x",
+		}),
 	}, `
 		foo{bar="baz",foo="x"} 34.45 3
 		abc{foo="x"} -2 123
@@ -248,12 +220,9 @@ func TestScrapeWorkScrapeInternalSuccess(t *testing.T) {
 	`, &ScrapeWork{
 		ScrapeTimeout: time.Second * 42,
 		HonorLabels:   false,
-		Labels: []prompbmarshal.Label{
-			{
-				Name:  "job",
-				Value: "override",
-			},
-		},
+		Labels: promutils.NewLabelsFromMap(map[string]string{
+			"job": "override",
+		}),
 	}, `
 		foo{exported_job="orig",job="override",bar="baz"} 34.45 123
 		bar{exported_job="aa",job="override",x="1",a="b",y="2"} -3e4 123
@@ -271,16 +240,10 @@ func TestScrapeWorkScrapeInternalSuccess(t *testing.T) {
 	`, &ScrapeWork{
 		ScrapeTimeout: time.Second * 42,
 		HonorLabels:   true,
-		Labels: []prompbmarshal.Label{
-			{
-				Name:  "instance",
-				Value: "foobar",
-			},
-			{
-				Name:  "job",
-				Value: "xxx",
-			},
-		},
+		Labels: promutils.NewLabelsFromMap(map[string]string{
+			"instance": "foobar",
+			"job":      "xxx",
+		}),
 	}, `
 		no_instance{job="some_job",label="val1"} 5555 123
 		test_with_instance{instance="some_instance",job="some_job",label="val2"} 1555 123
@@ -297,16 +260,10 @@ func TestScrapeWorkScrapeInternalSuccess(t *testing.T) {
 	`, &ScrapeWork{
 		ScrapeTimeout: time.Second * 42,
 		HonorLabels:   false,
-		Labels: []prompbmarshal.Label{
-			{
-				Name:  "instance",
-				Value: "foobar",
-			},
-			{
-				Name:  "job",
-				Value: "xxx",
-			},
-		},
+		Labels: promutils.NewLabelsFromMap(map[string]string{
+			"instance": "foobar",
+			"job":      "xxx",
+		}),
 	}, `
 		no_instance{exported_job="some_job",instance="foobar",job="xxx",label="val1"} 5555 123
 		test_with_instance{exported_instance="some_instance",exported_job="some_job",instance="foobar",job="xxx",label="val2"} 1555 123
@@ -323,12 +280,9 @@ func TestScrapeWorkScrapeInternalSuccess(t *testing.T) {
 	`, &ScrapeWork{
 		ScrapeTimeout: time.Second * 42,
 		HonorLabels:   true,
-		Labels: []prompbmarshal.Label{
-			{
-				Name:  "job",
-				Value: "override",
-			},
-		},
+		Labels: promutils.NewLabelsFromMap(map[string]string{
+			"job": "override",
+		}),
 	}, `
 		foo{job="orig",bar="baz"} 34.45 123
 		bar{job="aa",a="b"} -3e4 123
@@ -345,16 +299,10 @@ func TestScrapeWorkScrapeInternalSuccess(t *testing.T) {
 	`, &ScrapeWork{
 		ScrapeTimeout: time.Second * 42,
 		HonorLabels:   true,
-		Labels: []prompbmarshal.Label{
-			{
-				Name:  "job",
-				Value: "xx",
-			},
-			{
-				Name:  "__address__",
-				Value: "foo.com",
-			},
-		},
+		Labels: promutils.NewLabelsFromMap(map[string]string{
+			"job":         "xx",
+			"__address__": "foo.com",
+		}),
 		MetricRelabelConfigs: mustParseRelabelConfigs(`
 - action: replace
   source_labels: ["__address__", "job"]
@@ -381,16 +329,10 @@ func TestScrapeWorkScrapeInternalSuccess(t *testing.T) {
 	`, &ScrapeWork{
 		ScrapeTimeout: time.Second * 42,
 		HonorLabels:   true,
-		Labels: []prompbmarshal.Label{
-			{
-				Name:  "job",
-				Value: "xx",
-			},
-			{
-				Name:  "instance",
-				Value: "foo.com",
-			},
-		},
+		Labels: promutils.NewLabelsFromMap(map[string]string{
+			"job":      "xx",
+			"instance": "foo.com",
+		}),
 		MetricRelabelConfigs: mustParseRelabelConfigs(`
 - action: drop
   separator: ""
@@ -527,322 +469,218 @@ func TestAddRowToTimeseriesNoRelabeling(t *testing.T) {
 	// HonorLabels=false, empty Labels and ExternalLabels
 	f(`metric 0 123`,
 		&ScrapeWork{
-			Labels:         []prompbmarshal.Label{},
-			ExternalLabels: []prompbmarshal.Label{},
-			HonorLabels:    false,
+			HonorLabels: false,
 		},
 		`metric 0 123`)
 	f(`metric{a="f"} 0 123`,
 		&ScrapeWork{
-			Labels:         []prompbmarshal.Label{},
-			ExternalLabels: []prompbmarshal.Label{},
-			HonorLabels:    false,
+			HonorLabels: false,
 		},
 		`metric{a="f"} 0 123`)
 	// HonorLabels=true, empty Labels and ExternalLabels
 	f(`metric 0 123`,
 		&ScrapeWork{
-			Labels:         []prompbmarshal.Label{},
-			ExternalLabels: []prompbmarshal.Label{},
-			HonorLabels:    true,
+			HonorLabels: true,
 		},
 		`metric 0 123`)
 	f(`metric{a="f"} 0 123`,
 		&ScrapeWork{
-			Labels:         []prompbmarshal.Label{},
-			ExternalLabels: []prompbmarshal.Label{},
-			HonorLabels:    true,
+			HonorLabels: true,
 		},
 		`metric{a="f"} 0 123`)
 	// HonorLabels=false, non-empty Labels
 	f(`metric 0 123`,
 		&ScrapeWork{
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "a",
-					Value: "f",
-				},
-			},
-			ExternalLabels: []prompbmarshal.Label{},
-			HonorLabels:    false,
-		},
-		`metric{a="f"} 0 123`)
-	f(`metric{foo="bar"} 0 123`,
-		&ScrapeWork{
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "a",
-					Value: "f",
-				},
-			},
-			ExternalLabels: []prompbmarshal.Label{},
-			HonorLabels:    false,
-		},
-		`metric{a="f",foo="bar"} 0 123`)
-	// HonorLabels=true, non-empty Labels
-	f(`metric 0 123`,
-		&ScrapeWork{
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "a",
-					Value: "f",
-				},
-			},
-			ExternalLabels: []prompbmarshal.Label{},
-			HonorLabels:    true,
-		},
-		`metric{a="f"} 0 123`)
-	f(`metric{foo="bar"} 0 123`,
-		&ScrapeWork{
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "a",
-					Value: "f",
-				},
-			},
-			ExternalLabels: []prompbmarshal.Label{},
-			HonorLabels:    true,
-		},
-		`metric{a="f",foo="bar"} 0 123`)
-	// HonorLabels=false, non-empty ExternalLabels
-	f(`metric 0 123`,
-		&ScrapeWork{
-			Labels: []prompbmarshal.Label{},
-			ExternalLabels: []prompbmarshal.Label{
-				{
-					Name:  "a",
-					Value: "f",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"a": "f",
+			}),
 			HonorLabels: false,
 		},
 		`metric{a="f"} 0 123`)
 	f(`metric{foo="bar"} 0 123`,
 		&ScrapeWork{
-			Labels: []prompbmarshal.Label{},
-			ExternalLabels: []prompbmarshal.Label{
-				{
-					Name:  "a",
-					Value: "f",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"a": "f",
+			}),
+			HonorLabels: false,
+		},
+		`metric{a="f",foo="bar"} 0 123`)
+	// HonorLabels=true, non-empty Labels
+	f(`metric 0 123`,
+		&ScrapeWork{
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"a": "f",
+			}),
+			HonorLabels: true,
+		},
+		`metric{a="f"} 0 123`)
+	f(`metric{foo="bar"} 0 123`,
+		&ScrapeWork{
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"a": "f",
+			}),
+			HonorLabels: true,
+		},
+		`metric{a="f",foo="bar"} 0 123`)
+	// HonorLabels=false, non-empty ExternalLabels
+	f(`metric 0 123`,
+		&ScrapeWork{
+			ExternalLabels: promutils.NewLabelsFromMap(map[string]string{
+				"a": "f",
+			}),
+			HonorLabels: false,
+		},
+		`metric{a="f"} 0 123`)
+	f(`metric{foo="bar"} 0 123`,
+		&ScrapeWork{
+			ExternalLabels: promutils.NewLabelsFromMap(map[string]string{
+				"a": "f",
+			}),
 			HonorLabels: false,
 		},
 		`metric{a="f",foo="bar"} 0 123`)
 	// HonorLabels=true, non-empty ExternalLabels
 	f(`metric 0 123`,
 		&ScrapeWork{
-			Labels: []prompbmarshal.Label{},
-			ExternalLabels: []prompbmarshal.Label{
-				{
-					Name:  "a",
-					Value: "f",
-				},
-			},
+			ExternalLabels: promutils.NewLabelsFromMap(map[string]string{
+				"a": "f",
+			}),
 			HonorLabels: true,
 		},
 		`metric{a="f"} 0 123`)
 	f(`metric{foo="bar"} 0 123`,
 		&ScrapeWork{
-			Labels: []prompbmarshal.Label{},
-			ExternalLabels: []prompbmarshal.Label{
-				{
-					Name:  "a",
-					Value: "f",
-				},
-			},
+			ExternalLabels: promutils.NewLabelsFromMap(map[string]string{
+				"a": "f",
+			}),
 			HonorLabels: true,
 		},
 		`metric{a="f",foo="bar"} 0 123`)
 	// HonorLabels=false, non-empty Labels and ExternalLabels
 	f(`metric 0 123`,
 		&ScrapeWork{
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "x",
-					Value: "y",
-				},
-			},
-			ExternalLabels: []prompbmarshal.Label{
-				{
-					Name:  "a",
-					Value: "f",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"x": "y",
+			}),
+			ExternalLabels: promutils.NewLabelsFromMap(map[string]string{
+				"a": "f",
+			}),
 			HonorLabels: false,
 		},
 		`metric{a="f",x="y"} 0 123`)
 	f(`metric{foo="bar"} 0 123`,
 		&ScrapeWork{
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "x",
-					Value: "y",
-				},
-			},
-			ExternalLabels: []prompbmarshal.Label{
-				{
-					Name:  "a",
-					Value: "f",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"x": "y",
+			}),
+			ExternalLabels: promutils.NewLabelsFromMap(map[string]string{
+				"a": "f",
+			}),
 			HonorLabels: false,
 		},
 		`metric{a="f",foo="bar",x="y"} 0 123`)
 	// HonorLabels=true, non-empty Labels and ExternalLabels
 	f(`metric 0 123`,
 		&ScrapeWork{
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "x",
-					Value: "y",
-				},
-			},
-			ExternalLabels: []prompbmarshal.Label{
-				{
-					Name:  "a",
-					Value: "f",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"x": "y",
+			}),
+			ExternalLabels: promutils.NewLabelsFromMap(map[string]string{
+				"a": "f",
+			}),
 			HonorLabels: true,
 		},
 		`metric{a="f",x="y"} 0 123`)
 	f(`metric{foo="bar"} 0 123`,
 		&ScrapeWork{
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "x",
-					Value: "y",
-				},
-			},
-			ExternalLabels: []prompbmarshal.Label{
-				{
-					Name:  "a",
-					Value: "f",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"x": "y",
+			}),
+			ExternalLabels: promutils.NewLabelsFromMap(map[string]string{
+				"a": "f",
+			}),
 			HonorLabels: true,
 		},
 		`metric{a="f",foo="bar",x="y"} 0 123`)
 	// HonorLabels=false, clashing Labels and metric label
 	f(`metric{a="b"} 0 123`,
 		&ScrapeWork{
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "a",
-					Value: "f",
-				},
-			},
-			ExternalLabels: []prompbmarshal.Label{},
-			HonorLabels:    false,
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"a": "f",
+			}),
+			HonorLabels: false,
 		},
 		`metric{a="f",exported_a="b"} 0 123`)
 	// HonorLabels=true, clashing Labels and metric label
 	f(`metric{a="b"} 0 123`,
 		&ScrapeWork{
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "a",
-					Value: "f",
-				},
-			},
-			ExternalLabels: []prompbmarshal.Label{},
-			HonorLabels:    true,
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"a": "f",
+			}),
+			HonorLabels: true,
 		},
 		`metric{a="b"} 0 123`)
 	// HonorLabels=false, clashing ExternalLabels and metric label
 	f(`metric{a="b"} 0 123`,
 		&ScrapeWork{
-			Labels: []prompbmarshal.Label{},
-			ExternalLabels: []prompbmarshal.Label{
-				{
-					Name:  "a",
-					Value: "f",
-				},
-			},
+			ExternalLabels: promutils.NewLabelsFromMap(map[string]string{
+				"a": "f",
+			}),
 			HonorLabels: false,
 		},
 		`metric{a="f",exported_a="b"} 0 123`)
 	// HonorLabels=true, clashing ExternalLabels and metric label
 	f(`metric{a="b"} 0 123`,
 		&ScrapeWork{
-			Labels: []prompbmarshal.Label{},
-			ExternalLabels: []prompbmarshal.Label{
-				{
-					Name:  "a",
-					Value: "f",
-				},
-			},
+			ExternalLabels: promutils.NewLabelsFromMap(map[string]string{
+				"a": "f",
+			}),
 			HonorLabels: true,
 		},
 		`metric{a="b"} 0 123`)
 	// HonorLabels=false, clashing Labels and ExternalLAbels
 	f(`metric 0 123`,
 		&ScrapeWork{
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "a",
-					Value: "e",
-				},
-			},
-			ExternalLabels: []prompbmarshal.Label{
-				{
-					Name:  "a",
-					Value: "f",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"a": "e",
+			}),
+			ExternalLabels: promutils.NewLabelsFromMap(map[string]string{
+				"a": "f",
+			}),
 			HonorLabels: false,
 		},
 		`metric{a="f",exported_a="e"} 0 123`)
 	f(`metric{foo="bar"} 0 123`,
 		&ScrapeWork{
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "a",
-					Value: "e",
-				},
-			},
-			ExternalLabels: []prompbmarshal.Label{
-				{
-					Name:  "a",
-					Value: "f",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"a": "e",
+			}),
+			ExternalLabels: promutils.NewLabelsFromMap(map[string]string{
+				"a": "f",
+			}),
 			HonorLabels: false,
 		},
 		`metric{a="f",foo="bar",exported_a="e"} 0 123`)
 	// HonorLabels=true, clashing Labels and ExternalLAbels
 	f(`metric 0 123`,
 		&ScrapeWork{
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "a",
-					Value: "e",
-				},
-			},
-			ExternalLabels: []prompbmarshal.Label{
-				{
-					Name:  "a",
-					Value: "f",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"a": "e",
+			}),
+			ExternalLabels: promutils.NewLabelsFromMap(map[string]string{
+				"a": "f",
+			}),
 			HonorLabels: true,
 		},
 		`metric{a="e"} 0 123`)
 	f(`metric{foo="bar"} 0 123`,
 		&ScrapeWork{
-			Labels: []prompbmarshal.Label{
-				{
-					Name:  "a",
-					Value: "e",
-				},
-			},
-			ExternalLabels: []prompbmarshal.Label{
-				{
-					Name:  "a",
-					Value: "f",
-				},
-			},
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"a": "e",
+			}),
+			ExternalLabels: promutils.NewLabelsFromMap(map[string]string{
+				"a": "f",
+			}),
 			HonorLabels: true,
 		},
 		`metric{a="e",foo="bar"} 0 123`)
diff --git a/lib/promscrape/targetstatus.go b/lib/promscrape/targetstatus.go
index b16a490539..8e28497e62 100644
--- a/lib/promscrape/targetstatus.go
+++ b/lib/promscrape/targetstatus.go
@@ -14,8 +14,8 @@ import (
 	"unsafe"
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/fasttime"
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promrelabel"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 	"github.com/cespare/xxhash/v2"
 )
 
@@ -181,8 +181,8 @@ func (tsm *targetStatusMap) getActiveTargetStatuses() []targetStatus {
 	tsm.mu.Unlock()
 	// Sort discovered targets by __address__ label, so they stay in consistent order across calls
 	sort.Slice(tss, func(i, j int) bool {
-		addr1 := promrelabel.GetLabelValueByName(tss[i].sw.Config.OriginalLabels, "__address__")
-		addr2 := promrelabel.GetLabelValueByName(tss[j].sw.Config.OriginalLabels, "__address__")
+		addr1 := tss[i].sw.Config.OriginalLabels.Get("__address__")
+		addr2 := tss[j].sw.Config.OriginalLabels.Get("__address__")
 		return addr1 < addr2
 	})
 	return tss
@@ -219,11 +219,12 @@ func (tsm *targetStatusMap) WriteActiveTargetsJSON(w io.Writer) {
 	fmt.Fprintf(w, `]`)
 }
 
-func writeLabelsJSON(w io.Writer, labels []prompbmarshal.Label) {
+func writeLabelsJSON(w io.Writer, labels *promutils.Labels) {
 	fmt.Fprintf(w, `{`)
-	for i, label := range labels {
+	labelsList := labels.GetLabels()
+	for i, label := range labelsList {
 		fmt.Fprintf(w, "%q:%q", label.Name, label.Value)
-		if i+1 < len(labels) {
+		if i+1 < len(labelsList) {
 			fmt.Fprintf(w, `,`)
 		}
 	}
@@ -252,27 +253,27 @@ type droppedTargets struct {
 }
 
 type droppedTarget struct {
-	originalLabels []prompbmarshal.Label
+	originalLabels *promutils.Labels
 	deadline       uint64
 }
 
-func (dt *droppedTargets) getTargetsLabels() [][]prompbmarshal.Label {
+func (dt *droppedTargets) getTargetsLabels() []*promutils.Labels {
 	dt.mu.Lock()
-	dtls := make([][]prompbmarshal.Label, 0, len(dt.m))
+	dtls := make([]*promutils.Labels, 0, len(dt.m))
 	for _, v := range dt.m {
 		dtls = append(dtls, v.originalLabels)
 	}
 	dt.mu.Unlock()
 	// Sort discovered targets by __address__ label, so they stay in consistent order across calls
 	sort.Slice(dtls, func(i, j int) bool {
-		addr1 := promrelabel.GetLabelValueByName(dtls[i], "__address__")
-		addr2 := promrelabel.GetLabelValueByName(dtls[j], "__address__")
+		addr1 := dtls[i].Get("__address__")
+		addr2 := dtls[j].Get("__address__")
 		return addr1 < addr2
 	})
 	return dtls
 }
 
-func (dt *droppedTargets) Register(originalLabels []prompbmarshal.Label) {
+func (dt *droppedTargets) Register(originalLabels *promutils.Labels) {
 	// It is better to have hash collisions instead of spending additional CPU on promLabelsString() call.
 	key := labelsHash(originalLabels)
 	currentTime := fasttime.UnixTimestamp()
@@ -297,9 +298,9 @@ func (dt *droppedTargets) Register(originalLabels []prompbmarshal.Label) {
 	dt.mu.Unlock()
 }
 
-func labelsHash(labels []prompbmarshal.Label) uint64 {
+func labelsHash(labels *promutils.Labels) uint64 {
 	d := xxhashPool.Get().(*xxhash.Digest)
-	for _, label := range labels {
+	for _, label := range labels.Labels {
 		_, _ = d.WriteString(label.Name)
 		_, _ = d.WriteString(label.Value)
 	}
@@ -431,7 +432,8 @@ func filterTargetsByLabels(jts []*jobTargetsStatuses, searchQuery string) ([]*jo
 	for _, job := range jts {
 		var tss []targetStatus
 		for _, ts := range job.targetsStatus {
-			if ie.Match(ts.sw.Config.Labels) {
+			labels := ts.sw.Config.Labels.GetLabels()
+			if ie.Match(labels) {
 				tss = append(tss, ts)
 			}
 		}
@@ -496,15 +498,15 @@ func getRequestFilter(r *http.Request) *requestFilter {
 
 type targetsStatusResult struct {
 	jobTargetsStatuses   []*jobTargetsStatuses
-	droppedTargetsLabels [][]prompbmarshal.Label
+	droppedTargetsLabels []*promutils.Labels
 	emptyJobs            []string
 	err                  error
 }
 
 type targetLabels struct {
 	up               bool
-	discoveredLabels []prompbmarshal.Label
-	labels           []prompbmarshal.Label
+	discoveredLabels *promutils.Labels
+	labels           *promutils.Labels
 }
 type targetLabelsByJob struct {
 	jobName        string
@@ -534,7 +536,7 @@ func (tsr *targetsStatusResult) getTargetLabelsByJob() []*targetLabelsByJob {
 		}
 	}
 	for _, labels := range tsr.droppedTargetsLabels {
-		jobName := promrelabel.GetLabelValueByName(labels, "job")
+		jobName := labels.Get("job")
 		m := byJob[jobName]
 		if m == nil {
 			m = &targetLabelsByJob{
diff --git a/lib/promscrape/targetstatus.qtpl b/lib/promscrape/targetstatus.qtpl
index 5bfaba60e3..53bc8b7672 100644
--- a/lib/promscrape/targetstatus.qtpl
+++ b/lib/promscrape/targetstatus.qtpl
@@ -2,8 +2,7 @@
 	"net/url"
 	"time"
 
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promrelabel"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 ) %}
 
 {% stripspace %}
@@ -22,8 +21,8 @@
 		{%s= "\t" %}
 		state={% if ts.up %}up{% else %}down{% endif %},{% space %}
 		endpoint={%s= ts.sw.Config.ScrapeURL %},{% space %}
-		labels={%s= promLabelsString(promrelabel.FinalizeLabels(nil, ts.sw.Config.Labels)) %},{% space %}
-		{% if filter.showOriginalLabels %}originalLabels={%s= promLabelsString(ts.sw.Config.OriginalLabels) %},{% space %}{% endif %}
+		labels={%s= ts.sw.Config.Labels.String() %},{% space %}
+		{% if filter.showOriginalLabels %}originalLabels={%s= ts.sw.Config.OriginalLabels.String() %},{% space %}{% endif %}
 		scrapes_total={%d ts.scrapesTotal %},{% space %}
 		scrapes_failed={%d ts.scrapesFailed %},{% space %}
 		last_scrape={%d int(ts.getDurationFromLastScrape().Milliseconds()) %}ms ago,{% space %}
@@ -258,10 +257,10 @@
                             <td class="labels">
                                 <div title="click to show original labels"
                                   onclick="document.getElementById('original-labels-{%s targetID %}').style.display='block'">
-                                    {%= formatLabel(promrelabel.FinalizeLabels(nil, ts.sw.Config.Labels)) %}
+                                    {%= formatLabels(ts.sw.Config.Labels) %}
                                 </div>
                                 <div style="display:none" id="original-labels-{%s targetID %}">
-                                    {%= formatLabel(ts.sw.Config.OriginalLabels) %}
+                                    {%= formatLabels(ts.sw.Config.OriginalLabels) %}
                                 </div>
                             </td>
                             <td>{%d ts.scrapesTotal %}</td>
@@ -314,7 +313,7 @@
                 <tr
                     {% if !t.up %}
                         {% space %}role="alert"{% space %}
-                        {% if len(t.labels) > 0 %}
+                        {% if t.labels.Len() > 0 %}
                             class="alert alert-danger"
                         {% else %}
                             class="alert alert-warning"
@@ -324,17 +323,17 @@
                     <td>
                         {% if t.up %}
                             <span class="badge bg-success">UP</span>
-                        {% elseif len(t.labels) > 0 %}
+                        {% elseif t.labels.Len() > 0 %}
                             <span class="badge bg-danger">DOWN</span>
                         {% else %}
                             <span class="badge bg-warning">DROPPED</span>
                         {% endif %}
                     </td>
                     <td class="labels">
-                        {%= formatLabel(t.discoveredLabels) %}
+                        {%= formatLabels(t.discoveredLabels) %}
                     </td>
                     <td class="labels">
-                        {%= formatLabel(promrelabel.FinalizeLabels(nil, t.labels)) %}
+                        {%= formatLabels(t.labels) %}
                     </td>
                 </tr>
             {% endfor %}
@@ -376,11 +375,12 @@
 	{%s qa.Encode() %}
 {% endfunc %}
 
-{% func formatLabel(labels []prompbmarshal.Label) %}
+{% func formatLabels(labels *promutils.Labels) %}
+{% code labelsList := labels.GetLabels() %}
 {
-  {% for i, label := range labels %}
+  {% for i, label := range labelsList %}
       {%s label.Name %}={%q label.Value %}
-      {% if i+1 < len(labels) %},{% space %}{% endif %}
+      {% if i+1 < len(labelsList) %},{% space %}{% endif %}
   {% endfor %}
 }
 {% endfunc %}
diff --git a/lib/promscrape/targetstatus.qtpl.go b/lib/promscrape/targetstatus.qtpl.go
index c2a085da88..a560409cff 100644
--- a/lib/promscrape/targetstatus.qtpl.go
+++ b/lib/promscrape/targetstatus.qtpl.go
@@ -9,961 +9,960 @@ import (
 	"net/url"
 	"time"
 
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
-	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promrelabel"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
 )
 
-//line lib/promscrape/targetstatus.qtpl:11
+//line lib/promscrape/targetstatus.qtpl:10
 import (
 	qtio422016 "io"
 
 	qt422016 "github.com/valyala/quicktemplate"
 )
 
-//line lib/promscrape/targetstatus.qtpl:11
+//line lib/promscrape/targetstatus.qtpl:10
 var (
 	_ = qtio422016.Copy
 	_ = qt422016.AcquireByteBuffer
 )
 
-//line lib/promscrape/targetstatus.qtpl:11
+//line lib/promscrape/targetstatus.qtpl:10
 func StreamTargetsResponsePlain(qw422016 *qt422016.Writer, tsr *targetsStatusResult, filter *requestFilter) {
-//line lib/promscrape/targetstatus.qtpl:13
+//line lib/promscrape/targetstatus.qtpl:12
 	if tsr.err != nil {
-//line lib/promscrape/targetstatus.qtpl:14
+//line lib/promscrape/targetstatus.qtpl:13
 		qw422016.N().S(tsr.err.Error())
-//line lib/promscrape/targetstatus.qtpl:15
+//line lib/promscrape/targetstatus.qtpl:14
 		return
-//line lib/promscrape/targetstatus.qtpl:16
+//line lib/promscrape/targetstatus.qtpl:15
 	}
-//line lib/promscrape/targetstatus.qtpl:18
+//line lib/promscrape/targetstatus.qtpl:17
 	for _, jts := range tsr.jobTargetsStatuses {
-//line lib/promscrape/targetstatus.qtpl:18
+//line lib/promscrape/targetstatus.qtpl:17
 		qw422016.N().S(`job=`)
-//line lib/promscrape/targetstatus.qtpl:19
+//line lib/promscrape/targetstatus.qtpl:18
 		qw422016.N().S(jts.jobName)
-//line lib/promscrape/targetstatus.qtpl:19
+//line lib/promscrape/targetstatus.qtpl:18
 		qw422016.N().S(` `)
-//line lib/promscrape/targetstatus.qtpl:19
+//line lib/promscrape/targetstatus.qtpl:18
 		qw422016.N().S(`(`)
-//line lib/promscrape/targetstatus.qtpl:19
+//line lib/promscrape/targetstatus.qtpl:18
 		qw422016.N().D(jts.upCount)
-//line lib/promscrape/targetstatus.qtpl:19
+//line lib/promscrape/targetstatus.qtpl:18
 		qw422016.N().S(`/`)
-//line lib/promscrape/targetstatus.qtpl:19
+//line lib/promscrape/targetstatus.qtpl:18
 		qw422016.N().D(jts.targetsTotal)
-//line lib/promscrape/targetstatus.qtpl:19
+//line lib/promscrape/targetstatus.qtpl:18
 		qw422016.N().S(` `)
-//line lib/promscrape/targetstatus.qtpl:19
+//line lib/promscrape/targetstatus.qtpl:18
 		qw422016.N().S(`up)`)
-//line lib/promscrape/targetstatus.qtpl:20
+//line lib/promscrape/targetstatus.qtpl:19
 		qw422016.N().S(`
 `)
-//line lib/promscrape/targetstatus.qtpl:21
+//line lib/promscrape/targetstatus.qtpl:20
 		for _, ts := range jts.targetsStatus {
-//line lib/promscrape/targetstatus.qtpl:22
+//line lib/promscrape/targetstatus.qtpl:21
 			qw422016.N().S("\t")
-//line lib/promscrape/targetstatus.qtpl:22
+//line lib/promscrape/targetstatus.qtpl:21
 			qw422016.N().S(`state=`)
-//line lib/promscrape/targetstatus.qtpl:23
+//line lib/promscrape/targetstatus.qtpl:22
 			if ts.up {
-//line lib/promscrape/targetstatus.qtpl:23
+//line lib/promscrape/targetstatus.qtpl:22
 				qw422016.N().S(`up`)
-//line lib/promscrape/targetstatus.qtpl:23
+//line lib/promscrape/targetstatus.qtpl:22
 			} else {
-//line lib/promscrape/targetstatus.qtpl:23
+//line lib/promscrape/targetstatus.qtpl:22
 				qw422016.N().S(`down`)
-//line lib/promscrape/targetstatus.qtpl:23
+//line lib/promscrape/targetstatus.qtpl:22
 			}
-//line lib/promscrape/targetstatus.qtpl:23
+//line lib/promscrape/targetstatus.qtpl:22
 			qw422016.N().S(`,`)
-//line lib/promscrape/targetstatus.qtpl:23
+//line lib/promscrape/targetstatus.qtpl:22
 			qw422016.N().S(` `)
-//line lib/promscrape/targetstatus.qtpl:23
+//line lib/promscrape/targetstatus.qtpl:22
 			qw422016.N().S(`endpoint=`)
-//line lib/promscrape/targetstatus.qtpl:24
+//line lib/promscrape/targetstatus.qtpl:23
 			qw422016.N().S(ts.sw.Config.ScrapeURL)
-//line lib/promscrape/targetstatus.qtpl:24
+//line lib/promscrape/targetstatus.qtpl:23
 			qw422016.N().S(`,`)
-//line lib/promscrape/targetstatus.qtpl:24
+//line lib/promscrape/targetstatus.qtpl:23
 			qw422016.N().S(` `)
-//line lib/promscrape/targetstatus.qtpl:24
+//line lib/promscrape/targetstatus.qtpl:23
 			qw422016.N().S(`labels=`)
-//line lib/promscrape/targetstatus.qtpl:25
-			qw422016.N().S(promLabelsString(promrelabel.FinalizeLabels(nil, ts.sw.Config.Labels)))
-//line lib/promscrape/targetstatus.qtpl:25
+//line lib/promscrape/targetstatus.qtpl:24
+			qw422016.N().S(ts.sw.Config.Labels.String())
+//line lib/promscrape/targetstatus.qtpl:24
 			qw422016.N().S(`,`)
-//line lib/promscrape/targetstatus.qtpl:25
+//line lib/promscrape/targetstatus.qtpl:24
 			qw422016.N().S(` `)
-//line lib/promscrape/targetstatus.qtpl:26
+//line lib/promscrape/targetstatus.qtpl:25
 			if filter.showOriginalLabels {
-//line lib/promscrape/targetstatus.qtpl:26
+//line lib/promscrape/targetstatus.qtpl:25
 				qw422016.N().S(`originalLabels=`)
-//line lib/promscrape/targetstatus.qtpl:26
-				qw422016.N().S(promLabelsString(ts.sw.Config.OriginalLabels))
-//line lib/promscrape/targetstatus.qtpl:26
+//line lib/promscrape/targetstatus.qtpl:25
+				qw422016.N().S(ts.sw.Config.OriginalLabels.String())
+//line lib/promscrape/targetstatus.qtpl:25
 				qw422016.N().S(`,`)
-//line lib/promscrape/targetstatus.qtpl:26
+//line lib/promscrape/targetstatus.qtpl:25
 				qw422016.N().S(` `)
-//line lib/promscrape/targetstatus.qtpl:26
+//line lib/promscrape/targetstatus.qtpl:25
 			}
-//line lib/promscrape/targetstatus.qtpl:26
+//line lib/promscrape/targetstatus.qtpl:25
 			qw422016.N().S(`scrapes_total=`)
-//line lib/promscrape/targetstatus.qtpl:27
+//line lib/promscrape/targetstatus.qtpl:26
 			qw422016.N().D(ts.scrapesTotal)
-//line lib/promscrape/targetstatus.qtpl:27
+//line lib/promscrape/targetstatus.qtpl:26
 			qw422016.N().S(`,`)
-//line lib/promscrape/targetstatus.qtpl:27
+//line lib/promscrape/targetstatus.qtpl:26
 			qw422016.N().S(` `)
-//line lib/promscrape/targetstatus.qtpl:27
+//line lib/promscrape/targetstatus.qtpl:26
 			qw422016.N().S(`scrapes_failed=`)
-//line lib/promscrape/targetstatus.qtpl:28
+//line lib/promscrape/targetstatus.qtpl:27
 			qw422016.N().D(ts.scrapesFailed)
-//line lib/promscrape/targetstatus.qtpl:28
+//line lib/promscrape/targetstatus.qtpl:27
 			qw422016.N().S(`,`)
-//line lib/promscrape/targetstatus.qtpl:28
+//line lib/promscrape/targetstatus.qtpl:27
 			qw422016.N().S(` `)
-//line lib/promscrape/targetstatus.qtpl:28
+//line lib/promscrape/targetstatus.qtpl:27
 			qw422016.N().S(`last_scrape=`)
-//line lib/promscrape/targetstatus.qtpl:29
+//line lib/promscrape/targetstatus.qtpl:28
 			qw422016.N().D(int(ts.getDurationFromLastScrape().Milliseconds()))
-//line lib/promscrape/targetstatus.qtpl:29
+//line lib/promscrape/targetstatus.qtpl:28
 			qw422016.N().S(`ms ago,`)
-//line lib/promscrape/targetstatus.qtpl:29
+//line lib/promscrape/targetstatus.qtpl:28
 			qw422016.N().S(` `)
-//line lib/promscrape/targetstatus.qtpl:29
+//line lib/promscrape/targetstatus.qtpl:28
 			qw422016.N().S(`scrape_duration=`)
-//line lib/promscrape/targetstatus.qtpl:30
+//line lib/promscrape/targetstatus.qtpl:29
 			qw422016.N().D(int(ts.scrapeDuration))
-//line lib/promscrape/targetstatus.qtpl:30
+//line lib/promscrape/targetstatus.qtpl:29
 			qw422016.N().S(`ms,`)
-//line lib/promscrape/targetstatus.qtpl:30
+//line lib/promscrape/targetstatus.qtpl:29
 			qw422016.N().S(` `)
-//line lib/promscrape/targetstatus.qtpl:30
+//line lib/promscrape/targetstatus.qtpl:29
 			qw422016.N().S(`samples_scraped=`)
-//line lib/promscrape/targetstatus.qtpl:31
+//line lib/promscrape/targetstatus.qtpl:30
 			qw422016.N().D(ts.samplesScraped)
-//line lib/promscrape/targetstatus.qtpl:31
+//line lib/promscrape/targetstatus.qtpl:30
 			qw422016.N().S(`,`)
-//line lib/promscrape/targetstatus.qtpl:31
+//line lib/promscrape/targetstatus.qtpl:30
 			qw422016.N().S(` `)
-//line lib/promscrape/targetstatus.qtpl:31
+//line lib/promscrape/targetstatus.qtpl:30
 			qw422016.N().S(`error=`)
-//line lib/promscrape/targetstatus.qtpl:32
+//line lib/promscrape/targetstatus.qtpl:31
 			if ts.err != nil {
-//line lib/promscrape/targetstatus.qtpl:32
+//line lib/promscrape/targetstatus.qtpl:31
 				qw422016.N().S(ts.err.Error())
-//line lib/promscrape/targetstatus.qtpl:32
+//line lib/promscrape/targetstatus.qtpl:31
 			}
-//line lib/promscrape/targetstatus.qtpl:33
+//line lib/promscrape/targetstatus.qtpl:32
 			qw422016.N().S(`
 `)
-//line lib/promscrape/targetstatus.qtpl:34
+//line lib/promscrape/targetstatus.qtpl:33
 		}
-//line lib/promscrape/targetstatus.qtpl:35
+//line lib/promscrape/targetstatus.qtpl:34
 	}
-//line lib/promscrape/targetstatus.qtpl:37
+//line lib/promscrape/targetstatus.qtpl:36
 	for _, jobName := range tsr.emptyJobs {
-//line lib/promscrape/targetstatus.qtpl:37
+//line lib/promscrape/targetstatus.qtpl:36
 		qw422016.N().S(`job=`)
-//line lib/promscrape/targetstatus.qtpl:38
+//line lib/promscrape/targetstatus.qtpl:37
 		qw422016.N().S(jobName)
-//line lib/promscrape/targetstatus.qtpl:38
+//line lib/promscrape/targetstatus.qtpl:37
 		qw422016.N().S(` `)
-//line lib/promscrape/targetstatus.qtpl:38
+//line lib/promscrape/targetstatus.qtpl:37
 		qw422016.N().S(`(0/0 up)`)
-//line lib/promscrape/targetstatus.qtpl:39
+//line lib/promscrape/targetstatus.qtpl:38
 		qw422016.N().S(`
 `)
-//line lib/promscrape/targetstatus.qtpl:40
+//line lib/promscrape/targetstatus.qtpl:39
 	}
-//line lib/promscrape/targetstatus.qtpl:42
+//line lib/promscrape/targetstatus.qtpl:41
 }
 
-//line lib/promscrape/targetstatus.qtpl:42
+//line lib/promscrape/targetstatus.qtpl:41
 func WriteTargetsResponsePlain(qq422016 qtio422016.Writer, tsr *targetsStatusResult, filter *requestFilter) {
-//line lib/promscrape/targetstatus.qtpl:42
+//line lib/promscrape/targetstatus.qtpl:41
 	qw422016 := qt422016.AcquireWriter(qq422016)
-//line lib/promscrape/targetstatus.qtpl:42
+//line lib/promscrape/targetstatus.qtpl:41
 	StreamTargetsResponsePlain(qw422016, tsr, filter)
-//line lib/promscrape/targetstatus.qtpl:42
+//line lib/promscrape/targetstatus.qtpl:41
 	qt422016.ReleaseWriter(qw422016)
-//line lib/promscrape/targetstatus.qtpl:42
+//line lib/promscrape/targetstatus.qtpl:41
 }
 
-//line lib/promscrape/targetstatus.qtpl:42
+//line lib/promscrape/targetstatus.qtpl:41
 func TargetsResponsePlain(tsr *targetsStatusResult, filter *requestFilter) string {
-//line lib/promscrape/targetstatus.qtpl:42
+//line lib/promscrape/targetstatus.qtpl:41
 	qb422016 := qt422016.AcquireByteBuffer()
-//line lib/promscrape/targetstatus.qtpl:42
+//line lib/promscrape/targetstatus.qtpl:41
 	WriteTargetsResponsePlain(qb422016, tsr, filter)
-//line lib/promscrape/targetstatus.qtpl:42
+//line lib/promscrape/targetstatus.qtpl:41
 	qs422016 := string(qb422016.B)
-//line lib/promscrape/targetstatus.qtpl:42
+//line lib/promscrape/targetstatus.qtpl:41
 	qt422016.ReleaseByteBuffer(qb422016)
-//line lib/promscrape/targetstatus.qtpl:42
+//line lib/promscrape/targetstatus.qtpl:41
 	return qs422016
-//line lib/promscrape/targetstatus.qtpl:42
+//line lib/promscrape/targetstatus.qtpl:41
 }
 
-//line lib/promscrape/targetstatus.qtpl:44
+//line lib/promscrape/targetstatus.qtpl:43
 func StreamTargetsResponseHTML(qw422016 *qt422016.Writer, tsr *targetsStatusResult, filter *requestFilter) {
-//line lib/promscrape/targetstatus.qtpl:44
+//line lib/promscrape/targetstatus.qtpl:43
 	qw422016.N().S(`<!DOCTYPE html><html lang="en"><head>`)
-//line lib/promscrape/targetstatus.qtpl:48
+//line lib/promscrape/targetstatus.qtpl:47
 	streamcommonHeader(qw422016)
-//line lib/promscrape/targetstatus.qtpl:48
+//line lib/promscrape/targetstatus.qtpl:47
 	qw422016.N().S(`<title>Active Targets</title></head><body>`)
-//line lib/promscrape/targetstatus.qtpl:52
+//line lib/promscrape/targetstatus.qtpl:51
 	streamnavbar(qw422016)
-//line lib/promscrape/targetstatus.qtpl:52
+//line lib/promscrape/targetstatus.qtpl:51
 	qw422016.N().S(`<div class="container-fluid">`)
+//line lib/promscrape/targetstatus.qtpl:53
+	if tsr.err != nil {
 //line lib/promscrape/targetstatus.qtpl:54
-	if tsr.err != nil {
+		streamerrorNotification(qw422016, tsr.err)
 //line lib/promscrape/targetstatus.qtpl:55
-		streamerrorNotification(qw422016, tsr.err)
-//line lib/promscrape/targetstatus.qtpl:56
 	}
-//line lib/promscrape/targetstatus.qtpl:56
+//line lib/promscrape/targetstatus.qtpl:55
 	qw422016.N().S(`<div class="row"><main class="col-12"><h1>Active Targets</h1><hr />`)
-//line lib/promscrape/targetstatus.qtpl:61
+//line lib/promscrape/targetstatus.qtpl:60
 	streamfiltersForm(qw422016, filter)
-//line lib/promscrape/targetstatus.qtpl:61
+//line lib/promscrape/targetstatus.qtpl:60
 	qw422016.N().S(`<hr />`)
-//line lib/promscrape/targetstatus.qtpl:63
+//line lib/promscrape/targetstatus.qtpl:62
 	streamtargetsTabs(qw422016, tsr, filter, "scrapeTargets")
-//line lib/promscrape/targetstatus.qtpl:63
+//line lib/promscrape/targetstatus.qtpl:62
 	qw422016.N().S(`</main></div></div></body></html>`)
-//line lib/promscrape/targetstatus.qtpl:69
+//line lib/promscrape/targetstatus.qtpl:68
 }
 
-//line lib/promscrape/targetstatus.qtpl:69
+//line lib/promscrape/targetstatus.qtpl:68
 func WriteTargetsResponseHTML(qq422016 qtio422016.Writer, tsr *targetsStatusResult, filter *requestFilter) {
-//line lib/promscrape/targetstatus.qtpl:69
+//line lib/promscrape/targetstatus.qtpl:68
 	qw422016 := qt422016.AcquireWriter(qq422016)
-//line lib/promscrape/targetstatus.qtpl:69
+//line lib/promscrape/targetstatus.qtpl:68
 	StreamTargetsResponseHTML(qw422016, tsr, filter)
-//line lib/promscrape/targetstatus.qtpl:69
+//line lib/promscrape/targetstatus.qtpl:68
 	qt422016.ReleaseWriter(qw422016)
-//line lib/promscrape/targetstatus.qtpl:69
+//line lib/promscrape/targetstatus.qtpl:68
 }
 
-//line lib/promscrape/targetstatus.qtpl:69
+//line lib/promscrape/targetstatus.qtpl:68
 func TargetsResponseHTML(tsr *targetsStatusResult, filter *requestFilter) string {
-//line lib/promscrape/targetstatus.qtpl:69
+//line lib/promscrape/targetstatus.qtpl:68
 	qb422016 := qt422016.AcquireByteBuffer()
-//line lib/promscrape/targetstatus.qtpl:69
+//line lib/promscrape/targetstatus.qtpl:68
 	WriteTargetsResponseHTML(qb422016, tsr, filter)
-//line lib/promscrape/targetstatus.qtpl:69
+//line lib/promscrape/targetstatus.qtpl:68
 	qs422016 := string(qb422016.B)
-//line lib/promscrape/targetstatus.qtpl:69
+//line lib/promscrape/targetstatus.qtpl:68
 	qt422016.ReleaseByteBuffer(qb422016)
-//line lib/promscrape/targetstatus.qtpl:69
+//line lib/promscrape/targetstatus.qtpl:68
 	return qs422016
-//line lib/promscrape/targetstatus.qtpl:69
+//line lib/promscrape/targetstatus.qtpl:68
 }
 
-//line lib/promscrape/targetstatus.qtpl:71
+//line lib/promscrape/targetstatus.qtpl:70
 func StreamServiceDiscoveryResponse(qw422016 *qt422016.Writer, tsr *targetsStatusResult, filter *requestFilter) {
-//line lib/promscrape/targetstatus.qtpl:71
+//line lib/promscrape/targetstatus.qtpl:70
 	qw422016.N().S(`<!DOCTYPE html><html lang="en"><head>`)
-//line lib/promscrape/targetstatus.qtpl:75
+//line lib/promscrape/targetstatus.qtpl:74
 	streamcommonHeader(qw422016)
-//line lib/promscrape/targetstatus.qtpl:75
+//line lib/promscrape/targetstatus.qtpl:74
 	qw422016.N().S(`<title>Discovered Targets</title></head><body>`)
-//line lib/promscrape/targetstatus.qtpl:79
+//line lib/promscrape/targetstatus.qtpl:78
 	streamnavbar(qw422016)
-//line lib/promscrape/targetstatus.qtpl:79
+//line lib/promscrape/targetstatus.qtpl:78
 	qw422016.N().S(`<div class="container-fluid">`)
-//line lib/promscrape/targetstatus.qtpl:81
+//line lib/promscrape/targetstatus.qtpl:80
 	if tsr.err != nil {
-//line lib/promscrape/targetstatus.qtpl:82
+//line lib/promscrape/targetstatus.qtpl:81
 		streamerrorNotification(qw422016, tsr.err)
-//line lib/promscrape/targetstatus.qtpl:83
+//line lib/promscrape/targetstatus.qtpl:82
 	}
-//line lib/promscrape/targetstatus.qtpl:83
+//line lib/promscrape/targetstatus.qtpl:82
 	qw422016.N().S(`<div class="row"><main class="col-12"><h1>Discovered Targets</h1><hr />`)
-//line lib/promscrape/targetstatus.qtpl:88
+//line lib/promscrape/targetstatus.qtpl:87
 	streamfiltersForm(qw422016, filter)
-//line lib/promscrape/targetstatus.qtpl:88
+//line lib/promscrape/targetstatus.qtpl:87
 	qw422016.N().S(`<hr />`)
-//line lib/promscrape/targetstatus.qtpl:90
+//line lib/promscrape/targetstatus.qtpl:89
 	streamtargetsTabs(qw422016, tsr, filter, "discoveredTargets")
-//line lib/promscrape/targetstatus.qtpl:90
+//line lib/promscrape/targetstatus.qtpl:89
 	qw422016.N().S(`</main></div></div></body></html>`)
-//line lib/promscrape/targetstatus.qtpl:96
+//line lib/promscrape/targetstatus.qtpl:95
 }
 
-//line lib/promscrape/targetstatus.qtpl:96
+//line lib/promscrape/targetstatus.qtpl:95
 func WriteServiceDiscoveryResponse(qq422016 qtio422016.Writer, tsr *targetsStatusResult, filter *requestFilter) {
-//line lib/promscrape/targetstatus.qtpl:96
+//line lib/promscrape/targetstatus.qtpl:95
 	qw422016 := qt422016.AcquireWriter(qq422016)
-//line lib/promscrape/targetstatus.qtpl:96
+//line lib/promscrape/targetstatus.qtpl:95
 	StreamServiceDiscoveryResponse(qw422016, tsr, filter)
-//line lib/promscrape/targetstatus.qtpl:96
+//line lib/promscrape/targetstatus.qtpl:95
 	qt422016.ReleaseWriter(qw422016)
-//line lib/promscrape/targetstatus.qtpl:96
+//line lib/promscrape/targetstatus.qtpl:95
 }
 
-//line lib/promscrape/targetstatus.qtpl:96
+//line lib/promscrape/targetstatus.qtpl:95
 func ServiceDiscoveryResponse(tsr *targetsStatusResult, filter *requestFilter) string {
-//line lib/promscrape/targetstatus.qtpl:96
+//line lib/promscrape/targetstatus.qtpl:95
 	qb422016 := qt422016.AcquireByteBuffer()
-//line lib/promscrape/targetstatus.qtpl:96
+//line lib/promscrape/targetstatus.qtpl:95
 	WriteServiceDiscoveryResponse(qb422016, tsr, filter)
-//line lib/promscrape/targetstatus.qtpl:96
+//line lib/promscrape/targetstatus.qtpl:95
 	qs422016 := string(qb422016.B)
-//line lib/promscrape/targetstatus.qtpl:96
+//line lib/promscrape/targetstatus.qtpl:95
 	qt422016.ReleaseByteBuffer(qb422016)
-//line lib/promscrape/targetstatus.qtpl:96
+//line lib/promscrape/targetstatus.qtpl:95
 	return qs422016
-//line lib/promscrape/targetstatus.qtpl:96
+//line lib/promscrape/targetstatus.qtpl:95
 }
 
-//line lib/promscrape/targetstatus.qtpl:98
+//line lib/promscrape/targetstatus.qtpl:97
 func streamcommonHeader(qw422016 *qt422016.Writer) {
-//line lib/promscrape/targetstatus.qtpl:98
+//line lib/promscrape/targetstatus.qtpl:97
 	qw422016.N().S(`<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><link href="static/css/bootstrap.min.css" rel="stylesheet" />`)
-//line lib/promscrape/targetstatus.qtpl:102
+//line lib/promscrape/targetstatus.qtpl:101
 }
 
-//line lib/promscrape/targetstatus.qtpl:102
+//line lib/promscrape/targetstatus.qtpl:101
 func writecommonHeader(qq422016 qtio422016.Writer) {
-//line lib/promscrape/targetstatus.qtpl:102
+//line lib/promscrape/targetstatus.qtpl:101
 	qw422016 := qt422016.AcquireWriter(qq422016)
-//line lib/promscrape/targetstatus.qtpl:102
+//line lib/promscrape/targetstatus.qtpl:101
 	streamcommonHeader(qw422016)
-//line lib/promscrape/targetstatus.qtpl:102
+//line lib/promscrape/targetstatus.qtpl:101
 	qt422016.ReleaseWriter(qw422016)
-//line lib/promscrape/targetstatus.qtpl:102
+//line lib/promscrape/targetstatus.qtpl:101
 }
 
-//line lib/promscrape/targetstatus.qtpl:102
+//line lib/promscrape/targetstatus.qtpl:101
 func commonHeader() string {
-//line lib/promscrape/targetstatus.qtpl:102
+//line lib/promscrape/targetstatus.qtpl:101
 	qb422016 := qt422016.AcquireByteBuffer()
-//line lib/promscrape/targetstatus.qtpl:102
+//line lib/promscrape/targetstatus.qtpl:101
 	writecommonHeader(qb422016)
-//line lib/promscrape/targetstatus.qtpl:102
+//line lib/promscrape/targetstatus.qtpl:101
 	qs422016 := string(qb422016.B)
-//line lib/promscrape/targetstatus.qtpl:102
+//line lib/promscrape/targetstatus.qtpl:101
 	qt422016.ReleaseByteBuffer(qb422016)
-//line lib/promscrape/targetstatus.qtpl:102
+//line lib/promscrape/targetstatus.qtpl:101
 	return qs422016
-//line lib/promscrape/targetstatus.qtpl:102
+//line lib/promscrape/targetstatus.qtpl:101
 }
 
-//line lib/promscrape/targetstatus.qtpl:104
+//line lib/promscrape/targetstatus.qtpl:103
 func streamnavbar(qw422016 *qt422016.Writer) {
-//line lib/promscrape/targetstatus.qtpl:104
+//line lib/promscrape/targetstatus.qtpl:103
 	qw422016.N().S(`<div class="navbar navbar-dark bg-dark box-shadow"><div class="d-flex justify-content-between"><a href="#" class="navbar-brand d-flex align-items-center ms-3" title="The High Performance Open Source Time Series Database &amp; Monitoring Solution "><svg xmlns="http://www.w3.org/2000/svg" id="VM_logo" viewBox="0 0 464.61 533.89" width="20" height="20" class="me-1"><defs><style>.cls-1{fill:#fff;}</style></defs><path class="cls-1" d="M459.86,467.77c9,7.67,24.12,13.49,39.3,13.69v0h1.68v0c15.18-.2,30.31-6,39.3-13.69,47.43-40.45,184.65-166.24,184.65-166.24,36.84-34.27-65.64-68.28-223.95-68.47h-1.68c-158.31.19-260.79,34.2-224,68.47C275.21,301.53,412.43,427.32,459.86,467.77Z" transform="translate(-267.7 -233.05)"/><path class="cls-1" d="M540.1,535.88c-9,7.67-24.12,13.5-39.3,13.7h-1.6c-15.18-.2-30.31-6-39.3-13.7-32.81-28-148.56-132.93-192.16-172.7v60.74c0,6.67,2.55,15.52,7.09,19.68,29.64,27.18,143.94,131.8,185.07,166.88,9,7.67,24.12,13.49,39.3,13.69v0h1.6v0c15.18-.2,30.31-6,39.3-13.69,41.13-35.08,155.43-139.7,185.07-166.88,4.54-4.16,7.09-13,7.09-19.68V363.18C688.66,403,572.91,507.9,540.1,535.88Z" transform="translate(-267.7 -233.05)"/><path class="cls-1" d="M540.1,678.64c-9,7.67-24.12,13.49-39.3,13.69v0h-1.6v0c-15.18-.2-30.31-6-39.3-13.69-32.81-28-148.56-132.94-192.16-172.7v60.73c0,6.67,2.55,15.53,7.09,19.69,29.64,27.17,143.94,131.8,185.07,166.87,9,7.67,24.12,13.5,39.3,13.7h1.6c15.18-.2,30.31-6,39.3-13.7,41.13-35.07,155.43-139.7,185.07-166.87,4.54-4.16,7.09-13,7.09-19.69V505.94C688.66,545.7,572.91,650.66,540.1,678.64Z" transform="translate(-267.7 -233.05)"/></svg><strong>VictoriaMetrics</strong></a></div></div>`)
-//line lib/promscrape/targetstatus.qtpl:113
+//line lib/promscrape/targetstatus.qtpl:112
 }
 
-//line lib/promscrape/targetstatus.qtpl:113
+//line lib/promscrape/targetstatus.qtpl:112
 func writenavbar(qq422016 qtio422016.Writer) {
-//line lib/promscrape/targetstatus.qtpl:113
+//line lib/promscrape/targetstatus.qtpl:112
 	qw422016 := qt422016.AcquireWriter(qq422016)
-//line lib/promscrape/targetstatus.qtpl:113
+//line lib/promscrape/targetstatus.qtpl:112
 	streamnavbar(qw422016)
-//line lib/promscrape/targetstatus.qtpl:113
+//line lib/promscrape/targetstatus.qtpl:112
 	qt422016.ReleaseWriter(qw422016)
-//line lib/promscrape/targetstatus.qtpl:113
+//line lib/promscrape/targetstatus.qtpl:112
 }
 
-//line lib/promscrape/targetstatus.qtpl:113
+//line lib/promscrape/targetstatus.qtpl:112
 func navbar() string {
-//line lib/promscrape/targetstatus.qtpl:113
+//line lib/promscrape/targetstatus.qtpl:112
 	qb422016 := qt422016.AcquireByteBuffer()
-//line lib/promscrape/targetstatus.qtpl:113
+//line lib/promscrape/targetstatus.qtpl:112
 	writenavbar(qb422016)
-//line lib/promscrape/targetstatus.qtpl:113
+//line lib/promscrape/targetstatus.qtpl:112
 	qs422016 := string(qb422016.B)
-//line lib/promscrape/targetstatus.qtpl:113
+//line lib/promscrape/targetstatus.qtpl:112
 	qt422016.ReleaseByteBuffer(qb422016)
-//line lib/promscrape/targetstatus.qtpl:113
+//line lib/promscrape/targetstatus.qtpl:112
 	return qs422016
-//line lib/promscrape/targetstatus.qtpl:113
+//line lib/promscrape/targetstatus.qtpl:112
 }
 
-//line lib/promscrape/targetstatus.qtpl:115
+//line lib/promscrape/targetstatus.qtpl:114
 func streamfiltersForm(qw422016 *qt422016.Writer, filter *requestFilter) {
-//line lib/promscrape/targetstatus.qtpl:115
+//line lib/promscrape/targetstatus.qtpl:114
 	qw422016.N().S(`<div class="row g-3 align-items-center mb-3"><div class="col-auto"><button id="all-btn" type="button" class="btn`)
-//line lib/promscrape/targetstatus.qtpl:118
+//line lib/promscrape/targetstatus.qtpl:117
 	qw422016.N().S(` `)
-//line lib/promscrape/targetstatus.qtpl:118
+//line lib/promscrape/targetstatus.qtpl:117
 	if !filter.showOnlyUnhealthy {
-//line lib/promscrape/targetstatus.qtpl:118
+//line lib/promscrape/targetstatus.qtpl:117
 		qw422016.N().S(`btn-secondary`)
-//line lib/promscrape/targetstatus.qtpl:118
+//line lib/promscrape/targetstatus.qtpl:117
 	} else {
-//line lib/promscrape/targetstatus.qtpl:118
+//line lib/promscrape/targetstatus.qtpl:117
 		qw422016.N().S(`btn-success`)
-//line lib/promscrape/targetstatus.qtpl:118
+//line lib/promscrape/targetstatus.qtpl:117
 	}
-//line lib/promscrape/targetstatus.qtpl:118
+//line lib/promscrape/targetstatus.qtpl:117
 	qw422016.N().S(`"onclick="location.href='?`)
-//line lib/promscrape/targetstatus.qtpl:119
+//line lib/promscrape/targetstatus.qtpl:118
 	streamqueryArgs(qw422016, filter, map[string]string{"show_only_unhealthy": "false"})
-//line lib/promscrape/targetstatus.qtpl:119
+//line lib/promscrape/targetstatus.qtpl:118
 	qw422016.N().S(`'">All</button></div><div class="col-auto"><button id="unhealthy-btn" type="button" class="btn`)
-//line lib/promscrape/targetstatus.qtpl:124
+//line lib/promscrape/targetstatus.qtpl:123
 	qw422016.N().S(` `)
-//line lib/promscrape/targetstatus.qtpl:124
+//line lib/promscrape/targetstatus.qtpl:123
 	if filter.showOnlyUnhealthy {
-//line lib/promscrape/targetstatus.qtpl:124
+//line lib/promscrape/targetstatus.qtpl:123
 		qw422016.N().S(`btn-secondary`)
-//line lib/promscrape/targetstatus.qtpl:124
+//line lib/promscrape/targetstatus.qtpl:123
 	} else {
-//line lib/promscrape/targetstatus.qtpl:124
+//line lib/promscrape/targetstatus.qtpl:123
 		qw422016.N().S(`btn-danger`)
-//line lib/promscrape/targetstatus.qtpl:124
+//line lib/promscrape/targetstatus.qtpl:123
 	}
-//line lib/promscrape/targetstatus.qtpl:124
+//line lib/promscrape/targetstatus.qtpl:123
 	qw422016.N().S(`"onclick="location.href='?`)
-//line lib/promscrape/targetstatus.qtpl:125
+//line lib/promscrape/targetstatus.qtpl:124
 	streamqueryArgs(qw422016, filter, map[string]string{"show_only_unhealthy": "true"})
-//line lib/promscrape/targetstatus.qtpl:125
+//line lib/promscrape/targetstatus.qtpl:124
 	qw422016.N().S(`'">Unhealthy</button></div><div class="col-auto"><button type="button" class="btn btn-primary" onclick="document.querySelectorAll('.scrape-job').forEach((el) => { el.style.display = 'none'; })">Collapse all</button></div><div class="col-auto"><button type="button" class="btn btn-secondary" onclick="document.querySelectorAll('.scrape-job').forEach((el) => { el.style.display = 'block'; })">Expand all</button></div><div class="col-auto"><button type="button" class="btn btn-success" onclick="document.getElementById('filters').style.display='block'">Filter targets</button></div></div><div id="filters"`)
-//line lib/promscrape/targetstatus.qtpl:145
+//line lib/promscrape/targetstatus.qtpl:144
 	if filter.endpointSearch == "" && filter.labelSearch == "" {
-//line lib/promscrape/targetstatus.qtpl:145
+//line lib/promscrape/targetstatus.qtpl:144
 		qw422016.N().S(`style="display:none"`)
-//line lib/promscrape/targetstatus.qtpl:145
+//line lib/promscrape/targetstatus.qtpl:144
 	}
-//line lib/promscrape/targetstatus.qtpl:145
+//line lib/promscrape/targetstatus.qtpl:144
 	qw422016.N().S(`><form class="form-horizontal"><div class="form-group mb-3"><label for="endpoint_search" class="col-sm-10 control-label">Endpoint filter (<a target="_blank" href="https://github.com/google/re2/wiki/Syntax">Regexp</a> is accepted)</label><div class="col-sm-10"><input type="text" id="endpoint_search" name="endpoint_search"placeholder="For example, 127.0.0.1" class="form-control" value="`)
-//line lib/promscrape/targetstatus.qtpl:151
+//line lib/promscrape/targetstatus.qtpl:150
 	qw422016.E().S(filter.endpointSearch)
-//line lib/promscrape/targetstatus.qtpl:151
+//line lib/promscrape/targetstatus.qtpl:150
 	qw422016.N().S(`"/></div></div><div class="form-group mb-3"><label for="label_search" class="col-sm-10 control-label">Labels filter (<a target="_blank" href="https://prometheus.io/docs/prometheus/latest/querying/basics/#time-series-selectors">Arbitrary time series selectors</a> are accepted)</label><div class="col-sm-10"><input type="text" id="label_search" name="label_search"placeholder="For example, {instance=~'.+:9100'}" class="form-control" value="`)
-//line lib/promscrape/targetstatus.qtpl:158
+//line lib/promscrape/targetstatus.qtpl:157
 	qw422016.E().S(filter.labelSearch)
-//line lib/promscrape/targetstatus.qtpl:158
+//line lib/promscrape/targetstatus.qtpl:157
 	qw422016.N().S(`"/></div></div><input type="hidden" name="show_only_unhealthy" value="`)
-//line lib/promscrape/targetstatus.qtpl:161
+//line lib/promscrape/targetstatus.qtpl:160
 	qw422016.E().V(filter.showOnlyUnhealthy)
-//line lib/promscrape/targetstatus.qtpl:161
+//line lib/promscrape/targetstatus.qtpl:160
 	qw422016.N().S(`"/><input type="hidden" name="show_original_labels" value="`)
-//line lib/promscrape/targetstatus.qtpl:162
+//line lib/promscrape/targetstatus.qtpl:161
 	qw422016.E().V(filter.showOriginalLabels)
-//line lib/promscrape/targetstatus.qtpl:162
+//line lib/promscrape/targetstatus.qtpl:161
 	qw422016.N().S(`"/><button type="submit" class="btn btn-success mb-3">Submit</button><button type="button" class="btn btn-danger mb-3" onclick="location.href='?'">Clear target filters</button></form></div>`)
-//line lib/promscrape/targetstatus.qtpl:167
+//line lib/promscrape/targetstatus.qtpl:166
 }
 
-//line lib/promscrape/targetstatus.qtpl:167
+//line lib/promscrape/targetstatus.qtpl:166
 func writefiltersForm(qq422016 qtio422016.Writer, filter *requestFilter) {
-//line lib/promscrape/targetstatus.qtpl:167
+//line lib/promscrape/targetstatus.qtpl:166
 	qw422016 := qt422016.AcquireWriter(qq422016)
-//line lib/promscrape/targetstatus.qtpl:167
+//line lib/promscrape/targetstatus.qtpl:166
 	streamfiltersForm(qw422016, filter)
-//line lib/promscrape/targetstatus.qtpl:167
+//line lib/promscrape/targetstatus.qtpl:166
 	qt422016.ReleaseWriter(qw422016)
-//line lib/promscrape/targetstatus.qtpl:167
+//line lib/promscrape/targetstatus.qtpl:166
 }
 
-//line lib/promscrape/targetstatus.qtpl:167
+//line lib/promscrape/targetstatus.qtpl:166
 func filtersForm(filter *requestFilter) string {
-//line lib/promscrape/targetstatus.qtpl:167
+//line lib/promscrape/targetstatus.qtpl:166
 	qb422016 := qt422016.AcquireByteBuffer()
-//line lib/promscrape/targetstatus.qtpl:167
+//line lib/promscrape/targetstatus.qtpl:166
 	writefiltersForm(qb422016, filter)
-//line lib/promscrape/targetstatus.qtpl:167
+//line lib/promscrape/targetstatus.qtpl:166
 	qs422016 := string(qb422016.B)
-//line lib/promscrape/targetstatus.qtpl:167
+//line lib/promscrape/targetstatus.qtpl:166
 	qt422016.ReleaseByteBuffer(qb422016)
-//line lib/promscrape/targetstatus.qtpl:167
+//line lib/promscrape/targetstatus.qtpl:166
 	return qs422016
-//line lib/promscrape/targetstatus.qtpl:167
+//line lib/promscrape/targetstatus.qtpl:166
 }
 
-//line lib/promscrape/targetstatus.qtpl:169
+//line lib/promscrape/targetstatus.qtpl:168
 func streamtargetsTabs(qw422016 *qt422016.Writer, tsr *targetsStatusResult, filter *requestFilter, activeTab string) {
-//line lib/promscrape/targetstatus.qtpl:169
+//line lib/promscrape/targetstatus.qtpl:168
 	qw422016.N().S(`<ul class="nav nav-tabs" id="myTab" role="tablist"><li class="nav-item" role="presentation"><button class="nav-link`)
-//line lib/promscrape/targetstatus.qtpl:172
+//line lib/promscrape/targetstatus.qtpl:171
 	if activeTab == "scrapeTargets" {
-//line lib/promscrape/targetstatus.qtpl:172
+//line lib/promscrape/targetstatus.qtpl:171
 		qw422016.N().S(` `)
-//line lib/promscrape/targetstatus.qtpl:172
+//line lib/promscrape/targetstatus.qtpl:171
 		qw422016.N().S(`active`)
-//line lib/promscrape/targetstatus.qtpl:172
+//line lib/promscrape/targetstatus.qtpl:171
 	}
-//line lib/promscrape/targetstatus.qtpl:172
+//line lib/promscrape/targetstatus.qtpl:171
 	qw422016.N().S(`" type="button" role="tab"onclick="location.href='targets?`)
-//line lib/promscrape/targetstatus.qtpl:173
+//line lib/promscrape/targetstatus.qtpl:172
 	streamqueryArgs(qw422016, filter, nil)
-//line lib/promscrape/targetstatus.qtpl:173
+//line lib/promscrape/targetstatus.qtpl:172
 	qw422016.N().S(`'">Active targets</button></li><li class="nav-item" role="presentation"><button class="nav-link`)
-//line lib/promscrape/targetstatus.qtpl:178
+//line lib/promscrape/targetstatus.qtpl:177
 	if activeTab == "discoveredTargets" {
-//line lib/promscrape/targetstatus.qtpl:178
+//line lib/promscrape/targetstatus.qtpl:177
 		qw422016.N().S(` `)
-//line lib/promscrape/targetstatus.qtpl:178
+//line lib/promscrape/targetstatus.qtpl:177
 		qw422016.N().S(`active`)
-//line lib/promscrape/targetstatus.qtpl:178
+//line lib/promscrape/targetstatus.qtpl:177
 	}
-//line lib/promscrape/targetstatus.qtpl:178
+//line lib/promscrape/targetstatus.qtpl:177
 	qw422016.N().S(`" type="button" role="tab"onclick="location.href='service-discovery?`)
-//line lib/promscrape/targetstatus.qtpl:179
+//line lib/promscrape/targetstatus.qtpl:178
 	streamqueryArgs(qw422016, filter, nil)
-//line lib/promscrape/targetstatus.qtpl:179
+//line lib/promscrape/targetstatus.qtpl:178
 	qw422016.N().S(`'">Discovered targets</button></li></ul><div class="tab-content"><div class="tab-pane active" role="tabpanel">`)
-//line lib/promscrape/targetstatus.qtpl:186
+//line lib/promscrape/targetstatus.qtpl:185
 	switch activeTab {
-//line lib/promscrape/targetstatus.qtpl:187
+//line lib/promscrape/targetstatus.qtpl:186
 	case "scrapeTargets":
-//line lib/promscrape/targetstatus.qtpl:188
+//line lib/promscrape/targetstatus.qtpl:187
 		streamscrapeTargets(qw422016, tsr)
-//line lib/promscrape/targetstatus.qtpl:189
+//line lib/promscrape/targetstatus.qtpl:188
 	case "discoveredTargets":
-//line lib/promscrape/targetstatus.qtpl:190
+//line lib/promscrape/targetstatus.qtpl:189
 		streamdiscoveredTargets(qw422016, tsr)
-//line lib/promscrape/targetstatus.qtpl:191
+//line lib/promscrape/targetstatus.qtpl:190
 	}
-//line lib/promscrape/targetstatus.qtpl:191
+//line lib/promscrape/targetstatus.qtpl:190
 	qw422016.N().S(`</div></div>`)
-//line lib/promscrape/targetstatus.qtpl:194
+//line lib/promscrape/targetstatus.qtpl:193
 }
 
-//line lib/promscrape/targetstatus.qtpl:194
+//line lib/promscrape/targetstatus.qtpl:193
 func writetargetsTabs(qq422016 qtio422016.Writer, tsr *targetsStatusResult, filter *requestFilter, activeTab string) {
-//line lib/promscrape/targetstatus.qtpl:194
+//line lib/promscrape/targetstatus.qtpl:193
 	qw422016 := qt422016.AcquireWriter(qq422016)
-//line lib/promscrape/targetstatus.qtpl:194
+//line lib/promscrape/targetstatus.qtpl:193
 	streamtargetsTabs(qw422016, tsr, filter, activeTab)
-//line lib/promscrape/targetstatus.qtpl:194
+//line lib/promscrape/targetstatus.qtpl:193
 	qt422016.ReleaseWriter(qw422016)
-//line lib/promscrape/targetstatus.qtpl:194
+//line lib/promscrape/targetstatus.qtpl:193
 }
 
-//line lib/promscrape/targetstatus.qtpl:194
+//line lib/promscrape/targetstatus.qtpl:193
 func targetsTabs(tsr *targetsStatusResult, filter *requestFilter, activeTab string) string {
-//line lib/promscrape/targetstatus.qtpl:194
+//line lib/promscrape/targetstatus.qtpl:193
 	qb422016 := qt422016.AcquireByteBuffer()
-//line lib/promscrape/targetstatus.qtpl:194
+//line lib/promscrape/targetstatus.qtpl:193
 	writetargetsTabs(qb422016, tsr, filter, activeTab)
-//line lib/promscrape/targetstatus.qtpl:194
+//line lib/promscrape/targetstatus.qtpl:193
 	qs422016 := string(qb422016.B)
-//line lib/promscrape/targetstatus.qtpl:194
+//line lib/promscrape/targetstatus.qtpl:193
 	qt422016.ReleaseByteBuffer(qb422016)
-//line lib/promscrape/targetstatus.qtpl:194
+//line lib/promscrape/targetstatus.qtpl:193
 	return qs422016
-//line lib/promscrape/targetstatus.qtpl:194
+//line lib/promscrape/targetstatus.qtpl:193
 }
 
-//line lib/promscrape/targetstatus.qtpl:196
+//line lib/promscrape/targetstatus.qtpl:195
 func streamscrapeTargets(qw422016 *qt422016.Writer, tsr *targetsStatusResult) {
-//line lib/promscrape/targetstatus.qtpl:196
+//line lib/promscrape/targetstatus.qtpl:195
 	qw422016.N().S(`<div class="row mt-4"><div class="col-12">`)
-//line lib/promscrape/targetstatus.qtpl:199
+//line lib/promscrape/targetstatus.qtpl:198
 	for i, jts := range tsr.jobTargetsStatuses {
-//line lib/promscrape/targetstatus.qtpl:200
+//line lib/promscrape/targetstatus.qtpl:199
 		streamscrapeJobTargets(qw422016, i, jts)
-//line lib/promscrape/targetstatus.qtpl:201
+//line lib/promscrape/targetstatus.qtpl:200
 	}
-//line lib/promscrape/targetstatus.qtpl:202
+//line lib/promscrape/targetstatus.qtpl:201
 	for i, jobName := range tsr.emptyJobs {
-//line lib/promscrape/targetstatus.qtpl:204
+//line lib/promscrape/targetstatus.qtpl:203
 		num := i + len(tsr.jobTargetsStatuses)
 		jts := &jobTargetsStatuses{
 			jobName: jobName,
 		}
 
-//line lib/promscrape/targetstatus.qtpl:209
+//line lib/promscrape/targetstatus.qtpl:208
 		streamscrapeJobTargets(qw422016, num, jts)
-//line lib/promscrape/targetstatus.qtpl:210
+//line lib/promscrape/targetstatus.qtpl:209
 	}
-//line lib/promscrape/targetstatus.qtpl:210
+//line lib/promscrape/targetstatus.qtpl:209
 	qw422016.N().S(`</div></div>`)
-//line lib/promscrape/targetstatus.qtpl:213
+//line lib/promscrape/targetstatus.qtpl:212
 }
 
-//line lib/promscrape/targetstatus.qtpl:213
+//line lib/promscrape/targetstatus.qtpl:212
 func writescrapeTargets(qq422016 qtio422016.Writer, tsr *targetsStatusResult) {
-//line lib/promscrape/targetstatus.qtpl:213
+//line lib/promscrape/targetstatus.qtpl:212
 	qw422016 := qt422016.AcquireWriter(qq422016)
-//line lib/promscrape/targetstatus.qtpl:213
+//line lib/promscrape/targetstatus.qtpl:212
 	streamscrapeTargets(qw422016, tsr)
-//line lib/promscrape/targetstatus.qtpl:213
+//line lib/promscrape/targetstatus.qtpl:212
 	qt422016.ReleaseWriter(qw422016)
-//line lib/promscrape/targetstatus.qtpl:213
+//line lib/promscrape/targetstatus.qtpl:212
 }
 
-//line lib/promscrape/targetstatus.qtpl:213
+//line lib/promscrape/targetstatus.qtpl:212
 func scrapeTargets(tsr *targetsStatusResult) string {
-//line lib/promscrape/targetstatus.qtpl:213
+//line lib/promscrape/targetstatus.qtpl:212
 	qb422016 := qt422016.AcquireByteBuffer()
-//line lib/promscrape/targetstatus.qtpl:213
+//line lib/promscrape/targetstatus.qtpl:212
 	writescrapeTargets(qb422016, tsr)
-//line lib/promscrape/targetstatus.qtpl:213
+//line lib/promscrape/targetstatus.qtpl:212
 	qs422016 := string(qb422016.B)
-//line lib/promscrape/targetstatus.qtpl:213
+//line lib/promscrape/targetstatus.qtpl:212
 	qt422016.ReleaseByteBuffer(qb422016)
-//line lib/promscrape/targetstatus.qtpl:213
+//line lib/promscrape/targetstatus.qtpl:212
 	return qs422016
-//line lib/promscrape/targetstatus.qtpl:213
+//line lib/promscrape/targetstatus.qtpl:212
 }
 
-//line lib/promscrape/targetstatus.qtpl:215
+//line lib/promscrape/targetstatus.qtpl:214
 func streamscrapeJobTargets(qw422016 *qt422016.Writer, num int, jts *jobTargetsStatuses) {
-//line lib/promscrape/targetstatus.qtpl:215
+//line lib/promscrape/targetstatus.qtpl:214
 	qw422016.N().S(`<div class="row mb-4"><div class="col-12"><h4><span class="me-2">`)
-//line lib/promscrape/targetstatus.qtpl:219
+//line lib/promscrape/targetstatus.qtpl:218
 	qw422016.E().S(jts.jobName)
-//line lib/promscrape/targetstatus.qtpl:219
+//line lib/promscrape/targetstatus.qtpl:218
 	qw422016.N().S(` `)
-//line lib/promscrape/targetstatus.qtpl:219
+//line lib/promscrape/targetstatus.qtpl:218
 	qw422016.N().S(`(`)
-//line lib/promscrape/targetstatus.qtpl:219
+//line lib/promscrape/targetstatus.qtpl:218
 	qw422016.N().D(jts.upCount)
-//line lib/promscrape/targetstatus.qtpl:219
+//line lib/promscrape/targetstatus.qtpl:218
 	qw422016.N().S(`/`)
-//line lib/promscrape/targetstatus.qtpl:219
+//line lib/promscrape/targetstatus.qtpl:218
 	qw422016.N().D(jts.targetsTotal)
-//line lib/promscrape/targetstatus.qtpl:219
+//line lib/promscrape/targetstatus.qtpl:218
 	qw422016.N().S(` `)
-//line lib/promscrape/targetstatus.qtpl:219
+//line lib/promscrape/targetstatus.qtpl:218
 	qw422016.N().S(`up)</span>`)
-//line lib/promscrape/targetstatus.qtpl:220
+//line lib/promscrape/targetstatus.qtpl:219
 	streamshowHideScrapeJobButtons(qw422016, num)
-//line lib/promscrape/targetstatus.qtpl:220
+//line lib/promscrape/targetstatus.qtpl:219
 	qw422016.N().S(`</h4><div id="scrape-job-`)
-//line lib/promscrape/targetstatus.qtpl:222
+//line lib/promscrape/targetstatus.qtpl:221
 	qw422016.N().D(num)
-//line lib/promscrape/targetstatus.qtpl:222
+//line lib/promscrape/targetstatus.qtpl:221
 	qw422016.N().S(`" class="scrape-job table-responsive"><table class="table table-striped table-hover table-bordered table-sm"><thead><tr><th scope="col">Endpoint</th><th scope="col">State</th><th scope="col" title="target labels">Labels</th><th scope="col" title="total scrapes">Scrapes</th><th scope="col" title="total scrape errors">Errors</th><th scope="col" title="the time of the last scrape">Last Scrape</th><th scope="col" title="the duration of the last scrape">Duration</th><th scope="col" title="the number of metrics scraped during the last scrape">Samples</th><th scope="col" title="error from the last scrape (if any)">Last error</th></tr></thead><tbody>`)
-//line lib/promscrape/targetstatus.qtpl:238
+//line lib/promscrape/targetstatus.qtpl:237
 	for _, ts := range jts.targetsStatus {
-//line lib/promscrape/targetstatus.qtpl:240
+//line lib/promscrape/targetstatus.qtpl:239
 		endpoint := ts.sw.Config.ScrapeURL
 		targetID := getTargetID(ts.sw)
 		lastScrapeDuration := ts.getDurationFromLastScrape()
 
-//line lib/promscrape/targetstatus.qtpl:243
+//line lib/promscrape/targetstatus.qtpl:242
 		qw422016.N().S(`<tr`)
-//line lib/promscrape/targetstatus.qtpl:244
+//line lib/promscrape/targetstatus.qtpl:243
 		if !ts.up {
-//line lib/promscrape/targetstatus.qtpl:244
+//line lib/promscrape/targetstatus.qtpl:243
 			qw422016.N().S(` `)
-//line lib/promscrape/targetstatus.qtpl:244
+//line lib/promscrape/targetstatus.qtpl:243
 			qw422016.N().S(`class="alert alert-danger" role="alert"`)
-//line lib/promscrape/targetstatus.qtpl:244
+//line lib/promscrape/targetstatus.qtpl:243
 		}
-//line lib/promscrape/targetstatus.qtpl:244
+//line lib/promscrape/targetstatus.qtpl:243
 		qw422016.N().S(`><td class="endpoint"><a href="`)
-//line lib/promscrape/targetstatus.qtpl:246
+//line lib/promscrape/targetstatus.qtpl:245
 		qw422016.E().S(endpoint)
-//line lib/promscrape/targetstatus.qtpl:246
+//line lib/promscrape/targetstatus.qtpl:245
 		qw422016.N().S(`" target="_blank">`)
-//line lib/promscrape/targetstatus.qtpl:246
+//line lib/promscrape/targetstatus.qtpl:245
 		qw422016.E().S(endpoint)
-//line lib/promscrape/targetstatus.qtpl:246
+//line lib/promscrape/targetstatus.qtpl:245
 		qw422016.N().S(`</a> (<a href="target_response?id=`)
-//line lib/promscrape/targetstatus.qtpl:247
+//line lib/promscrape/targetstatus.qtpl:246
 		qw422016.E().S(targetID)
-//line lib/promscrape/targetstatus.qtpl:247
+//line lib/promscrape/targetstatus.qtpl:246
 		qw422016.N().S(`" target="_blank"title="click to fetch target response on behalf of the scraper">response</a>)</td><td>`)
-//line lib/promscrape/targetstatus.qtpl:252
+//line lib/promscrape/targetstatus.qtpl:251
 		if ts.up {
-//line lib/promscrape/targetstatus.qtpl:252
+//line lib/promscrape/targetstatus.qtpl:251
 			qw422016.N().S(`<span class="badge bg-success">UP</span>`)
-//line lib/promscrape/targetstatus.qtpl:254
+//line lib/promscrape/targetstatus.qtpl:253
 		} else {
-//line lib/promscrape/targetstatus.qtpl:254
+//line lib/promscrape/targetstatus.qtpl:253
 			qw422016.N().S(`<span class="badge bg-danger">DOWN</span>`)
-//line lib/promscrape/targetstatus.qtpl:256
+//line lib/promscrape/targetstatus.qtpl:255
 		}
-//line lib/promscrape/targetstatus.qtpl:256
+//line lib/promscrape/targetstatus.qtpl:255
 		qw422016.N().S(`</td><td class="labels"><div title="click to show original labels"onclick="document.getElementById('original-labels-`)
-//line lib/promscrape/targetstatus.qtpl:260
+//line lib/promscrape/targetstatus.qtpl:259
 		qw422016.E().S(targetID)
-//line lib/promscrape/targetstatus.qtpl:260
+//line lib/promscrape/targetstatus.qtpl:259
 		qw422016.N().S(`').style.display='block'">`)
-//line lib/promscrape/targetstatus.qtpl:261
-		streamformatLabel(qw422016, promrelabel.FinalizeLabels(nil, ts.sw.Config.Labels))
-//line lib/promscrape/targetstatus.qtpl:261
+//line lib/promscrape/targetstatus.qtpl:260
+		streamformatLabels(qw422016, ts.sw.Config.Labels)
+//line lib/promscrape/targetstatus.qtpl:260
 		qw422016.N().S(`</div><div style="display:none" id="original-labels-`)
-//line lib/promscrape/targetstatus.qtpl:263
+//line lib/promscrape/targetstatus.qtpl:262
 		qw422016.E().S(targetID)
-//line lib/promscrape/targetstatus.qtpl:263
+//line lib/promscrape/targetstatus.qtpl:262
 		qw422016.N().S(`">`)
-//line lib/promscrape/targetstatus.qtpl:264
-		streamformatLabel(qw422016, ts.sw.Config.OriginalLabels)
-//line lib/promscrape/targetstatus.qtpl:264
+//line lib/promscrape/targetstatus.qtpl:263
+		streamformatLabels(qw422016, ts.sw.Config.OriginalLabels)
+//line lib/promscrape/targetstatus.qtpl:263
 		qw422016.N().S(`</div></td><td>`)
-//line lib/promscrape/targetstatus.qtpl:267
+//line lib/promscrape/targetstatus.qtpl:266
 		qw422016.N().D(ts.scrapesTotal)
+//line lib/promscrape/targetstatus.qtpl:266
+		qw422016.N().S(`</td><td>`)
+//line lib/promscrape/targetstatus.qtpl:267
+		qw422016.N().D(ts.scrapesFailed)
 //line lib/promscrape/targetstatus.qtpl:267
 		qw422016.N().S(`</td><td>`)
-//line lib/promscrape/targetstatus.qtpl:268
-		qw422016.N().D(ts.scrapesFailed)
-//line lib/promscrape/targetstatus.qtpl:268
-		qw422016.N().S(`</td><td>`)
-//line lib/promscrape/targetstatus.qtpl:270
+//line lib/promscrape/targetstatus.qtpl:269
 		if lastScrapeDuration < 365*24*time.Hour {
-//line lib/promscrape/targetstatus.qtpl:271
+//line lib/promscrape/targetstatus.qtpl:270
 			qw422016.N().D(int(lastScrapeDuration.Milliseconds()))
-//line lib/promscrape/targetstatus.qtpl:271
+//line lib/promscrape/targetstatus.qtpl:270
 			qw422016.N().S(`ms ago`)
-//line lib/promscrape/targetstatus.qtpl:272
+//line lib/promscrape/targetstatus.qtpl:271
 		} else {
-//line lib/promscrape/targetstatus.qtpl:272
+//line lib/promscrape/targetstatus.qtpl:271
 			qw422016.N().S(`none`)
-//line lib/promscrape/targetstatus.qtpl:274
+//line lib/promscrape/targetstatus.qtpl:273
 		}
-//line lib/promscrape/targetstatus.qtpl:274
+//line lib/promscrape/targetstatus.qtpl:273
 		qw422016.N().S(`<td>`)
-//line lib/promscrape/targetstatus.qtpl:275
+//line lib/promscrape/targetstatus.qtpl:274
 		qw422016.N().D(int(ts.scrapeDuration))
-//line lib/promscrape/targetstatus.qtpl:275
+//line lib/promscrape/targetstatus.qtpl:274
 		qw422016.N().S(`ms</td><td>`)
-//line lib/promscrape/targetstatus.qtpl:276
+//line lib/promscrape/targetstatus.qtpl:275
 		qw422016.N().D(ts.samplesScraped)
-//line lib/promscrape/targetstatus.qtpl:276
+//line lib/promscrape/targetstatus.qtpl:275
 		qw422016.N().S(`</td><td>`)
-//line lib/promscrape/targetstatus.qtpl:277
+//line lib/promscrape/targetstatus.qtpl:276
 		if ts.err != nil {
-//line lib/promscrape/targetstatus.qtpl:277
+//line lib/promscrape/targetstatus.qtpl:276
 			qw422016.E().S(ts.err.Error())
-//line lib/promscrape/targetstatus.qtpl:277
+//line lib/promscrape/targetstatus.qtpl:276
 		}
-//line lib/promscrape/targetstatus.qtpl:277
+//line lib/promscrape/targetstatus.qtpl:276
 		qw422016.N().S(`</td></tr>`)
-//line lib/promscrape/targetstatus.qtpl:279
+//line lib/promscrape/targetstatus.qtpl:278
 	}
-//line lib/promscrape/targetstatus.qtpl:279
+//line lib/promscrape/targetstatus.qtpl:278
 	qw422016.N().S(`</tbody></table></div></div></div>`)
-//line lib/promscrape/targetstatus.qtpl:285
+//line lib/promscrape/targetstatus.qtpl:284
 }
 
-//line lib/promscrape/targetstatus.qtpl:285
+//line lib/promscrape/targetstatus.qtpl:284
 func writescrapeJobTargets(qq422016 qtio422016.Writer, num int, jts *jobTargetsStatuses) {
-//line lib/promscrape/targetstatus.qtpl:285
+//line lib/promscrape/targetstatus.qtpl:284
 	qw422016 := qt422016.AcquireWriter(qq422016)
-//line lib/promscrape/targetstatus.qtpl:285
+//line lib/promscrape/targetstatus.qtpl:284
 	streamscrapeJobTargets(qw422016, num, jts)
-//line lib/promscrape/targetstatus.qtpl:285
+//line lib/promscrape/targetstatus.qtpl:284
 	qt422016.ReleaseWriter(qw422016)
-//line lib/promscrape/targetstatus.qtpl:285
+//line lib/promscrape/targetstatus.qtpl:284
 }
 
-//line lib/promscrape/targetstatus.qtpl:285
+//line lib/promscrape/targetstatus.qtpl:284
 func scrapeJobTargets(num int, jts *jobTargetsStatuses) string {
-//line lib/promscrape/targetstatus.qtpl:285
+//line lib/promscrape/targetstatus.qtpl:284
 	qb422016 := qt422016.AcquireByteBuffer()
-//line lib/promscrape/targetstatus.qtpl:285
+//line lib/promscrape/targetstatus.qtpl:284
 	writescrapeJobTargets(qb422016, num, jts)
-//line lib/promscrape/targetstatus.qtpl:285
+//line lib/promscrape/targetstatus.qtpl:284
 	qs422016 := string(qb422016.B)
-//line lib/promscrape/targetstatus.qtpl:285
+//line lib/promscrape/targetstatus.qtpl:284
 	qt422016.ReleaseByteBuffer(qb422016)
-//line lib/promscrape/targetstatus.qtpl:285
+//line lib/promscrape/targetstatus.qtpl:284
 	return qs422016
-//line lib/promscrape/targetstatus.qtpl:285
+//line lib/promscrape/targetstatus.qtpl:284
 }
 
-//line lib/promscrape/targetstatus.qtpl:287
+//line lib/promscrape/targetstatus.qtpl:286
 func streamdiscoveredTargets(qw422016 *qt422016.Writer, tsr *targetsStatusResult) {
-//line lib/promscrape/targetstatus.qtpl:288
+//line lib/promscrape/targetstatus.qtpl:287
 	tljs := tsr.getTargetLabelsByJob()
 
-//line lib/promscrape/targetstatus.qtpl:288
+//line lib/promscrape/targetstatus.qtpl:287
 	qw422016.N().S(`<div class="row mt-4"><div class="col-12">`)
-//line lib/promscrape/targetstatus.qtpl:291
+//line lib/promscrape/targetstatus.qtpl:290
 	for i, tlj := range tljs {
-//line lib/promscrape/targetstatus.qtpl:292
+//line lib/promscrape/targetstatus.qtpl:291
 		streamdiscoveredJobTargets(qw422016, i, tlj)
-//line lib/promscrape/targetstatus.qtpl:293
+//line lib/promscrape/targetstatus.qtpl:292
 	}
-//line lib/promscrape/targetstatus.qtpl:293
+//line lib/promscrape/targetstatus.qtpl:292
 	qw422016.N().S(`</div></div>`)
-//line lib/promscrape/targetstatus.qtpl:296
+//line lib/promscrape/targetstatus.qtpl:295
 }
 
-//line lib/promscrape/targetstatus.qtpl:296
+//line lib/promscrape/targetstatus.qtpl:295
 func writediscoveredTargets(qq422016 qtio422016.Writer, tsr *targetsStatusResult) {
-//line lib/promscrape/targetstatus.qtpl:296
+//line lib/promscrape/targetstatus.qtpl:295
 	qw422016 := qt422016.AcquireWriter(qq422016)
-//line lib/promscrape/targetstatus.qtpl:296
+//line lib/promscrape/targetstatus.qtpl:295
 	streamdiscoveredTargets(qw422016, tsr)
-//line lib/promscrape/targetstatus.qtpl:296
+//line lib/promscrape/targetstatus.qtpl:295
 	qt422016.ReleaseWriter(qw422016)
-//line lib/promscrape/targetstatus.qtpl:296
+//line lib/promscrape/targetstatus.qtpl:295
 }
 
-//line lib/promscrape/targetstatus.qtpl:296
+//line lib/promscrape/targetstatus.qtpl:295
 func discoveredTargets(tsr *targetsStatusResult) string {
-//line lib/promscrape/targetstatus.qtpl:296
+//line lib/promscrape/targetstatus.qtpl:295
 	qb422016 := qt422016.AcquireByteBuffer()
-//line lib/promscrape/targetstatus.qtpl:296
+//line lib/promscrape/targetstatus.qtpl:295
 	writediscoveredTargets(qb422016, tsr)
-//line lib/promscrape/targetstatus.qtpl:296
+//line lib/promscrape/targetstatus.qtpl:295
 	qs422016 := string(qb422016.B)
-//line lib/promscrape/targetstatus.qtpl:296
+//line lib/promscrape/targetstatus.qtpl:295
 	qt422016.ReleaseByteBuffer(qb422016)
-//line lib/promscrape/targetstatus.qtpl:296
+//line lib/promscrape/targetstatus.qtpl:295
 	return qs422016
-//line lib/promscrape/targetstatus.qtpl:296
+//line lib/promscrape/targetstatus.qtpl:295
 }
 
-//line lib/promscrape/targetstatus.qtpl:298
+//line lib/promscrape/targetstatus.qtpl:297
 func streamdiscoveredJobTargets(qw422016 *qt422016.Writer, num int, tlj *targetLabelsByJob) {
-//line lib/promscrape/targetstatus.qtpl:298
+//line lib/promscrape/targetstatus.qtpl:297
 	qw422016.N().S(`<h4><span class="me-2">`)
-//line lib/promscrape/targetstatus.qtpl:300
+//line lib/promscrape/targetstatus.qtpl:299
 	qw422016.E().S(tlj.jobName)
-//line lib/promscrape/targetstatus.qtpl:300
+//line lib/promscrape/targetstatus.qtpl:299
 	qw422016.N().S(` `)
-//line lib/promscrape/targetstatus.qtpl:300
+//line lib/promscrape/targetstatus.qtpl:299
 	qw422016.N().S(`(`)
-//line lib/promscrape/targetstatus.qtpl:300
+//line lib/promscrape/targetstatus.qtpl:299
 	qw422016.N().D(tlj.activeTargets)
-//line lib/promscrape/targetstatus.qtpl:300
+//line lib/promscrape/targetstatus.qtpl:299
 	qw422016.N().S(`/`)
-//line lib/promscrape/targetstatus.qtpl:300
+//line lib/promscrape/targetstatus.qtpl:299
 	qw422016.N().D(tlj.activeTargets + tlj.droppedTargets)
-//line lib/promscrape/targetstatus.qtpl:300
+//line lib/promscrape/targetstatus.qtpl:299
 	qw422016.N().S(` `)
-//line lib/promscrape/targetstatus.qtpl:300
+//line lib/promscrape/targetstatus.qtpl:299
 	qw422016.N().S(`active)</span>`)
-//line lib/promscrape/targetstatus.qtpl:301
+//line lib/promscrape/targetstatus.qtpl:300
 	streamshowHideScrapeJobButtons(qw422016, num)
-//line lib/promscrape/targetstatus.qtpl:301
+//line lib/promscrape/targetstatus.qtpl:300
 	qw422016.N().S(`</h4><div id="scrape-job-`)
-//line lib/promscrape/targetstatus.qtpl:303
+//line lib/promscrape/targetstatus.qtpl:302
 	qw422016.N().D(num)
-//line lib/promscrape/targetstatus.qtpl:303
+//line lib/promscrape/targetstatus.qtpl:302
 	qw422016.N().S(`" class="scrape-job table-responsive"><table class="table table-striped table-hover table-bordered table-sm"><thead><tr><th scope="col" style="width: 5%">Status</th><th scope="col" style="width: 65%">Discovered Labels</th><th scope="col" style="width: 30%">Target Labels</th></tr></thead><tbody>`)
-//line lib/promscrape/targetstatus.qtpl:313
+//line lib/promscrape/targetstatus.qtpl:312
 	for _, t := range tlj.targets {
-//line lib/promscrape/targetstatus.qtpl:313
+//line lib/promscrape/targetstatus.qtpl:312
 		qw422016.N().S(`<tr`)
-//line lib/promscrape/targetstatus.qtpl:315
+//line lib/promscrape/targetstatus.qtpl:314
 		if !t.up {
-//line lib/promscrape/targetstatus.qtpl:316
+//line lib/promscrape/targetstatus.qtpl:315
 			qw422016.N().S(` `)
-//line lib/promscrape/targetstatus.qtpl:316
+//line lib/promscrape/targetstatus.qtpl:315
 			qw422016.N().S(`role="alert"`)
-//line lib/promscrape/targetstatus.qtpl:316
+//line lib/promscrape/targetstatus.qtpl:315
 			qw422016.N().S(` `)
-//line lib/promscrape/targetstatus.qtpl:317
-			if len(t.labels) > 0 {
-//line lib/promscrape/targetstatus.qtpl:317
+//line lib/promscrape/targetstatus.qtpl:316
+			if t.labels.Len() > 0 {
+//line lib/promscrape/targetstatus.qtpl:316
 				qw422016.N().S(`class="alert alert-danger"`)
-//line lib/promscrape/targetstatus.qtpl:319
+//line lib/promscrape/targetstatus.qtpl:318
 			} else {
-//line lib/promscrape/targetstatus.qtpl:319
+//line lib/promscrape/targetstatus.qtpl:318
 				qw422016.N().S(`class="alert alert-warning"`)
-//line lib/promscrape/targetstatus.qtpl:321
+//line lib/promscrape/targetstatus.qtpl:320
 			}
-//line lib/promscrape/targetstatus.qtpl:322
+//line lib/promscrape/targetstatus.qtpl:321
 		}
-//line lib/promscrape/targetstatus.qtpl:322
+//line lib/promscrape/targetstatus.qtpl:321
 		qw422016.N().S(`><td>`)
-//line lib/promscrape/targetstatus.qtpl:325
+//line lib/promscrape/targetstatus.qtpl:324
 		if t.up {
-//line lib/promscrape/targetstatus.qtpl:325
+//line lib/promscrape/targetstatus.qtpl:324
 			qw422016.N().S(`<span class="badge bg-success">UP</span>`)
-//line lib/promscrape/targetstatus.qtpl:327
-		} else if len(t.labels) > 0 {
-//line lib/promscrape/targetstatus.qtpl:327
+//line lib/promscrape/targetstatus.qtpl:326
+		} else if t.labels.Len() > 0 {
+//line lib/promscrape/targetstatus.qtpl:326
 			qw422016.N().S(`<span class="badge bg-danger">DOWN</span>`)
-//line lib/promscrape/targetstatus.qtpl:329
+//line lib/promscrape/targetstatus.qtpl:328
 		} else {
-//line lib/promscrape/targetstatus.qtpl:329
+//line lib/promscrape/targetstatus.qtpl:328
 			qw422016.N().S(`<span class="badge bg-warning">DROPPED</span>`)
-//line lib/promscrape/targetstatus.qtpl:331
+//line lib/promscrape/targetstatus.qtpl:330
 		}
-//line lib/promscrape/targetstatus.qtpl:331
+//line lib/promscrape/targetstatus.qtpl:330
 		qw422016.N().S(`</td><td class="labels">`)
-//line lib/promscrape/targetstatus.qtpl:334
-		streamformatLabel(qw422016, t.discoveredLabels)
-//line lib/promscrape/targetstatus.qtpl:334
+//line lib/promscrape/targetstatus.qtpl:333
+		streamformatLabels(qw422016, t.discoveredLabels)
+//line lib/promscrape/targetstatus.qtpl:333
 		qw422016.N().S(`</td><td class="labels">`)
-//line lib/promscrape/targetstatus.qtpl:337
-		streamformatLabel(qw422016, promrelabel.FinalizeLabels(nil, t.labels))
-//line lib/promscrape/targetstatus.qtpl:337
+//line lib/promscrape/targetstatus.qtpl:336
+		streamformatLabels(qw422016, t.labels)
+//line lib/promscrape/targetstatus.qtpl:336
 		qw422016.N().S(`</td></tr>`)
-//line lib/promscrape/targetstatus.qtpl:340
+//line lib/promscrape/targetstatus.qtpl:339
 	}
-//line lib/promscrape/targetstatus.qtpl:340
+//line lib/promscrape/targetstatus.qtpl:339
 	qw422016.N().S(`</tbody></table></div>`)
-//line lib/promscrape/targetstatus.qtpl:344
+//line lib/promscrape/targetstatus.qtpl:343
 }
 
-//line lib/promscrape/targetstatus.qtpl:344
+//line lib/promscrape/targetstatus.qtpl:343
 func writediscoveredJobTargets(qq422016 qtio422016.Writer, num int, tlj *targetLabelsByJob) {
-//line lib/promscrape/targetstatus.qtpl:344
+//line lib/promscrape/targetstatus.qtpl:343
 	qw422016 := qt422016.AcquireWriter(qq422016)
-//line lib/promscrape/targetstatus.qtpl:344
+//line lib/promscrape/targetstatus.qtpl:343
 	streamdiscoveredJobTargets(qw422016, num, tlj)
-//line lib/promscrape/targetstatus.qtpl:344
+//line lib/promscrape/targetstatus.qtpl:343
 	qt422016.ReleaseWriter(qw422016)
-//line lib/promscrape/targetstatus.qtpl:344
+//line lib/promscrape/targetstatus.qtpl:343
 }
 
-//line lib/promscrape/targetstatus.qtpl:344
+//line lib/promscrape/targetstatus.qtpl:343
 func discoveredJobTargets(num int, tlj *targetLabelsByJob) string {
-//line lib/promscrape/targetstatus.qtpl:344
+//line lib/promscrape/targetstatus.qtpl:343
 	qb422016 := qt422016.AcquireByteBuffer()
-//line lib/promscrape/targetstatus.qtpl:344
+//line lib/promscrape/targetstatus.qtpl:343
 	writediscoveredJobTargets(qb422016, num, tlj)
-//line lib/promscrape/targetstatus.qtpl:344
+//line lib/promscrape/targetstatus.qtpl:343
 	qs422016 := string(qb422016.B)
-//line lib/promscrape/targetstatus.qtpl:344
+//line lib/promscrape/targetstatus.qtpl:343
 	qt422016.ReleaseByteBuffer(qb422016)
-//line lib/promscrape/targetstatus.qtpl:344
+//line lib/promscrape/targetstatus.qtpl:343
 	return qs422016
-//line lib/promscrape/targetstatus.qtpl:344
+//line lib/promscrape/targetstatus.qtpl:343
 }
 
-//line lib/promscrape/targetstatus.qtpl:346
+//line lib/promscrape/targetstatus.qtpl:345
 func streamshowHideScrapeJobButtons(qw422016 *qt422016.Writer, num int) {
-//line lib/promscrape/targetstatus.qtpl:346
+//line lib/promscrape/targetstatus.qtpl:345
 	qw422016.N().S(`<button type="button" class="btn btn-primary btn-sm me-1"onclick="document.getElementById('scrape-job-`)
-//line lib/promscrape/targetstatus.qtpl:348
+//line lib/promscrape/targetstatus.qtpl:347
 	qw422016.N().D(num)
-//line lib/promscrape/targetstatus.qtpl:348
+//line lib/promscrape/targetstatus.qtpl:347
 	qw422016.N().S(`').style.display='none'">collapse</button><button type="button" class="btn btn-secondary btn-sm me-1"onclick="document.getElementById('scrape-job-`)
-//line lib/promscrape/targetstatus.qtpl:352
+//line lib/promscrape/targetstatus.qtpl:351
 	qw422016.N().D(num)
-//line lib/promscrape/targetstatus.qtpl:352
+//line lib/promscrape/targetstatus.qtpl:351
 	qw422016.N().S(`').style.display='block'">expand</button>`)
-//line lib/promscrape/targetstatus.qtpl:355
+//line lib/promscrape/targetstatus.qtpl:354
 }
 
-//line lib/promscrape/targetstatus.qtpl:355
+//line lib/promscrape/targetstatus.qtpl:354
 func writeshowHideScrapeJobButtons(qq422016 qtio422016.Writer, num int) {
-//line lib/promscrape/targetstatus.qtpl:355
+//line lib/promscrape/targetstatus.qtpl:354
 	qw422016 := qt422016.AcquireWriter(qq422016)
-//line lib/promscrape/targetstatus.qtpl:355
+//line lib/promscrape/targetstatus.qtpl:354
 	streamshowHideScrapeJobButtons(qw422016, num)
-//line lib/promscrape/targetstatus.qtpl:355
+//line lib/promscrape/targetstatus.qtpl:354
 	qt422016.ReleaseWriter(qw422016)
-//line lib/promscrape/targetstatus.qtpl:355
+//line lib/promscrape/targetstatus.qtpl:354
 }
 
-//line lib/promscrape/targetstatus.qtpl:355
+//line lib/promscrape/targetstatus.qtpl:354
 func showHideScrapeJobButtons(num int) string {
-//line lib/promscrape/targetstatus.qtpl:355
+//line lib/promscrape/targetstatus.qtpl:354
 	qb422016 := qt422016.AcquireByteBuffer()
-//line lib/promscrape/targetstatus.qtpl:355
+//line lib/promscrape/targetstatus.qtpl:354
 	writeshowHideScrapeJobButtons(qb422016, num)
-//line lib/promscrape/targetstatus.qtpl:355
+//line lib/promscrape/targetstatus.qtpl:354
 	qs422016 := string(qb422016.B)
-//line lib/promscrape/targetstatus.qtpl:355
+//line lib/promscrape/targetstatus.qtpl:354
 	qt422016.ReleaseByteBuffer(qb422016)
-//line lib/promscrape/targetstatus.qtpl:355
+//line lib/promscrape/targetstatus.qtpl:354
 	return qs422016
-//line lib/promscrape/targetstatus.qtpl:355
+//line lib/promscrape/targetstatus.qtpl:354
 }
 
-//line lib/promscrape/targetstatus.qtpl:357
+//line lib/promscrape/targetstatus.qtpl:356
 func streamqueryArgs(qw422016 *qt422016.Writer, filter *requestFilter, override map[string]string) {
-//line lib/promscrape/targetstatus.qtpl:359
+//line lib/promscrape/targetstatus.qtpl:358
 	showOnlyUnhealthy := "false"
 	if filter.showOnlyUnhealthy {
 		showOnlyUnhealthy = "true"
@@ -981,43 +980,46 @@ func streamqueryArgs(qw422016 *qt422016.Writer, filter *requestFilter, override
 		qa[k] = []string{v}
 	}
 
-//line lib/promscrape/targetstatus.qtpl:376
+//line lib/promscrape/targetstatus.qtpl:375
 	qw422016.E().S(qa.Encode())
-//line lib/promscrape/targetstatus.qtpl:377
+//line lib/promscrape/targetstatus.qtpl:376
 }
 
-//line lib/promscrape/targetstatus.qtpl:377
+//line lib/promscrape/targetstatus.qtpl:376
 func writequeryArgs(qq422016 qtio422016.Writer, filter *requestFilter, override map[string]string) {
-//line lib/promscrape/targetstatus.qtpl:377
+//line lib/promscrape/targetstatus.qtpl:376
 	qw422016 := qt422016.AcquireWriter(qq422016)
-//line lib/promscrape/targetstatus.qtpl:377
+//line lib/promscrape/targetstatus.qtpl:376
 	streamqueryArgs(qw422016, filter, override)
-//line lib/promscrape/targetstatus.qtpl:377
+//line lib/promscrape/targetstatus.qtpl:376
 	qt422016.ReleaseWriter(qw422016)
-//line lib/promscrape/targetstatus.qtpl:377
+//line lib/promscrape/targetstatus.qtpl:376
 }
 
-//line lib/promscrape/targetstatus.qtpl:377
+//line lib/promscrape/targetstatus.qtpl:376
 func queryArgs(filter *requestFilter, override map[string]string) string {
-//line lib/promscrape/targetstatus.qtpl:377
+//line lib/promscrape/targetstatus.qtpl:376
 	qb422016 := qt422016.AcquireByteBuffer()
-//line lib/promscrape/targetstatus.qtpl:377
+//line lib/promscrape/targetstatus.qtpl:376
 	writequeryArgs(qb422016, filter, override)
-//line lib/promscrape/targetstatus.qtpl:377
+//line lib/promscrape/targetstatus.qtpl:376
 	qs422016 := string(qb422016.B)
-//line lib/promscrape/targetstatus.qtpl:377
+//line lib/promscrape/targetstatus.qtpl:376
 	qt422016.ReleaseByteBuffer(qb422016)
-//line lib/promscrape/targetstatus.qtpl:377
+//line lib/promscrape/targetstatus.qtpl:376
 	return qs422016
-//line lib/promscrape/targetstatus.qtpl:377
+//line lib/promscrape/targetstatus.qtpl:376
 }
 
+//line lib/promscrape/targetstatus.qtpl:378
+func streamformatLabels(qw422016 *qt422016.Writer, labels *promutils.Labels) {
 //line lib/promscrape/targetstatus.qtpl:379
-func streamformatLabel(qw422016 *qt422016.Writer, labels []prompbmarshal.Label) {
+	labelsList := labels.GetLabels()
+
 //line lib/promscrape/targetstatus.qtpl:379
 	qw422016.N().S(`{`)
 //line lib/promscrape/targetstatus.qtpl:381
-	for i, label := range labels {
+	for i, label := range labelsList {
 //line lib/promscrape/targetstatus.qtpl:382
 		qw422016.E().S(label.Name)
 //line lib/promscrape/targetstatus.qtpl:382
@@ -1025,7 +1027,7 @@ func streamformatLabel(qw422016 *qt422016.Writer, labels []prompbmarshal.Label)
 //line lib/promscrape/targetstatus.qtpl:382
 		qw422016.E().Q(label.Value)
 //line lib/promscrape/targetstatus.qtpl:383
-		if i+1 < len(labels) {
+		if i+1 < len(labelsList) {
 //line lib/promscrape/targetstatus.qtpl:383
 			qw422016.N().S(`,`)
 //line lib/promscrape/targetstatus.qtpl:383
@@ -1040,22 +1042,22 @@ func streamformatLabel(qw422016 *qt422016.Writer, labels []prompbmarshal.Label)
 }
 
 //line lib/promscrape/targetstatus.qtpl:386
-func writeformatLabel(qq422016 qtio422016.Writer, labels []prompbmarshal.Label) {
+func writeformatLabels(qq422016 qtio422016.Writer, labels *promutils.Labels) {
 //line lib/promscrape/targetstatus.qtpl:386
 	qw422016 := qt422016.AcquireWriter(qq422016)
 //line lib/promscrape/targetstatus.qtpl:386
-	streamformatLabel(qw422016, labels)
+	streamformatLabels(qw422016, labels)
 //line lib/promscrape/targetstatus.qtpl:386
 	qt422016.ReleaseWriter(qw422016)
 //line lib/promscrape/targetstatus.qtpl:386
 }
 
 //line lib/promscrape/targetstatus.qtpl:386
-func formatLabel(labels []prompbmarshal.Label) string {
+func formatLabels(labels *promutils.Labels) string {
 //line lib/promscrape/targetstatus.qtpl:386
 	qb422016 := qt422016.AcquireByteBuffer()
 //line lib/promscrape/targetstatus.qtpl:386
-	writeformatLabel(qb422016, labels)
+	writeformatLabels(qb422016, labels)
 //line lib/promscrape/targetstatus.qtpl:386
 	qs422016 := string(qb422016.B)
 //line lib/promscrape/targetstatus.qtpl:386
diff --git a/lib/promutils/labels.go b/lib/promutils/labels.go
new file mode 100644
index 0000000000..f5b7163de2
--- /dev/null
+++ b/lib/promutils/labels.go
@@ -0,0 +1,328 @@
+package promutils
+
+import (
+	"encoding/json"
+	"fmt"
+	"sort"
+	"strconv"
+	"strings"
+	"sync"
+
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/prometheus"
+)
+
+// Labels contains Prometheus labels.
+type Labels struct {
+	Labels []prompbmarshal.Label
+}
+
+// NewLabels returns Labels with the given capacity.
+func NewLabels(capacity int) *Labels {
+	return &Labels{
+		Labels: make([]prompbmarshal.Label, 0, capacity),
+	}
+}
+
+// NewLabelsFromMap returns Labels generated from m.
+func NewLabelsFromMap(m map[string]string) *Labels {
+	var x Labels
+	x.InitFromMap(m)
+	return &x
+}
+
+// MarshalYAML implements yaml.Marshaler interface.
+func (x *Labels) MarshalYAML() (interface{}, error) {
+	m := x.toMap()
+	return m, nil
+}
+
+// UnmarshalYAML implements yaml.Unmarshaler interface.
+func (x *Labels) UnmarshalYAML(unmarshal func(interface{}) error) error {
+	var m map[string]string
+	if err := unmarshal(&m); err != nil {
+		return err
+	}
+	x.InitFromMap(m)
+	return nil
+}
+
+// MarshalJSON returns JSON respresentation for x.
+func (x *Labels) MarshalJSON() ([]byte, error) {
+	m := x.toMap()
+	return json.Marshal(m)
+}
+
+// UnmarshalJSON unmarshals JSON from data.
+func (x *Labels) UnmarshalJSON(data []byte) error {
+	var m map[string]string
+	if err := json.Unmarshal(data, &m); err != nil {
+		return err
+	}
+	x.InitFromMap(m)
+	return nil
+}
+
+// InitFromMap initializes x from m.
+func (x *Labels) InitFromMap(m map[string]string) {
+	x.Reset()
+	for name, value := range m {
+		x.Add(name, value)
+	}
+	x.Sort()
+}
+
+func (x *Labels) toMap() map[string]string {
+	labels := x.GetLabels()
+	m := make(map[string]string, len(labels))
+	for _, label := range labels {
+		m[label.Name] = label.Value
+	}
+	return m
+}
+
+// GetLabels returns the list of labels from x.
+func (x *Labels) GetLabels() []prompbmarshal.Label {
+	if x == nil {
+		return nil
+	}
+	return x.Labels
+}
+
+// String returns string representation of x.
+func (x *Labels) String() string {
+	labels := x.GetLabels()
+	// Calculate the required memory for storing serialized labels.
+	n := 2 // for `{...}`
+	for _, label := range labels {
+		n += len(label.Name) + len(label.Value)
+		n += 4 // for `="...",`
+	}
+	b := make([]byte, 0, n)
+	b = append(b, '{')
+	for i, label := range labels {
+		b = append(b, label.Name...)
+		b = append(b, '=')
+		b = strconv.AppendQuote(b, label.Value)
+		if i+1 < len(labels) {
+			b = append(b, ',')
+		}
+	}
+	b = append(b, '}')
+	return bytesutil.ToUnsafeString(b)
+}
+
+// Reset resets x.
+func (x *Labels) Reset() {
+	cleanLabels(x.Labels)
+	x.Labels = x.Labels[:0]
+}
+
+// Clone returns a clone of x.
+func (x *Labels) Clone() *Labels {
+	srcLabels := x.GetLabels()
+	labels := append([]prompbmarshal.Label{}, srcLabels...)
+	return &Labels{
+		Labels: labels,
+	}
+}
+
+// Sort sorts x labels in alphabetical order of their names.
+func (x *Labels) Sort() {
+	if !sort.IsSorted(x) {
+		sort.Sort(x)
+	}
+}
+
+// SortStable sorts x labels in alphabetical order of their name using stable sort.
+func (x *Labels) SortStable() {
+	if !sort.IsSorted(x) {
+		sort.Stable(x)
+	}
+}
+
+// Len returns the number of labels in x.
+func (x *Labels) Len() int {
+	labels := x.GetLabels()
+	return len(labels)
+}
+
+// Less compares label names at i and j index.
+func (x *Labels) Less(i, j int) bool {
+	labels := x.Labels
+	return labels[i].Name < labels[j].Name
+}
+
+// Swap swaps labels at i and j index.
+func (x *Labels) Swap(i, j int) {
+	labels := x.Labels
+	labels[i], labels[j] = labels[j], labels[i]
+}
+
+// Add adds name=value label to x.
+func (x *Labels) Add(name, value string) {
+	x.Labels = append(x.Labels, prompbmarshal.Label{
+		Name:  name,
+		Value: value,
+	})
+}
+
+// AddFrom adds src labels to x.
+func (x *Labels) AddFrom(src *Labels) {
+	for _, label := range src.GetLabels() {
+		x.Add(label.Name, label.Value)
+	}
+}
+
+// Get returns value for label with the given name.
+func (x *Labels) Get(name string) string {
+	labels := x.GetLabels()
+	for _, label := range labels {
+		if label.Name == name {
+			return label.Value
+		}
+	}
+	return ""
+}
+
+// InternStrings interns all the strings used in x labels.
+func (x *Labels) InternStrings() {
+	labels := x.GetLabels()
+	for _, label := range labels {
+		label.Name = bytesutil.InternString(label.Name)
+		label.Value = bytesutil.InternString(label.Value)
+	}
+}
+
+// RemoveDuplicates removes labels with duplicate names.
+func (x *Labels) RemoveDuplicates() {
+	if x.Len() < 2 {
+		return
+	}
+	// Remove duplicate labels if any.
+	// Stable sorting is needed in order to preserve the order for labels with identical names.
+	// This is needed in order to remove labels with duplicate names other than the last one.
+	x.SortStable()
+	labels := x.Labels
+	prevName := labels[0].Name
+	hasDuplicateLabels := false
+	for _, label := range labels[1:] {
+		if label.Name == prevName {
+			hasDuplicateLabels = true
+			break
+		}
+		prevName = label.Name
+	}
+	if !hasDuplicateLabels {
+		return
+	}
+	prevName = labels[0].Name
+	tmp := labels[:1]
+	for _, label := range labels[1:] {
+		if label.Name == prevName {
+			tmp[len(tmp)-1] = label
+		} else {
+			tmp = append(tmp, label)
+			prevName = label.Name
+		}
+	}
+	cleanLabels(labels[len(tmp):])
+	x.Labels = tmp
+}
+
+// RemoveMetaLabels removes all the `__meta_` labels from x.
+//
+// See https://www.robustperception.io/life-of-a-label fo details.
+func (x *Labels) RemoveMetaLabels() {
+	src := x.Labels
+	dst := x.Labels[:0]
+	for _, label := range src {
+		if strings.HasPrefix(label.Name, "__meta_") {
+			continue
+		}
+		dst = append(dst, label)
+	}
+	cleanLabels(src[len(dst):])
+	x.Labels = dst
+}
+
+// RemoveLabelsWithDoubleUnderscorePrefix removes labels with "__" prefix from x.
+func (x *Labels) RemoveLabelsWithDoubleUnderscorePrefix() {
+	src := x.Labels
+	dst := x.Labels[:0]
+	for _, label := range src {
+		name := label.Name
+		// A hack: do not delete __vm_filepath label, since it is used by internal logic for FileSDConfig.
+		if strings.HasPrefix(name, "__") && name != "__vm_filepath" {
+			continue
+		}
+		dst = append(dst, label)
+	}
+	cleanLabels(src[len(dst):])
+	x.Labels = dst
+}
+
+func cleanLabels(labels []prompbmarshal.Label) {
+	for i := range labels {
+		label := &labels[i]
+		label.Name = ""
+		label.Value = ""
+	}
+}
+
+// GetLabels returns and empty Labels instance from the pool.
+//
+// The returned Labels instance must be returned to pool via PutLabels() when no longer needed.
+func GetLabels() *Labels {
+	v := labelsPool.Get()
+	if v == nil {
+		return &Labels{}
+	}
+	return v.(*Labels)
+}
+
+// PutLabels returns x, which has been obtained via GetLabels(), to the pool.
+//
+// The x mustn't be used after returning to the pool.
+func PutLabels(x *Labels) {
+	x.Reset()
+	labelsPool.Put(x)
+}
+
+var labelsPool sync.Pool
+
+// NewLabelsFromString creates labels from s, which can have the form `metric{labels}`.
+//
+// This function must be used only in tests
+func NewLabelsFromString(metricWithLabels string) *Labels {
+	stripDummyMetric := false
+	if strings.HasPrefix(metricWithLabels, "{") {
+		// Add a dummy metric name, since the parser needs it
+		metricWithLabels = "dummy_metric" + metricWithLabels
+		stripDummyMetric = true
+	}
+	// add a value to metricWithLabels, so it could be parsed by prometheus protocol parser.
+	s := metricWithLabels + " 123"
+	var rows prometheus.Rows
+	var err error
+	rows.UnmarshalWithErrLogger(s, func(s string) {
+		err = fmt.Errorf("error during metric parse: %s", s)
+	})
+	if err != nil {
+		logger.Panicf("BUG: cannot parse %q: %s", metricWithLabels, err)
+	}
+	if len(rows.Rows) != 1 {
+		logger.Panicf("BUG: unexpected number of rows parsed; got %d; want 1", len(rows.Rows))
+	}
+	r := rows.Rows[0]
+	var x Labels
+	if !stripDummyMetric {
+		x.Add("__name__", r.Metric)
+	}
+	for _, tag := range r.Tags {
+		x.Add(tag.Key, tag.Value)
+	}
+	return &x
+}
diff --git a/lib/promutils/labels_test.go b/lib/promutils/labels_test.go
new file mode 100644
index 0000000000..f218d5f866
--- /dev/null
+++ b/lib/promutils/labels_test.go
@@ -0,0 +1,177 @@
+package promutils
+
+import (
+	"encoding/json"
+	"testing"
+
+	"gopkg.in/yaml.v2"
+)
+
+func TestLabels(t *testing.T) {
+	x := NewLabels(2)
+	x.Add("job", "bar")
+	x.Add("instance", "foo")
+	v := x.Get("instance")
+	if v != "foo" {
+		t.Fatalf("unexpected value obtained; got %q; want %q", v, "foo")
+	}
+	v = x.Get("non-existing-label")
+	if v != "" {
+		t.Fatalf("unexpected non-empty value obtained for non-existing label: %q", v)
+	}
+	n := x.Len()
+	if n != 2 {
+		t.Fatalf("unexpected labels len; got %d; want 2", n)
+	}
+	x.Sort()
+	x.SortStable()
+	s, err := yaml.Marshal(x)
+	if err != nil {
+		t.Fatalf("unexpected error in yaml.Marshal: %s", err)
+	}
+	sExpected := "instance: foo\njob: bar\n"
+	if string(s) != sExpected {
+		t.Fatalf("unexpected marshaled value;\ngot\n%s\nwant\n%q", s, sExpected)
+	}
+	x1 := GetLabels()
+	if err := yaml.Unmarshal(s, &x1); err != nil {
+		t.Fatalf("unexpected error in yaml.Unmarshal: %s", err)
+	}
+	x1.InternStrings()
+	s, err = yaml.Marshal(&x1)
+	if err != nil {
+		t.Fatalf("unexpected error in yaml.Marshal: %s", err)
+	}
+	if string(s) != sExpected {
+		t.Fatalf("unexpected marshaled value;\ngot\n%s\nwant\n%q", s, sExpected)
+	}
+	PutLabels(x1)
+	x1 = nil
+	if n = x1.Len(); n != 0 {
+		t.Fatalf("unexpected len for empty labels: %d", n)
+	}
+	x1 = GetLabels()
+	x2 := x.Clone()
+	s, err = yaml.Marshal(x2)
+	if err != nil {
+		t.Fatalf("cannot marshal cloned labels")
+	}
+	if string(s) != sExpected {
+		t.Fatalf("unexpected marshaled value;\ngot\n%s\nwant\n%q", s, sExpected)
+	}
+	s2 := x2.String()
+	s2Expected := `{instance="foo",job="bar"}`
+	if s2 != s2Expected {
+		t.Fatalf("unexpected string representation for labels;\ngot\n%s\nwant\n%s", s2, s2Expected)
+	}
+}
+
+func TestLabelsUnmarshalYAMLFailure(t *testing.T) {
+	f := func(s string) {
+		t.Helper()
+		var x Labels
+		if err := yaml.Unmarshal([]byte(s), &x); err == nil {
+			t.Fatalf("expecting non-nil error")
+		}
+	}
+	f("foobar")
+	f("[foo,bar]")
+	f("{foo:[bar]}")
+	f("[aa")
+}
+
+func TestLabelsUnmarshalJSONSuccess(t *testing.T) {
+	f := func(s string) {
+		t.Helper()
+		var x Labels
+		if err := json.Unmarshal([]byte(s), &x); err != nil {
+			t.Fatalf("unexpected error in json.Unmarshal: %s", err)
+		}
+		data, err := json.Marshal(&x)
+		if err != nil {
+			t.Fatalf("json.Marshal error: %s", err)
+		}
+		if string(data) != s {
+			t.Fatalf("unexpected marshaled JSON;\ngot\n%s\nwant\n%s", data, s)
+		}
+	}
+	f(`{}`)
+	f(`{"foo":"bar"}`)
+	f(`{"a":"y","x":"b"}`)
+}
+
+func TestLabelsUnmarshalJSONFailure(t *testing.T) {
+	f := func(s string) {
+		t.Helper()
+		var x Labels
+		if err := json.Unmarshal([]byte(s), &x); err == nil {
+			t.Fatalf("expecting non-nil error")
+		}
+	}
+	f("foobar")
+	f("[1,2]")
+	f(`{"foo":123}`)
+	f(`{"foo"`)
+	f(`"ff`)
+}
+
+func TestLabelsRemoveDuplicates(t *testing.T) {
+	var x Labels
+	x.Add("foo", "bar")
+	x.Add("foo", "baz")
+	x.Add("foo", "123")
+	x.Add("bar", "a")
+	x.RemoveDuplicates()
+	s := x.String()
+	sExpected := `{bar="a",foo="123"}`
+	if s != sExpected {
+		t.Fatalf("unexpected result;\ngot\n%s\nwant\n%s", s, sExpected)
+	}
+}
+
+func TestLabelsAddFrom(t *testing.T) {
+	var a, b Labels
+	a.Add("z", "x")
+	a.Add("foo", "bar")
+	b.Add("foo", "baz")
+	b.Add("x", "y")
+	a.AddFrom(&b)
+	a.RemoveDuplicates()
+	s := a.String()
+	sExpected := `{foo="baz",x="y",z="x"}`
+	if s != sExpected {
+		t.Fatalf("unexpected result;\ngot\n%s\nwant\n%s", s, sExpected)
+	}
+}
+
+func TestLabelsRemoveMetaLabels(t *testing.T) {
+	f := func(metric, resultExpected string) {
+		t.Helper()
+		labels := NewLabelsFromString(metric)
+		labels.RemoveMetaLabels()
+		result := labels.String()
+		if result != resultExpected {
+			t.Fatalf("unexpected result of RemoveMetaLabels;\ngot\n%s\nwant\n%s", result, resultExpected)
+		}
+	}
+	f(`{}`, `{}`)
+	f(`{foo="bar"}`, `{foo="bar"}`)
+	f(`{__meta_foo="bar"}`, `{}`)
+	f(`{__meta_foo="bdffr",foo="bar",__meta_xxx="basd"}`, `{foo="bar"}`)
+}
+
+func TestLabelsRemoveLabelsWithDoubleUnderscorePrefix(t *testing.T) {
+	f := func(metric, resultExpected string) {
+		t.Helper()
+		labels := NewLabelsFromString(metric)
+		labels.RemoveLabelsWithDoubleUnderscorePrefix()
+		result := labels.String()
+		if result != resultExpected {
+			t.Fatalf("unexpected result of RemoveLabelsWithDoubleUnderscorePrefix;\ngot\n%s\nwant\n%s", result, resultExpected)
+		}
+	}
+	f(`{}`, `{}`)
+	f(`{foo="bar"}`, `{foo="bar"}`)
+	f(`{__meta_foo="bar",a="b",__name__="foo",__vm_filepath="aa"}`, `{a="b",__vm_filepath="aa"}`)
+	f(`{__meta_foo="bdffr",foo="bar",__meta_xxx="basd"}`, `{foo="bar"}`)
+}
diff --git a/lib/promutils/labels_timing_test.go b/lib/promutils/labels_timing_test.go
new file mode 100644
index 0000000000..d61275c7be
--- /dev/null
+++ b/lib/promutils/labels_timing_test.go
@@ -0,0 +1,20 @@
+package promutils
+
+import (
+	"testing"
+)
+
+func BenchmarkLabelsInternStrings(b *testing.B) {
+	b.ReportAllocs()
+	b.SetBytes(1)
+	b.RunParallel(func(pb *testing.PB) {
+		labels := NewLabelsFromMap(map[string]string{
+			"job":                         "node-exporter",
+			"instance":                    "foo.bar.baz:1234",
+			"__meta_kubernetes_namespace": "default",
+		})
+		for pb.Next() {
+			labels.InternStrings()
+		}
+	})
+}