app/{vminsert,vmagent}: drop series on exceeding -maxLabelsPerTimeseries, -maxLabelValueLen flags and maxLabelNameLen=256 limits

This commit is contained in:
Andrii Chubatiuk 2024-11-15 14:05:14 +02:00
parent a335ed23c7
commit a921ad7380
No known key found for this signature in database
GPG key ID: 96D776CC99880667
23 changed files with 221 additions and 210 deletions

View file

@ -10,7 +10,7 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil" "github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/decimal" "github.com/VictoriaMetrics/VictoriaMetrics/lib/decimal"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompb" "github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/prometheus" "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/prometheus"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/storage" "github.com/VictoriaMetrics/VictoriaMetrics/lib/storage"
) )
@ -48,7 +48,7 @@ func selfScraper(scrapeInterval time.Duration) {
var bb bytesutil.ByteBuffer var bb bytesutil.ByteBuffer
var rows prometheus.Rows var rows prometheus.Rows
var mrs []storage.MetricRow var mrs []storage.MetricRow
var labels []prompb.Label var labels []prompbmarshal.Label
t := time.NewTicker(scrapeInterval) t := time.NewTicker(scrapeInterval)
f := func(currentTime time.Time, sendStaleMarkers bool) { f := func(currentTime time.Time, sendStaleMarkers bool) {
currentTimestamp := currentTime.UnixNano() / 1e6 currentTimestamp := currentTime.UnixNano() / 1e6
@ -99,11 +99,11 @@ func selfScraper(scrapeInterval time.Duration) {
} }
} }
func addLabel(dst []prompb.Label, key, value string) []prompb.Label { func addLabel(dst []prompbmarshal.Label, key, value string) []prompbmarshal.Label {
if len(dst) < cap(dst) { if len(dst) < cap(dst) {
dst = dst[:len(dst)+1] dst = dst[:len(dst)+1]
} else { } else {
dst = append(dst, prompb.Label{}) dst = append(dst, prompbmarshal.Label{})
} }
lb := &dst[len(dst)-1] lb := &dst[len(dst)-1]
lb.Name = key lb.Name = key

View file

@ -7,13 +7,10 @@ import (
"net/url" "net/url"
"path/filepath" "path/filepath"
"slices" "slices"
"strconv"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/auth" "github.com/VictoriaMetrics/VictoriaMetrics/lib/auth"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/bloomfilter" "github.com/VictoriaMetrics/VictoriaMetrics/lib/bloomfilter"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil" "github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil"
@ -21,6 +18,7 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/fasttime" "github.com/VictoriaMetrics/VictoriaMetrics/lib/fasttime"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/flagutil" "github.com/VictoriaMetrics/VictoriaMetrics/lib/flagutil"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/fs" "github.com/VictoriaMetrics/VictoriaMetrics/lib/fs"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/memory" "github.com/VictoriaMetrics/VictoriaMetrics/lib/memory"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/persistentqueue" "github.com/VictoriaMetrics/VictoriaMetrics/lib/persistentqueue"
@ -29,6 +27,7 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promrelabel" "github.com/VictoriaMetrics/VictoriaMetrics/lib/promrelabel"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils" "github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/ratelimiter" "github.com/VictoriaMetrics/VictoriaMetrics/lib/ratelimiter"
storagelimits "github.com/VictoriaMetrics/VictoriaMetrics/lib/storage/limits"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/streamaggr" "github.com/VictoriaMetrics/VictoriaMetrics/lib/streamaggr"
"github.com/VictoriaMetrics/metrics" "github.com/VictoriaMetrics/metrics"
"github.com/cespare/xxhash/v2" "github.com/cespare/xxhash/v2"
@ -485,6 +484,14 @@ func tryPush(at *auth.Token, wr *prompbmarshal.WriteRequest, forceDropSamplesOnF
rowsCountAfterRelabel := getRowsCount(tssBlock) rowsCountAfterRelabel := getRowsCount(tssBlock)
rowsDroppedByGlobalRelabel.Add(rowsCountBeforeRelabel - rowsCountAfterRelabel) rowsDroppedByGlobalRelabel.Add(rowsCountBeforeRelabel - rowsCountAfterRelabel)
} }
idxDiff := 0
for i, ts := range tssBlock {
if storagelimits.ExceedingLabels(ts.Labels) {
idxDiff++
} else if idxDiff > 0 {
tss[i-idxDiff] = tss[i]
}
}
sortLabelsIfNeeded(tssBlock) sortLabelsIfNeeded(tssBlock)
tssBlock = limitSeriesCardinality(tssBlock) tssBlock = limitSeriesCardinality(tssBlock)
if sas.IsEnabled() { if sas.IsEnabled() {
@ -729,29 +736,14 @@ func logSkippedSeries(labels []prompbmarshal.Label, flagName string, flagValue i
select { select {
case <-logSkippedSeriesTicker.C: case <-logSkippedSeriesTicker.C:
// Do not use logger.WithThrottler() here, since this will increase CPU usage // Do not use logger.WithThrottler() here, since this will increase CPU usage
// because every call to logSkippedSeries will result to a call to labelsToString. // because every call to logSkippedSeries will result to a call to prompbmarshal.LabelsToString.
logger.Warnf("skip series %s because %s=%d reached", labelsToString(labels), flagName, flagValue) logger.Warnf("skip series %s because %s=%d reached", prompbmarshal.LabelsToString(labels), flagName, flagValue)
default: default:
} }
} }
var logSkippedSeriesTicker = time.NewTicker(5 * time.Second) var logSkippedSeriesTicker = time.NewTicker(5 * time.Second)
func labelsToString(labels []prompbmarshal.Label) string {
var b []byte
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 string(b)
}
var ( var (
globalRowsPushedBeforeRelabel = metrics.NewCounter("vmagent_remotewrite_global_rows_pushed_before_relabel_total") globalRowsPushedBeforeRelabel = metrics.NewCounter("vmagent_remotewrite_global_rows_pushed_before_relabel_total")
rowsDroppedByGlobalRelabel = metrics.NewCounter("vmagent_remotewrite_global_relabel_metrics_dropped_total") rowsDroppedByGlobalRelabel = metrics.NewCounter("vmagent_remotewrite_global_relabel_metrics_dropped_total")

View file

@ -17,7 +17,7 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmctl/vm" "github.com/VictoriaMetrics/VictoriaMetrics/app/vmctl/vm"
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmselect/promql" "github.com/VictoriaMetrics/VictoriaMetrics/app/vmselect/promql"
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmstorage" "github.com/VictoriaMetrics/VictoriaMetrics/app/vmstorage"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompb" "github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/storage" "github.com/VictoriaMetrics/VictoriaMetrics/lib/storage"
) )
@ -214,15 +214,15 @@ func processFlags() {
func fillStorage(series []vm.TimeSeries) error { func fillStorage(series []vm.TimeSeries) error {
var mrs []storage.MetricRow var mrs []storage.MetricRow
for _, series := range series { for _, series := range series {
var labels []prompb.Label var labels []prompbmarshal.Label
for _, lp := range series.LabelPairs { for _, lp := range series.LabelPairs {
labels = append(labels, prompb.Label{ labels = append(labels, prompbmarshal.Label{
Name: lp.Name, Name: lp.Name,
Value: lp.Value, Value: lp.Value,
}) })
} }
if series.Name != "" { if series.Name != "" {
labels = append(labels, prompb.Label{ labels = append(labels, prompbmarshal.Label{
Name: "__name__", Name: "__name__",
Value: series.Name, Value: series.Name,
}) })

View file

@ -8,9 +8,10 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmstorage" "github.com/VictoriaMetrics/VictoriaMetrics/app/vmstorage"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil" "github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver" "github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompb" "github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/slicesutil" "github.com/VictoriaMetrics/VictoriaMetrics/lib/slicesutil"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/storage" "github.com/VictoriaMetrics/VictoriaMetrics/lib/storage"
storagelimits "github.com/VictoriaMetrics/VictoriaMetrics/lib/storage/limits"
) )
// InsertCtx contains common bits for data points insertion. // InsertCtx contains common bits for data points insertion.
@ -30,7 +31,7 @@ type InsertCtx struct {
func (ctx *InsertCtx) Reset(rowsLen int) { func (ctx *InsertCtx) Reset(rowsLen int) {
labels := ctx.Labels labels := ctx.Labels
for i := range labels { for i := range labels {
labels[i] = prompb.Label{} labels[i] = prompbmarshal.Label{}
} }
ctx.Labels = labels[:0] ctx.Labels = labels[:0]
@ -51,7 +52,7 @@ func cleanMetricRow(mr *storage.MetricRow) {
mr.MetricNameRaw = nil mr.MetricNameRaw = nil
} }
func (ctx *InsertCtx) marshalMetricNameRaw(prefix []byte, labels []prompb.Label) []byte { func (ctx *InsertCtx) marshalMetricNameRaw(prefix []byte, labels []prompbmarshal.Label) []byte {
start := len(ctx.metricNamesBuf) start := len(ctx.metricNamesBuf)
ctx.metricNamesBuf = append(ctx.metricNamesBuf, prefix...) ctx.metricNamesBuf = append(ctx.metricNamesBuf, prefix...)
ctx.metricNamesBuf = storage.MarshalMetricNameRaw(ctx.metricNamesBuf, labels) ctx.metricNamesBuf = storage.MarshalMetricNameRaw(ctx.metricNamesBuf, labels)
@ -60,7 +61,10 @@ func (ctx *InsertCtx) marshalMetricNameRaw(prefix []byte, labels []prompb.Label)
} }
// WriteDataPoint writes (timestamp, value) with the given prefix and labels into ctx buffer. // WriteDataPoint writes (timestamp, value) with the given prefix and labels into ctx buffer.
func (ctx *InsertCtx) WriteDataPoint(prefix []byte, labels []prompb.Label, timestamp int64, value float64) error { func (ctx *InsertCtx) WriteDataPoint(prefix []byte, labels []prompbmarshal.Label, timestamp int64, value float64) error {
if storagelimits.ExceedingLabels(labels) {
return nil
}
metricNameRaw := ctx.marshalMetricNameRaw(prefix, labels) metricNameRaw := ctx.marshalMetricNameRaw(prefix, labels)
return ctx.addRow(metricNameRaw, timestamp, value) return ctx.addRow(metricNameRaw, timestamp, value)
} }
@ -68,7 +72,10 @@ func (ctx *InsertCtx) WriteDataPoint(prefix []byte, labels []prompb.Label, times
// WriteDataPointExt writes (timestamp, value) with the given metricNameRaw and labels into ctx buffer. // WriteDataPointExt writes (timestamp, value) with the given metricNameRaw and labels into ctx buffer.
// //
// It returns metricNameRaw for the given labels if len(metricNameRaw) == 0. // It returns metricNameRaw for the given labels if len(metricNameRaw) == 0.
func (ctx *InsertCtx) WriteDataPointExt(metricNameRaw []byte, labels []prompb.Label, timestamp int64, value float64) ([]byte, error) { func (ctx *InsertCtx) WriteDataPointExt(metricNameRaw []byte, labels []prompbmarshal.Label, timestamp int64, value float64) ([]byte, error) {
if storagelimits.ExceedingLabels(labels) {
return metricNameRaw, nil
}
if len(metricNameRaw) == 0 { if len(metricNameRaw) == 0 {
metricNameRaw = ctx.marshalMetricNameRaw(nil, labels) metricNameRaw = ctx.marshalMetricNameRaw(nil, labels)
} }
@ -106,7 +113,7 @@ func (ctx *InsertCtx) AddLabelBytes(name, value []byte) {
// Do not skip labels with empty name, since they are equal to __name__. // Do not skip labels with empty name, since they are equal to __name__.
return return
} }
ctx.Labels = append(ctx.Labels, prompb.Label{ ctx.Labels = append(ctx.Labels, prompbmarshal.Label{
// Do not copy name and value contents for performance reasons. // Do not copy name and value contents for performance reasons.
// This reduces GC overhead on the number of objects and allocations. // This reduces GC overhead on the number of objects and allocations.
Name: bytesutil.ToUnsafeString(name), Name: bytesutil.ToUnsafeString(name),
@ -124,7 +131,7 @@ func (ctx *InsertCtx) AddLabel(name, value string) {
// Do not skip labels with empty name, since they are equal to __name__. // Do not skip labels with empty name, since they are equal to __name__.
return return
} }
ctx.Labels = append(ctx.Labels, prompb.Label{ ctx.Labels = append(ctx.Labels, prompbmarshal.Label{
// Do not copy name and value contents for performance reasons. // Do not copy name and value contents for performance reasons.
// This reduces GC overhead on the number of objects and allocations. // This reduces GC overhead on the number of objects and allocations.
Name: name, Name: name,

View file

@ -4,7 +4,7 @@ import (
"flag" "flag"
"sort" "sort"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompb" "github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
) )
var sortLabels = flag.Bool("sortLabels", false, `Whether to sort labels for incoming samples before writing them to storage. `+ var sortLabels = flag.Bool("sortLabels", false, `Whether to sort labels for incoming samples before writing them to storage. `+
@ -19,7 +19,7 @@ func (ctx *InsertCtx) SortLabelsIfNeeded() {
} }
} }
type sortedLabels []prompb.Label type sortedLabels []prompbmarshal.Label
func (sl *sortedLabels) Len() int { return len(*sl) } func (sl *sortedLabels) Len() int { return len(*sl) }
func (sl *sortedLabels) Less(i, j int) bool { func (sl *sortedLabels) Less(i, j int) bool {

View file

@ -9,7 +9,6 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/app/vminsert/common" "github.com/VictoriaMetrics/VictoriaMetrics/app/vminsert/common"
"github.com/VictoriaMetrics/VictoriaMetrics/app/vminsert/relabel" "github.com/VictoriaMetrics/VictoriaMetrics/app/vminsert/relabel"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil" "github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompb"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal" "github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
parserCommon "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/common" parserCommon "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/common"
parser "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/influx" parser "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/influx"
@ -150,7 +149,7 @@ type pushCtx struct {
Common common.InsertCtx Common common.InsertCtx
metricNameBuf []byte metricNameBuf []byte
metricGroupBuf []byte metricGroupBuf []byte
originLabels []prompb.Label originLabels []prompbmarshal.Label
} }
func (ctx *pushCtx) reset() { func (ctx *pushCtx) reset() {
@ -160,7 +159,7 @@ func (ctx *pushCtx) reset() {
originLabels := ctx.originLabels originLabels := ctx.originLabels
for i := range originLabels { for i := range originLabels {
originLabels[i] = prompb.Label{} originLabels[i] = prompbmarshal.Label{}
} }
ctx.originLabels = originLabels[:0] ctx.originLabels = originLabels[:0]
} }

View file

@ -41,7 +41,6 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape" "github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/common" "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/common"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/opentelemetry/firehose" "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/opentelemetry/firehose"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/storage"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/stringsutil" "github.com/VictoriaMetrics/VictoriaMetrics/lib/stringsutil"
) )
@ -67,8 +66,6 @@ var (
"at -opentsdbHTTPListenAddr . See https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt") "at -opentsdbHTTPListenAddr . See https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt")
configAuthKey = flagutil.NewPassword("configAuthKey", "Authorization key for accessing /config page. It must be passed via authKey query arg. It overrides -httpAuth.*") configAuthKey = flagutil.NewPassword("configAuthKey", "Authorization key for accessing /config page. It must be passed via authKey query arg. It overrides -httpAuth.*")
reloadAuthKey = flagutil.NewPassword("reloadAuthKey", "Auth key for /-/reload http endpoint. It must be passed via authKey query arg. It overrides httpAuth.* settings.") reloadAuthKey = flagutil.NewPassword("reloadAuthKey", "Auth key for /-/reload http endpoint. It must be passed via authKey query arg. It overrides httpAuth.* settings.")
maxLabelsPerTimeseries = flag.Int("maxLabelsPerTimeseries", 30, "The maximum number of labels accepted per time series. Superfluous labels are dropped. In this case the vm_metrics_with_dropped_labels_total metric at /metrics page is incremented")
maxLabelValueLen = flag.Int("maxLabelValueLen", 4*1024, "The maximum length of label values in the accepted time series. Longer label values are truncated. In this case the vm_too_long_label_values_total metric at /metrics page is incremented")
) )
var ( var (
@ -87,8 +84,6 @@ var staticServer = http.FileServer(http.FS(staticFiles))
func Init() { func Init() {
relabel.Init() relabel.Init()
vminsertCommon.InitStreamAggr() vminsertCommon.InitStreamAggr()
storage.SetMaxLabelsPerTimeseries(*maxLabelsPerTimeseries)
storage.SetMaxLabelValueLen(*maxLabelValueLen)
common.StartUnmarshalWorkers() common.StartUnmarshalWorkers()
if len(*graphiteListenAddr) > 0 { if len(*graphiteListenAddr) > 0 {
graphiteServer = graphiteserver.MustStart(*graphiteListenAddr, *graphiteUseProxyProtocol, graphite.InsertHandler) graphiteServer = graphiteserver.MustStart(*graphiteListenAddr, *graphiteUseProxyProtocol, graphite.InsertHandler)
@ -439,14 +434,4 @@ var (
promscrapeStatusConfigRequests = metrics.NewCounter(`vm_http_requests_total{path="/api/v1/status/config"}`) promscrapeStatusConfigRequests = metrics.NewCounter(`vm_http_requests_total{path="/api/v1/status/config"}`)
promscrapeConfigReloadRequests = metrics.NewCounter(`vm_http_requests_total{path="/-/reload"}`) promscrapeConfigReloadRequests = metrics.NewCounter(`vm_http_requests_total{path="/-/reload"}`)
_ = metrics.NewGauge(`vm_metrics_with_dropped_labels_total`, func() float64 {
return float64(storage.MetricsWithDroppedLabels.Load())
})
_ = metrics.NewGauge(`vm_too_long_label_names_total`, func() float64 {
return float64(storage.TooLongLabelNames.Load())
})
_ = metrics.NewGauge(`vm_too_long_label_values_total`, func() float64 {
return float64(storage.TooLongLabelValues.Load())
})
) )

View file

@ -8,7 +8,6 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/fasttime" "github.com/VictoriaMetrics/VictoriaMetrics/lib/fasttime"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/procutil" "github.com/VictoriaMetrics/VictoriaMetrics/lib/procutil"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompb"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal" "github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promrelabel" "github.com/VictoriaMetrics/VictoriaMetrics/lib/promrelabel"
"github.com/VictoriaMetrics/metrics" "github.com/VictoriaMetrics/metrics"
@ -108,7 +107,7 @@ func (ctx *Ctx) Reset() {
// ApplyRelabeling applies relabeling to the given labels and returns the result. // ApplyRelabeling applies relabeling to the given labels and returns the result.
// //
// The returned labels are valid until the next call to ApplyRelabeling. // The returned labels are valid until the next call to ApplyRelabeling.
func (ctx *Ctx) ApplyRelabeling(labels []prompb.Label) []prompb.Label { func (ctx *Ctx) ApplyRelabeling(labels []prompbmarshal.Label) []prompbmarshal.Label {
pcs := pcsGlobal.Load() pcs := pcsGlobal.Load()
if pcs.Len() == 0 && !*usePromCompatibleNaming { if pcs.Len() == 0 && !*usePromCompatibleNaming {
// There are no relabeling rules. // There are no relabeling rules.
@ -159,7 +158,7 @@ func (ctx *Ctx) ApplyRelabeling(labels []prompb.Label) []prompb.Label {
name = "" name = ""
} }
value := label.Value value := label.Value
dst = append(dst, prompb.Label{ dst = append(dst, prompbmarshal.Label{
Name: name, Name: name,
Value: value, Value: value,
}) })

View file

@ -14,7 +14,7 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmstorage" "github.com/VictoriaMetrics/VictoriaMetrics/app/vmstorage"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/bufferedwriter" "github.com/VictoriaMetrics/VictoriaMetrics/lib/bufferedwriter"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/httputils" "github.com/VictoriaMetrics/VictoriaMetrics/lib/httputils"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompb" "github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
graphiteparser "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/graphite" graphiteparser "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/graphite"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/storage" "github.com/VictoriaMetrics/VictoriaMetrics/lib/storage"
"github.com/VictoriaMetrics/metrics" "github.com/VictoriaMetrics/metrics"
@ -95,7 +95,7 @@ func registerMetrics(startTime time.Time, w http.ResponseWriter, r *http.Request
_ = deadline // TODO: use the deadline as in the cluster branch _ = deadline // TODO: use the deadline as in the cluster branch
paths := r.Form["path"] paths := r.Form["path"]
var row graphiteparser.Row var row graphiteparser.Row
var labels []prompb.Label var labels []prompbmarshal.Label
var b []byte var b []byte
var tagsPool []graphiteparser.Tag var tagsPool []graphiteparser.Tag
mrs := make([]storage.MetricRow, len(paths)) mrs := make([]storage.MetricRow, len(paths))
@ -122,12 +122,12 @@ func registerMetrics(startTime time.Time, w http.ResponseWriter, r *http.Request
canonicalPaths[i] = string(b) canonicalPaths[i] = string(b)
// Convert parsed metric and tags to labels. // Convert parsed metric and tags to labels.
labels = append(labels[:0], prompb.Label{ labels = append(labels[:0], prompbmarshal.Label{
Name: "__name__", Name: "__name__",
Value: row.Metric, Value: row.Metric,
}) })
for _, tag := range row.Tags { for _, tag := range row.Tags {
labels = append(labels, prompb.Label{ labels = append(labels, prompbmarshal.Label{
Name: tag.Key, Name: tag.Key,
Value: tag.Value, Value: tag.Value,
}) })

View file

@ -3674,12 +3674,12 @@
"uid": "$ds" "uid": "$ds"
}, },
"exemplar": true, "exemplar": true,
"expr": "sum(increase(vm_metrics_with_dropped_labels_total{job=~\"$job_insert\", instance=~\"$instance\"}[$__rate_interval]))", "expr": "sum(increase(vm_series_dropped_total{job=~\"$job_insert\", instance=~\"$instance\"}[$__rate_interval])) by (reason)",
"format": "time_series", "format": "time_series",
"hide": false, "hide": false,
"interval": "", "interval": "",
"intervalFactor": 1, "intervalFactor": 1,
"legendFormat": "metrics with dropped labels", "legendFormat": "dropped series, which a hitting {{reason}}",
"refId": "A" "refId": "A"
} }
], ],

View file

@ -4190,12 +4190,12 @@
"uid": "$ds" "uid": "$ds"
}, },
"exemplar": false, "exemplar": false,
"expr": "sum(increase(vm_metrics_with_dropped_labels_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])) by (instance)", "expr": "sum(increase(vm_series_dropped_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])) by (instance,reason)",
"format": "time_series", "format": "time_series",
"hide": false, "hide": false,
"interval": "", "interval": "",
"intervalFactor": 1, "intervalFactor": 1,
"legendFormat": "{{instance}} - limit exceeded", "legendFormat": "{{instance}} - {{reason}}",
"range": true, "range": true,
"refId": "A" "refId": "A"
} }

View file

@ -3675,12 +3675,12 @@
"uid": "$ds" "uid": "$ds"
}, },
"exemplar": true, "exemplar": true,
"expr": "sum(increase(vm_metrics_with_dropped_labels_total{job=~\"$job_insert\", instance=~\"$instance\"}[$__rate_interval]))", "expr": "sum(increase(vm_series_dropped_total{job=~\"$job_insert\", instance=~\"$instance\"}[$__rate_interval])) by (reason)",
"format": "time_series", "format": "time_series",
"hide": false, "hide": false,
"interval": "", "interval": "",
"intervalFactor": 1, "intervalFactor": 1,
"legendFormat": "metrics with dropped labels", "legendFormat": "dropped series, which a hitting {{reason}}",
"refId": "A" "refId": "A"
} }
], ],

View file

@ -4191,12 +4191,12 @@
"uid": "$ds" "uid": "$ds"
}, },
"exemplar": false, "exemplar": false,
"expr": "sum(increase(vm_metrics_with_dropped_labels_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])) by (instance)", "expr": "sum(increase(vm_series_dropped_total{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])) by (instance, reason)",
"format": "time_series", "format": "time_series",
"hide": false, "hide": false,
"interval": "", "interval": "",
"intervalFactor": 1, "intervalFactor": 1,
"legendFormat": "{{instance}} - limit exceeded", "legendFormat": "{{instance}} - {{reason}}",
"range": true, "range": true,
"refId": "A" "refId": "A"
} }

View file

@ -141,13 +141,13 @@ groups:
See also https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3976#issuecomment-1476883183" See also https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3976#issuecomment-1476883183"
- alert: LabelsLimitExceededOnIngestion - alert: LabelsLimitExceededOnIngestion
expr: increase(vm_metrics_with_dropped_labels_total[5m]) > 0 expr: increase(vm_series_dropped_total{reason="too_many_labels"}[5m]) > 0
for: 15m for: 15m
labels: labels:
severity: warning severity: warning
annotations: annotations:
dashboard: "http://localhost:3000/d/oS7Bi_0Wz?viewPanel=116&var-instance={{ $labels.instance }}" dashboard: "http://localhost:3000/d/oS7Bi_0Wz?viewPanel=116&var-instance={{ $labels.instance }}"
summary: "Metrics ingested to vminsert on {{ $labels.instance }} are exceeding labels limit" summary: "Metrics ingested to vminsert on {{ $labels.instance }} are exceeding one of labels limits: `{{ $labels.reason}}`"
description: "VictoriaMetrics limits the number of labels per each metric with `-maxLabelsPerTimeseries` command-line flag.\n description: "VictoriaMetrics limits the number of labels per each metric with `-maxLabelsPerTimeseries` command-line flag.\n
This prevents from ingesting metrics with too many labels. Please verify that `-maxLabelsPerTimeseries` is configured This prevents from ingesting metrics with too many labels. Please verify that `-maxLabelsPerTimeseries` is configured
correctly or that clients which send these metrics aren't misbehaving." correctly or that clients which send these metrics aren't misbehaving."

View file

@ -120,10 +120,11 @@ groups:
`-maxLabelValueLen` command-line flags. `-maxLabelValueLen` command-line flags.
- alert: TooLongLabelValues - alert: TooLongLabelValues
expr: increase(vm_too_long_label_values_total[5m]) > 0 expr: increase(vm_series_dropped_total{reason="too_long_label_value"}[5m]) > 0
labels: labels:
severity: critical severity: critical
annotations: annotations:
dashboard: "http://localhost:3000/d/wNf0q_kZk?viewPanel=74&var-instance={{ $labels.instance }}"
summary: "VictoriaMetrics truncates too long label values" summary: "VictoriaMetrics truncates too long label values"
description: | description: |
The maximum length of a label value is limited via `-maxLabelValueLen` cmd-line flag. The maximum length of a label value is limited via `-maxLabelValueLen` cmd-line flag.
@ -132,10 +133,11 @@ groups:
either reduce the size of label values or increase `-maxLabelValueLen`. either reduce the size of label values or increase `-maxLabelValueLen`.
- alert: TooLongLabelNames - alert: TooLongLabelNames
expr: increase(vm_too_long_label_names_total[5m]) > 0 expr: increase(vm_series_dropped_total{reason="too_long_label_name"}[5m]) > 0
labels: labels:
severity: critical severity: critical
annotations: annotations:
dashboard: "http://localhost:3000/d/wNf0q_kZk?viewPanel=74&var-instance={{ $labels.instance }}"
summary: "VictoriaMetrics truncates too long label names" summary: "VictoriaMetrics truncates too long label names"
description: > description: >
The maximum length of a label name is limited by 256 bytes. The maximum length of a label name is limited by 256 bytes.

View file

@ -121,13 +121,13 @@ groups:
See also https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3976#issuecomment-1476883183" See also https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3976#issuecomment-1476883183"
- alert: LabelsLimitExceededOnIngestion - alert: LabelsLimitExceededOnIngestion
expr: increase(vm_metrics_with_dropped_labels_total[5m]) > 0 expr: increase(vm_series_dropped_total{reason="too_many_labels"}[5m]) > 0
for: 15m for: 15m
labels: labels:
severity: warning severity: warning
annotations: annotations:
dashboard: "http://localhost:3000/d/wNf0q_kZk?viewPanel=74&var-instance={{ $labels.instance }}" dashboard: "http://localhost:3000/d/wNf0q_kZk?viewPanel=74&var-instance={{ $labels.instance }}"
summary: "Metrics ingested in ({{ $labels.instance }}) are exceeding labels limit" summary: "Metrics ingested to vminsert on {{ $labels.instance }} are exceeding one of labels limits: `{{ $labels.reason}}`"
description: "VictoriaMetrics limits the number of labels per each metric with `-maxLabelsPerTimeseries` command-line flag.\n description: "VictoriaMetrics limits the number of labels per each metric with `-maxLabelsPerTimeseries` command-line flag.\n
This prevents ingestion of metrics with too many labels. Please verify that `-maxLabelsPerTimeseries` is configured This prevents from ingesting metrics with too many labels. Please verify that `-maxLabelsPerTimeseries` is configured
correctly or that clients which send these metrics aren't misbehaving." correctly or that clients which send these metrics aren't misbehaving."

View file

@ -1243,7 +1243,7 @@ Below is the output for `/path/to/vminsert -help`:
The maximum size in bytes of a single Prometheus remote_write API request The maximum size in bytes of a single Prometheus remote_write API request
Supports the following optional suffixes for size values: KB, MB, GB, TB, KiB, MiB, GiB, TiB (default 33554432) Supports the following optional suffixes for size values: KB, MB, GB, TB, KiB, MiB, GiB, TiB (default 33554432)
-maxLabelValueLen int -maxLabelValueLen int
The maximum length of label values in the accepted time series. Longer label values are truncated. In this case the vm_too_long_label_values_total metric at /metrics page is incremented (default 4096) The maximum length of label values in the accepted time series. Series, with longer label values are dropped. In this case the `vm_series_dropped_total{reason="too_long_label_value"}` metric at /metrics page is incremented (default 4096)
-maxLabelsPerTimeseries int -maxLabelsPerTimeseries int
The maximum number of labels accepted per time series. Superfluous labels are dropped. In this case the vm_metrics_with_dropped_labels_total metric at /metrics page is incremented (default 30) The maximum number of labels accepted per time series. Superfluous labels are dropped. In this case the vm_metrics_with_dropped_labels_total metric at /metrics page is incremented (default 30)
-memory.allowedBytes size -memory.allowedBytes size

View file

@ -2462,9 +2462,10 @@ and [cardinality explorer docs](#cardinality-explorer).
* New time series can be logged if `-logNewSeries` command-line flag is passed to VictoriaMetrics. * New time series can be logged if `-logNewSeries` command-line flag is passed to VictoriaMetrics.
* VictoriaMetrics limits the number of labels per each metric with `-maxLabelsPerTimeseries` command-line flag * VictoriaMetrics limits the number of labels per each metric with `-maxLabelsPerTimeseries` command-line flag
and drops superfluous labels. This prevents from ingesting metrics with too many labels. and drops series with superfluous labels. This prevents from ingesting metrics with too many labels.
It is recommended [monitoring](#monitoring) `vm_metrics_with_dropped_labels_total` It is recommended [monitoring](#monitoring) `vm_series_dropped_total{reason="too_many_labels"}`
metric in order to determine whether `-maxLabelsPerTimeseries` must be adjusted for your workload. metric in order to determine whether `-maxLabelsPerTimeseries` must be adjusted for your workload.
Alternatively you can use [relabeling](https://docs.victoriametrics.com/single-server-victoriametrics/#relabeling) to change metric target labels.
* If you store Graphite metrics like `foo.bar.baz` in VictoriaMetrics, then `{__graphite__="foo.*.baz"}` filter can be used for selecting such metrics. * If you store Graphite metrics like `foo.bar.baz` in VictoriaMetrics, then `{__graphite__="foo.*.baz"}` filter can be used for selecting such metrics.
See [these docs](#selecting-graphite-metrics) for details. You can also query Graphite metrics with [Graphite querying API](#graphite-render-api-usage). See [these docs](#selecting-graphite-metrics) for details. You can also query Graphite metrics with [Graphite querying API](#graphite-render-api-usage).
@ -2960,9 +2961,9 @@ Pass `-help` to VictoriaMetrics in order to see the list of supported command-li
The maximum size in bytes of a single Prometheus remote_write API request The maximum size in bytes of a single Prometheus remote_write API request
Supports the following optional suffixes for size values: KB, MB, GB, TB, KiB, MiB, GiB, TiB (default 33554432) Supports the following optional suffixes for size values: KB, MB, GB, TB, KiB, MiB, GiB, TiB (default 33554432)
-maxLabelValueLen int -maxLabelValueLen int
The maximum length of label values in the accepted time series. Longer label values are truncated. In this case the vm_too_long_label_values_total metric at /metrics page is incremented (default 4096) The maximum length of label values in the accepted time series. Series, with longer label values are dropped. In this case the `vm_series_dropped_total{reason="too_long_label_value"}` metric at /metrics page is incremented (default 4096)
-maxLabelsPerTimeseries int -maxLabelsPerTimeseries int
The maximum number of labels accepted per time series. Superfluous labels are dropped. In this case the vm_metrics_with_dropped_labels_total metric at /metrics page is incremented (default 30) The maximum number of labels accepted per time series. Series with superfluous labels are dropped. In this case the `vm_series_dropped_total{reason="too_many_labels"}` metric at /metrics page is incremented (default 30)
-memory.allowedBytes size -memory.allowedBytes size
Allowed size of system memory VictoriaMetrics caches may occupy. This option overrides -memory.allowedPercent if set to a non-zero value. Too low a value may increase the cache miss rate usually resulting in higher CPU and disk IO usage. Too high a value may evict too much data from the OS page cache resulting in higher disk IO usage Allowed size of system memory VictoriaMetrics caches may occupy. This option overrides -memory.allowedPercent if set to a non-zero value. Too low a value may increase the cache miss rate usually resulting in higher CPU and disk IO usage. Too high a value may evict too much data from the OS page cache resulting in higher disk IO usage
Supports the following optional suffixes for size values: KB, MB, GB, TB, KiB, MiB, GiB, TiB (default 0) Supports the following optional suffixes for size values: KB, MB, GB, TB, KiB, MiB, GiB, TiB (default 0)

View file

@ -20,12 +20,15 @@ See also [LTS releases](https://docs.victoriametrics.com/lts-releases/).
* SECURITY: upgrade Go builder from Go1.23.1 to Go1.23.3. See the list of issues addressed in [Go1.23.2](https://github.com/golang/go/issues?q=milestone%3AGo1.23.2+label%3ACherryPickApproved) and [Go1.23.3](https://github.com/golang/go/issues?q=milestone%3AGo1.23.3+label%3ACherryPickApproved). * SECURITY: upgrade Go builder from Go1.23.1 to Go1.23.3. See the list of issues addressed in [Go1.23.2](https://github.com/golang/go/issues?q=milestone%3AGo1.23.2+label%3ACherryPickApproved) and [Go1.23.3](https://github.com/golang/go/issues?q=milestone%3AGo1.23.3+label%3ACherryPickApproved).
* FEATURE: [vmagent](https://docs.victoriametrics.com/vmagent) added `-maxLabelsPerTimeseries` and `-maxLabelValueLen` flags, which limits amount of labels, label name and value length for pushed to/scraped by vmagent data. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6928).
* BUGFIX: [vmctl](https://docs.victoriametrics.com/vmctl/): drop rows that do not belong to the current series during import. The dropped rows should belong to another series whose tags are a superset of the current series. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7301) and [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/7330). Thanks to @dpedu for reporting and cooperating with the test. * BUGFIX: [vmctl](https://docs.victoriametrics.com/vmctl/): drop rows that do not belong to the current series during import. The dropped rows should belong to another series whose tags are a superset of the current series. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7301) and [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/7330). Thanks to @dpedu for reporting and cooperating with the test.
* BUGFIX: [vmsingle](https://docs.victoriametrics.com/single-server-victoriametrics/), `vmselect` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/cluster-victoriametrics/): keep the order of resulting time series when `limit_offset` is applied. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7068). * BUGFIX: [vmsingle](https://docs.victoriametrics.com/single-server-victoriametrics/), `vmselect` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/cluster-victoriametrics/): keep the order of resulting time series when `limit_offset` is applied. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7068).
* BUGFIX: [graphite](https://docs.victoriametrics.com/#graphite-render-api-usage): properly handle xFilesFactor=0 for `transformRemoveEmptySeries` function. See [this PR](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/7337) for details. * BUGFIX: [graphite](https://docs.victoriametrics.com/#graphite-render-api-usage): properly handle xFilesFactor=0 for `transformRemoveEmptySeries` function. See [this PR](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/7337) for details.
* BUGFIX: [vmauth](https://docs.victoriametrics.com/vmauth/): properly check availability of all the backends before giving up when proxying requests. Previously, vmauth could return an error even if there were healthy backends available. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3061) for details. * BUGFIX: [vmauth](https://docs.victoriametrics.com/vmauth/): properly check availability of all the backends before giving up when proxying requests. Previously, vmauth could return an error even if there were healthy backends available. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3061) for details.
* BUGFIX: [vmauth](https://docs.victoriametrics.com/vmauth/): properly inherit [`drop_src_path_prefix_parts`](https://docs.victoriametrics.com/vmauth/#dropping-request-path-prefix), [`load_balancing_policy`](https://docs.victoriametrics.com/vmauth/#high-availability), [`retry_status_codes`](https://docs.victoriametrics.com/vmauth/#load-balancing) and [`discover_backend_ips`](https://docs.victoriametrics.com/vmauth/#discovering-backend-ips) options by `url_map` entries if `url_prefix` option isn't set at the [user config level](https://docs.victoriametrics.com/vmauth/#auth-config). These options were inherited only when the `url_prefix` option was set. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7519). * BUGFIX: [vmauth](https://docs.victoriametrics.com/vmauth/): properly inherit [`drop_src_path_prefix_parts`](https://docs.victoriametrics.com/vmauth/#dropping-request-path-prefix), [`load_balancing_policy`](https://docs.victoriametrics.com/vmauth/#high-availability), [`retry_status_codes`](https://docs.victoriametrics.com/vmauth/#load-balancing) and [`discover_backend_ips`](https://docs.victoriametrics.com/vmauth/#discovering-backend-ips) options by `url_map` entries if `url_prefix` option isn't set at the [user config level](https://docs.victoriametrics.com/vmauth/#auth-config). These options were inherited only when the `url_prefix` option was set. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7519).
* BUGFIX: [dashboards](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/dashboards): add `file` label filter to vmalert dashboard panels. Previously, metrics from groups with the same name but different rule files could be mixed in the results. * BUGFIX: [dashboards](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/dashboards): add `file` label filter to vmalert dashboard panels. Previously, metrics from groups with the same name but different rule files could be mixed in the results.
* BUGFIX: [vmsingle](https://docs.victoriametrics.com/single-server-victoriametrics/) changed a meaning of `-maxLabelsPerTimeseries` and `-maxLabelValueLen`. Previously excessive labels, label names and values were truncated. With this change all series, which are hitting these limits will be dropped. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6928)
## [v1.106.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.106.0) ## [v1.106.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.106.0)

View file

@ -1893,6 +1893,10 @@ See the docs at https://docs.victoriametrics.com/vmagent/ .
-maxInsertRequestSize size -maxInsertRequestSize size
The maximum size in bytes of a single Prometheus remote_write API request The maximum size in bytes of a single Prometheus remote_write API request
Supports the following optional suffixes for size values: KB, MB, GB, TB, KiB, MiB, GiB, TiB (default 33554432) Supports the following optional suffixes for size values: KB, MB, GB, TB, KiB, MiB, GiB, TiB (default 33554432)
-maxLabelValueLen int
The maximum length of label values in the accepted time series. Series, with longer label values are dropped. In this case the `vm_series_dropped_total{reason="too_long_label_value"}` metric at /metrics page is incremented (default 4096).
-maxLabelsPerTimeseries int
The maximum number of labels accepted per time series. Series with superfluous labels are dropped. In this case the `vm_series_dropped_total{reason="too_many_labels"}` metric at /metrics page is incremented (default 30)
-memory.allowedBytes size -memory.allowedBytes size
Allowed size of system memory VictoriaMetrics caches may occupy. This option overrides -memory.allowedPercent if set to a non-zero value. Too low a value may increase the cache miss rate usually resulting in higher CPU and disk IO usage. Too high a value may evict too much data from the OS page cache resulting in higher disk IO usage Allowed size of system memory VictoriaMetrics caches may occupy. This option overrides -memory.allowedPercent if set to a non-zero value. Too low a value may increase the cache miss rate usually resulting in higher CPU and disk IO usage. Too high a value may evict too much data from the OS page cache resulting in higher disk IO usage
Supports the following optional suffixes for size values: KB, MB, GB, TB, KiB, MiB, GiB, TiB (default 0) Supports the following optional suffixes for size values: KB, MB, GB, TB, KiB, MiB, GiB, TiB (default 0)

View file

@ -6,6 +6,8 @@ package prompbmarshal
import ( import (
"encoding/binary" "encoding/binary"
"math" "math"
"sort"
"strconv"
) )
type Sample struct { type Sample struct {
@ -124,3 +126,27 @@ func (m *Label) Size() (n int) {
} }
return n return n
} }
// LabelsToString converts labels to Prometheus-compatible string
func LabelsToString(labels []Label) string {
labelsCopy := append([]Label{}, labels...)
sort.Slice(labelsCopy, func(i, j int) bool {
return string(labelsCopy[i].Name) < string(labelsCopy[j].Name)
})
var b []byte
b = append(b, '{')
for i, label := range labelsCopy {
if len(label.Name) == 0 {
b = append(b, "__name__"...)
} else {
b = append(b, label.Name...)
}
b = append(b, '=')
b = strconv.AppendQuote(b, label.Value)
if i < len(labels)-1 {
b = append(b, ',')
}
}
b = append(b, '}')
return string(b)
}

View file

@ -0,0 +1,113 @@
package limits
import (
"flag"
"sync/atomic"
"time"
"github.com/VictoriaMetrics/metrics"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
)
const maxLabelNameLen = 256
var (
maxLabelsPerTimeseries = flag.Int("maxLabelsPerTimeseries", 30, "The maximum number of labels per time series to be accepted. Timeseries with superfluous labels are dropped. In this case the vm_series_dropped_total{reason=\"too_many_labels\"} metric at /metrics page is incremented")
maxLabelValueLen = flag.Int("maxLabelValueLen", 4*1024, "The maximum length of label values in the accepted time series. Metrics with longer label value are dropped. In this case the vm_series_dropped_total{reason=\"too_long_label_value\"} metric at /metrics page is incremented")
)
var (
droppedSeriesWithTooManyLabelsLogTicker = time.NewTicker(5 * time.Second)
droppedSeriesWithTooLongLabelNameLogTicker = time.NewTicker(5 * time.Second)
droppedSeriesWithTooLongLabelValueLogTicker = time.NewTicker(5 * time.Second)
)
var (
// droppedSeriesWithTooManyLabels is the number of dropped series with too many labels
droppedSeriesWithTooManyLabels atomic.Uint64
// droppedSeriesWithTooLongLabelName is the number of dropped series which contain labels with too long names
droppedSeriesWithTooLongLabelName atomic.Uint64
// droppedSeriesWithTooLongLabelValue is the number of dropped series which contain labels with too long values
droppedSeriesWithTooLongLabelValue atomic.Uint64
)
var (
_ = metrics.NewGauge(`vm_series_dropped_total{reason="too_many_labels"}`, func() float64 {
return float64(droppedSeriesWithTooManyLabels.Load())
})
_ = metrics.NewGauge(`vm_series_dropped_total{reason="too_long_label_name"}`, func() float64 {
return float64(droppedSeriesWithTooLongLabelName.Load())
})
_ = metrics.NewGauge(`vm_series_dropped_total{reason="too_long_label_value"}`, func() float64 {
return float64(droppedSeriesWithTooLongLabelValue.Load())
})
)
func trackDroppedSeriesWithTooManyLabels(labels []prompbmarshal.Label) {
droppedSeriesWithTooManyLabels.Add(1)
select {
case <-droppedSeriesWithTooManyLabelsLogTicker.C:
// Do not call logger.WithThrottler() here, since this will result in increased CPU usage
// because prompbmarshal.LabelsToString() will be called with each trackDroppedSeriesWithTooManyLabels call.
logger.Warnf("dropping series with %d labels for %s; either reduce the number of labels for this metric "+
"or increase -maxLabelsPerTimeseries=%d command-line flag value",
len(labels), prompbmarshal.LabelsToString(labels), *maxLabelsPerTimeseries)
default:
}
}
func trackDroppedSeriesWithTooLongLabelValue(l *prompbmarshal.Label, labels []prompbmarshal.Label) {
droppedSeriesWithTooLongLabelValue.Add(1)
select {
case <-droppedSeriesWithTooLongLabelValueLogTicker.C:
label := *l
// Do not call logger.WithThrottler() here, since this will result in increased CPU usage
// because prompbmarshal.LabelsToString() will be called with each trackDroppedSeriesWithTooLongLabelValue call.
logger.Warnf("drop series with a value %s for label %s because its length=%d exceeds -maxLabelValueLen=%d; "+
"original labels: %s; either reduce the label value length or increase -maxLabelValueLen command-line flag value",
label.Value, label.Name, len(label.Value), *maxLabelValueLen, prompbmarshal.LabelsToString(labels))
default:
}
}
func trackDroppedSeriesWithTooLongLabelName(l *prompbmarshal.Label, labels []prompbmarshal.Label) {
droppedSeriesWithTooLongLabelName.Add(1)
select {
case <-droppedSeriesWithTooLongLabelNameLogTicker.C:
label := *l
// Do not call logger.WithThrottler() here, since this will result in increased CPU usage
// because prompbmarshal.LabelsToString() will be called with each trackDroppedSeriesWithTooLongLabelName call.
logger.Warnf("drop series with a value for label %s because its length=%d exceeds %d; "+
"original labels: %s; consider reducing the label name length",
label.Name, len(label.Name), maxLabelNameLen, prompbmarshal.LabelsToString(labels))
default:
}
}
// ExceedingLabels checks if passed labels exceed one of the limits:
// * Maximum allowed labels limit
// * Maximum allowed label name length limit
// * Maximum allowed label value length limit
//
// increments metrics and shows warning in logs
func ExceedingLabels(labels []prompbmarshal.Label) bool {
if len(labels) > *maxLabelsPerTimeseries {
trackDroppedSeriesWithTooManyLabels(labels)
return true
}
for _, l := range labels {
if len(l.Name) > maxLabelNameLen {
trackDroppedSeriesWithTooLongLabelName(&l, labels)
return true
}
if len(l.Value) > *maxLabelValueLen {
trackDroppedSeriesWithTooLongLabelValue(&l, labels)
return true
}
}
return false
}

View file

@ -5,16 +5,12 @@ import (
"fmt" "fmt"
"runtime" "runtime"
"sort" "sort"
"strconv"
"strings" "strings"
"sync" "sync"
"sync/atomic"
"time"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil" "github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/encoding" "github.com/VictoriaMetrics/VictoriaMetrics/lib/encoding"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" "github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompb"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/slicesutil" "github.com/VictoriaMetrics/VictoriaMetrics/lib/slicesutil"
) )
@ -467,63 +463,15 @@ func (mn *MetricName) Unmarshal(src []byte) error {
return nil return nil
} }
// The maximum length of label name.
//
// Longer names are truncated.
const maxLabelNameLen = 256
// The maximum length of label value.
//
// Longer values are truncated.
var maxLabelValueLen = 1024
// SetMaxLabelValueLen sets the limit on the label value length.
//
// This function can be called before using the storage package.
//
// Label values with longer length are truncated.
func SetMaxLabelValueLen(n int) {
if n > 0 {
maxLabelValueLen = n
}
}
// The maximum number of labels per each timeseries.
var maxLabelsPerTimeseries = 30
// SetMaxLabelsPerTimeseries sets the limit on the number of labels
// per each time series.
//
// This function can be called before using the storage package.
//
// Superfluous labels are dropped.
func SetMaxLabelsPerTimeseries(maxLabels int) {
if maxLabels > 0 {
maxLabelsPerTimeseries = maxLabels
}
}
// MarshalMetricNameRaw marshals labels to dst and returns the result. // MarshalMetricNameRaw marshals labels to dst and returns the result.
// //
// The result must be unmarshaled with MetricName.UnmarshalRaw // The result must be unmarshaled with MetricName.UnmarshalRaw
func MarshalMetricNameRaw(dst []byte, labels []prompb.Label) []byte { func MarshalMetricNameRaw(dst []byte, labels []prompbmarshal.Label) []byte {
// Calculate the required space for dst. // Calculate the required space for dst.
dstLen := len(dst) dstLen := len(dst)
dstSize := dstLen dstSize := dstLen
for i := range labels { for i := range labels {
if i >= maxLabelsPerTimeseries {
trackDroppedLabels(labels, labels[i:])
break
}
label := &labels[i] label := &labels[i]
if len(label.Name) > maxLabelNameLen {
TooLongLabelNames.Add(1)
label.Name = label.Name[:maxLabelNameLen]
}
if len(label.Value) > maxLabelValueLen {
trackTruncatedLabels(labels, label)
label.Value = label.Value[:maxLabelValueLen]
}
if len(label.Value) == 0 { if len(label.Value) == 0 {
// Skip labels without values, since they have no sense in prometheus. // Skip labels without values, since they have no sense in prometheus.
continue continue
@ -539,9 +487,6 @@ func MarshalMetricNameRaw(dst []byte, labels []prompb.Label) []byte {
// Marshal labels to dst. // Marshal labels to dst.
for i := range labels { for i := range labels {
if i >= maxLabelsPerTimeseries {
break
}
label := &labels[i] label := &labels[i]
if len(label.Value) == 0 { if len(label.Value) == 0 {
// Skip labels without values, since they have no sense in prometheus. // Skip labels without values, since they have no sense in prometheus.
@ -553,71 +498,6 @@ func MarshalMetricNameRaw(dst []byte, labels []prompb.Label) []byte {
return dst return dst
} }
var (
// MetricsWithDroppedLabels is the number of metrics with at least a single dropped label
MetricsWithDroppedLabels atomic.Uint64
// TooLongLabelNames is the number of too long label names
TooLongLabelNames atomic.Uint64
// TooLongLabelValues is the number of too long label values
TooLongLabelValues atomic.Uint64
)
func trackDroppedLabels(labels, droppedLabels []prompb.Label) {
MetricsWithDroppedLabels.Add(1)
select {
case <-droppedLabelsLogTicker.C:
// Do not call logger.WithThrottler() here, since this will result in increased CPU usage
// because labelsToString() will be called with each trackDroppedLabels call.
logger.Warnf("dropping %d labels for %s; dropped labels: %s; either reduce the number of labels for this metric "+
"or increase -maxLabelsPerTimeseries=%d command-line flag value",
len(droppedLabels), labelsToString(labels), labelsToString(droppedLabels), maxLabelsPerTimeseries)
default:
}
}
func trackTruncatedLabels(labels []prompb.Label, truncated *prompb.Label) {
TooLongLabelValues.Add(1)
select {
case <-truncatedLabelsLogTicker.C:
// Do not call logger.WithThrottler() here, since this will result in increased CPU usage
// because labelsToString() will be called with each trackTruncatedLabels call.
logger.Warnf("truncate value for label %s because its length=%d exceeds -maxLabelValueLen=%d; "+
"original labels: %s; either reduce the label value length or increase -maxLabelValueLen command-line flag value",
truncated.Name, len(truncated.Value), maxLabelValueLen, labelsToString(labels))
default:
}
}
var (
droppedLabelsLogTicker = time.NewTicker(5 * time.Second)
truncatedLabelsLogTicker = time.NewTicker(5 * time.Second)
)
func labelsToString(labels []prompb.Label) string {
labelsCopy := append([]prompb.Label{}, labels...)
sort.Slice(labelsCopy, func(i, j int) bool {
return string(labelsCopy[i].Name) < string(labelsCopy[j].Name)
})
var b []byte
b = append(b, '{')
for i, label := range labelsCopy {
if len(label.Name) == 0 {
b = append(b, "__name__"...)
} else {
b = append(b, label.Name...)
}
b = append(b, '=')
b = strconv.AppendQuote(b, string(label.Value))
if i < len(labels)-1 {
b = append(b, ',')
}
}
b = append(b, '}')
return string(b)
}
// marshalRaw marshals mn to dst and returns the result. // marshalRaw marshals mn to dst and returns the result.
// //
// The results may be unmarshaled with MetricName.UnmarshalRaw. // The results may be unmarshaled with MetricName.UnmarshalRaw.