Repository: VictoriaMetrics/VictoriaMetrics
Pull request #5663 (2024-01-23 09:25:26)

lib/promscrape: respect `0` value for `series_limit` param
Respect `0` value for `series_limit` param in `scrape_config` even if global limit was set via `-promscrape.seriesLimitPerTarget`. Previously, `0` value will be ignored in favor of `-promscrape.seriesLimitPerTarget`.

This behavior aligns with possibility to override `series_limit` value via relabeling with `__series_limit__` label.

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/VictoriaMetrics/VictoriaMetrics/pull/5663?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VictoriaMetrics) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Comparison is base [(`15a15e5`)](https://app.codecov.io/gh/VictoriaMetrics/VictoriaMetrics/commit/15a15e5b99eea8962448028f00498d6619663c2c?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VictoriaMetrics) 60.01% compared to head [(`f24431e`)](https://app.codecov.io/gh/VictoriaMetrics/VictoriaMetrics/pull/5663?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VictoriaMetrics) 60.00%.


<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           master    #5663      +/-   ##
==========================================
- Coverage   60.01%   60.00%   -0.01%     
==========================================
  Files         409      409              
  Lines       76383    76383              
==========================================
- Hits        45841    45836       -5     
- Misses      27999    28003       +4     
- Partials     2543     2544       +1     
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/VictoriaMetrics/VictoriaMetrics/pull/5663?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VictoriaMetrics).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VictoriaMetrics).


Patch:
diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md
index 226f782cd..2b36f335a 100644
--- a/docs/CHANGELOG.md
+++ b/docs/CHANGELOG.md
@@ -76,6 +76,7 @@ The sandbox cluster installation is running under the constant load generated by
 * BUGFIX: [vmagent](https://docs.victoriametrics.com/vmagent.html): properly assume role with [AWS IRSA authorization](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html). Previously role chaining was not supported. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3822) for details.
 * BUGFIX: [vmagent](https://docs.victoriametrics.com/vmagent.html): exit if there is config syntax error in [`scrape_config_files`](https://docs.victoriametrics.com/vmagent.html#loading-scrape-configs-from-multiple-files) when `-promscrape.config.strictParse=true`. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5508).
 * BUGFIX: [vmagent](https://docs.victoriametrics.com/vmagent.html): properly discover targets for `role: endpoints` and `role: endpointslice` in [kubernetes_sd_configs](https://docs.victoriametrics.com/sd_configs.html#kubernetes_sd_configs). Previously some `endpoints` and `endpointslice` targets could be left undiscovered or some targets could have missing `__meta_*` labels when performing service discovery in busy Kubernetes clusters with large number of pods. See [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/5557).
+* BUGFIX: [vmagent](https://docs.victoriametrics.com/vmagent.html): respect explicitly set `series_limit: 0` in [scrape_config](https://docs.victoriametrics.com/sd_configs.html#scrape_configs). This allows removing [`series_limit` restriction](https://docs.victoriametrics.com/vmagent.html#cardinality-limiter) on a per-`scrape_config` basis when global limit is set via `-promscrape.seriesLimitPerTarget`. Previously, `0` value was ignored in favor of `-promscrape.seriesLimitPerTarget`.
 * BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): fix a link for the statistic inaccuracy explanation in the cardinality explorer tool. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5460).
 * BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): fix the display of autocomplete results and cache the results. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5472) and [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5470).
 * BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): send `step` param for instant queries. The change reverts [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3896) due to reasons explained in [this comment](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3896#issuecomment-1896704401).
diff --git a/docs/anomaly-detection/CHANGELOG.md b/docs/anomaly-detection/CHANGELOG.md
index cfe79b711..845ef2479 100644
--- a/docs/anomaly-detection/CHANGELOG.md
+++ b/docs/anomaly-detection/CHANGELOG.md
@@ -20,14 +20,14 @@ The following `tip` changes can be tested by building from the `latest` tag:
 docker pull us-docker.pkg.dev/victoriametrics-test/public/vmanomaly-trial:latest
 ```
 
-Please find [launch instructions here](/anomaly-detection/overview.html#run-vmanomaly-docker-container).
+Please find [launch instructions here](/anomaly-detection/Overview.html#run-vmanomaly-docker-container).
 
 # tip
 
 
 ## v1.8.0
 Released: 2024-01-15
-- FEATURE: Added Univariate [MAD (median absolute deviation)](/anomaly-detection/components/models.md#mad-median-absolute-deviation) model support.
+- FEATURE: Added Univariate [MAD (median absolute deviation)](/anomaly-detection/components/models.html#mad-median-absolute-deviation) model support.
 - IMPROVEMENT: Update Python to 3.12.1 and all the dependencies.
 - IMPROVEMENT: Don't check /health endpoint, check the real /query_range or /import endpoints directly. Users kept getting problems with /health.
 - DEPRECATION: "health_path" param is deprecated and doesn't do anything in config ([reader](/anomaly-detection/components/reader.html#vm-reader), [writer](/anomaly-detection/components/writer.html#vm-writer), [monitoring.push](/anomaly-detection/components/monitoring.html#push-config-parameters)).
diff --git a/docs/anomaly-detection/Overview.md b/docs/anomaly-detection/Overview.md
index b16d0cbe3..993cffb29 100644
--- a/docs/anomaly-detection/Overview.md
+++ b/docs/anomaly-detection/Overview.md
@@ -9,6 +9,7 @@ menu:
     weight: 1
 aliases:
 - /anomaly-detection.html
+- /anomaly-detection/overview.html
 ---
 
 
diff --git a/docs/anomaly-detection/guides/README.md b/docs/anomaly-detection/guides/README.md
index d72bb9a94..ace726f76 100644
--- a/docs/anomaly-detection/guides/README.md
+++ b/docs/anomaly-detection/guides/README.md
@@ -12,7 +12,7 @@ aliases:
 
 # Guides
 
-This section holds guides of how to set up and use VictoriaMetrics Anomaly Detection (or simply [`vmanomaly`](/anomaly-detection/overview.html)) service, integrating it with different observability components.
+This section holds guides of how to set up and use VictoriaMetrics Anomaly Detection (or simply [`vmanomaly`](/anomaly-detection/Overview.html)) service, integrating it with different observability components.
 
 Guides: 
 
diff --git a/docs/anomaly-detection/guides/guide-vmanomaly-vmalert.md b/docs/anomaly-detection/guides/guide-vmanomaly-vmalert.md
index b0d1b738b..fcedc81b9 100644
--- a/docs/anomaly-detection/guides/guide-vmanomaly-vmalert.md
+++ b/docs/anomaly-detection/guides/guide-vmanomaly-vmalert.md
@@ -32,7 +32,7 @@ aliases:
 
 ## 1. What is vmanomaly?
 
-*VictoriaMetrics Anomaly Detection* ([vmanomaly](https://docs.victoriametrics.com/anomaly-detection/overview.html)) is a service that continuously scans time series stored in VictoriaMetrics and detects unexpected changes within data patterns in real-time. It does so by utilizing user-configurable machine learning models.
+*VictoriaMetrics Anomaly Detection* ([vmanomaly](https://docs.victoriametrics.com/anomaly-detection/Overview.html)) is a service that continuously scans time series stored in VictoriaMetrics and detects unexpected changes within data patterns in real-time. It does so by utilizing user-configurable machine learning models.
 
 All the service parameters are defined in a config file.
 
@@ -67,8 +67,8 @@ Compared to classical alerting rules, anomaly detection is more "hands-off" and
 Practical use case is to put anomaly score generated by vmanomaly into alerting rules with some threshold. 
 
 **In this tutorial we are going to:**
-  - Configure docker-compose file with all needed services ([VictoriaMetrics Single-Node](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html), [vmalert](https://docs.victoriametrics.com/vmalert.html), [vmagent](https://docs.victoriametrics.com/vmagent.html), [Grafana](https://grafana.com/), [Node Exporter](https://prometheus.io/docs/guides/node-exporter/) and [vmanomaly](https://docs.victoriametrics.com/anomaly-detection/overview.html) ).
-  - Explore configuration files for [vmanomaly](https://docs.victoriametrics.com/anomaly-detection/overview.html) and [vmalert](https://docs.victoriametrics.com/vmalert.html).
+  - Configure docker-compose file with all needed services ([VictoriaMetrics Single-Node](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html), [vmalert](https://docs.victoriametrics.com/vmalert.html), [vmagent](https://docs.victoriametrics.com/vmagent.html), [Grafana](https://grafana.com/), [Node Exporter](https://prometheus.io/docs/guides/node-exporter/) and [vmanomaly](https://docs.victoriametrics.com/anomaly-detection/Overview.html) ).
+  - Explore configuration files for [vmanomaly](https://docs.victoriametrics.com/anomaly-detection/Overview.html) and [vmalert](https://docs.victoriametrics.com/vmalert.html).
   - Run our own [VictoriaMetrics](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html) database with data scraped from [Node Exporter](https://prometheus.io/docs/guides/node-exporter/).
   - Explore data for analysis in [Grafana](https://grafana.com/).
   - Explore `vmanomaly` results.
@@ -271,10 +271,12 @@ scrape_configs:
 
 </div>
 
-### vmanomaly licencing
+### vmanomaly licensing
+
+We will utilize the license key stored locally in the file `vmanomaly_license.txt`.
+
+For additional licensing options, please refer to the [VictoriaMetrics Anomaly Detection documentation on licensing](https://docs.victoriametrics.com/anomaly-detection/Overview#licensing).
 
-We are going to use license stored locally in file `vmanomaly_license.txt` with key in it.
-You can explore other license options [here](https://docs.victoriametrics.com/anomaly-detection/overview#licensing)
 
 ### Alertmanager setup 
 
diff --git a/lib/mergeset/merge.go b/lib/mergeset/merge.go
index 3f443c2f7..df8a7fcd6 100644
--- a/lib/mergeset/merge.go
+++ b/lib/mergeset/merge.go
@@ -129,8 +129,8 @@ again:
 	if bsr.currItemIdx < len(items) {
 		// An optimization, which allows skipping costly comparison for every merged item in the loop below.
 		// Thanks to @ahfuzhang for the suggestion at https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5651
-		lastItem := items[len(items)-1].Bytes(data)
-		compareEveryItem = hasNextItem && string(lastItem) > nextItem
+		lastItem := items[len(items)-1].String(data)
+		compareEveryItem = hasNextItem && lastItem > nextItem
 	}
 	for bsr.currItemIdx < len(items) {
 		item := items[bsr.currItemIdx].Bytes(data)
@@ -183,12 +183,12 @@ func (bsm *blockStreamMerger) flushIB(bsw *blockStreamWriter, ph *partHeader, it
 		}
 		// Consistency checks after prepareBlock call.
 		firstItem := items[0].String(data)
-		if firstItem != string(bsm.firstItem) {
-			logger.Panicf("BUG: prepareBlock must return first item equal to the original first item;\ngot\n%X\nwant\n%X", firstItem, bsm.firstItem)
+		if firstItem < string(bsm.firstItem) {
+			logger.Panicf("BUG: prepareBlock must return the first item bigger or equal to the original first item;\ngot\n%X\nwant\n%X", firstItem, bsm.firstItem)
 		}
 		lastItem := items[len(items)-1].String(data)
-		if lastItem != string(bsm.lastItem) {
-			logger.Panicf("BUG: prepareBlock must return last item equal to the original last item;\ngot\n%X\nwant\n%X", lastItem, bsm.lastItem)
+		if lastItem > string(bsm.lastItem) {
+			logger.Panicf("BUG: prepareBlock must return the last item smaller or equal to the original last item;\ngot\n%X\nwant\n%X", lastItem, bsm.lastItem)
 		}
 		// Verify whether the bsm.ib.items are sorted only in tests, since this
 		// can be expensive check in prod for items with long common prefix.
diff --git a/lib/promscrape/config.go b/lib/promscrape/config.go
index 156707de0..323395c0a 100644
--- a/lib/promscrape/config.go
+++ b/lib/promscrape/config.go
@@ -322,7 +322,7 @@ type ScrapeConfig struct {
 	StreamParse         bool                       `yaml:"stream_parse,omitempty"`
 	ScrapeAlignInterval *promutils.Duration        `yaml:"scrape_align_interval,omitempty"`
 	ScrapeOffset        *promutils.Duration        `yaml:"scrape_offset,omitempty"`
-	SeriesLimit         int                        `yaml:"series_limit,omitempty"`
+	SeriesLimit         *int                       `yaml:"series_limit,omitempty"`
 	NoStaleMarkers      *bool                      `yaml:"no_stale_markers,omitempty"`
 	ProxyClientConfig   promauth.ProxyClientConfig `yaml:",inline"`
 
@@ -876,8 +876,8 @@ func getScrapeWorkConfig(sc *ScrapeConfig, baseDir string, globalCfg *GlobalConf
 		noStaleTracking = *sc.NoStaleMarkers
 	}
 	seriesLimit := *seriesLimitPerTarget
-	if sc.SeriesLimit > 0 {
-		seriesLimit = sc.SeriesLimit
+	if sc.SeriesLimit != nil {
+		seriesLimit = *sc.SeriesLimit
 	}
 	swc := &scrapeWorkConfig{
 		scrapeInterval:       scrapeInterval,


Test patch:
diff --git a/lib/promscrape/config_test.go b/lib/promscrape/config_test.go
index 64473229d..950e455d2 100644
--- a/lib/promscrape/config_test.go
+++ b/lib/promscrape/config_test.go
@@ -1190,6 +1190,29 @@ scrape_configs:
 			jobNameOriginal: "foo",
 		},
 	})
+
+	defaultSeriesLimitPerTarget := *seriesLimitPerTarget
+	*seriesLimitPerTarget = 1e3
+	f(`
+scrape_configs:
+- job_name: foo
+  series_limit: 0
+  static_configs:
+  - targets: ["foo.bar:1234"]
+`, []*ScrapeWork{
+		{
+			ScrapeURL:       "http://foo.bar:1234/metrics",
+			ScrapeInterval:  defaultScrapeInterval,
+			ScrapeTimeout:   defaultScrapeTimeout,
+			jobNameOriginal: "foo",
+			Labels: promutils.NewLabelsFromMap(map[string]string{
+				"instance": "foo.bar:1234",
+				"job":      "foo",
+			}),
+			SeriesLimit: 0,
+		},
+	})
+	*seriesLimitPerTarget = defaultSeriesLimitPerTarget
 }
 
 func equalStaticConfigForScrapeWorks(a, b []*ScrapeWork) bool {