mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2026-08-05 23:36:27 +03:00
Compare commits
4 Commits
master
...
issue-1129
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
28a1fbdb4a | ||
|
|
c1d342ff02 | ||
|
|
db93881959 | ||
|
|
b39fd34106 |
16
.github/workflows/build.yml
vendored
16
.github/workflows/build.yml
vendored
@@ -73,19 +73,11 @@ jobs:
|
||||
id: go
|
||||
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
||||
with:
|
||||
cache: false
|
||||
cache-dependency-path: |
|
||||
go.sum
|
||||
Makefile
|
||||
app/**/Makefile
|
||||
go-version-file: 'go.mod'
|
||||
|
||||
- name: Cache Go build artifacts
|
||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: go-build-${{ matrix.os }}-${{ matrix.arch }}-${{ hashFiles('go.sum', 'Makefile') }}
|
||||
restore-keys: |
|
||||
go-build-${{ matrix.os }}-${{ matrix.arch }}-
|
||||
|
||||
- run: go version
|
||||
|
||||
- name: Build victoria-metrics for ${{ matrix.os }}-${{ matrix.arch }}
|
||||
|
||||
@@ -3,7 +3,7 @@ services:
|
||||
# It scrapes targets defined in --promscrape.config
|
||||
# And forward them to --remoteWrite.url
|
||||
vmagent:
|
||||
image: victoriametrics/vmagent:v1.149.0
|
||||
image: victoriametrics/vmagent:v1.148.0
|
||||
depends_on:
|
||||
- "vmauth"
|
||||
ports:
|
||||
@@ -42,14 +42,14 @@ services:
|
||||
# vmstorage shards. Each shard receives 1/N of all metrics sent to vminserts,
|
||||
# where N is number of vmstorages (2 in this case).
|
||||
vmstorage-1:
|
||||
image: victoriametrics/vmstorage:v1.149.0-cluster
|
||||
image: victoriametrics/vmstorage:v1.148.0-cluster
|
||||
volumes:
|
||||
- strgdata-1:/storage
|
||||
command:
|
||||
- "--storageDataPath=/storage"
|
||||
restart: always
|
||||
vmstorage-2:
|
||||
image: victoriametrics/vmstorage:v1.149.0-cluster
|
||||
image: victoriametrics/vmstorage:v1.148.0-cluster
|
||||
volumes:
|
||||
- strgdata-2:/storage
|
||||
command:
|
||||
@@ -59,7 +59,7 @@ services:
|
||||
# vminsert is ingestion frontend. It receives metrics pushed by vmagent,
|
||||
# pre-process them and distributes across configured vmstorage shards.
|
||||
vminsert-1:
|
||||
image: victoriametrics/vminsert:v1.149.0-cluster
|
||||
image: victoriametrics/vminsert:v1.148.0-cluster
|
||||
depends_on:
|
||||
- "vmstorage-1"
|
||||
- "vmstorage-2"
|
||||
@@ -68,7 +68,7 @@ services:
|
||||
- "--storageNode=vmstorage-2:8400"
|
||||
restart: always
|
||||
vminsert-2:
|
||||
image: victoriametrics/vminsert:v1.149.0-cluster
|
||||
image: victoriametrics/vminsert:v1.148.0-cluster
|
||||
depends_on:
|
||||
- "vmstorage-1"
|
||||
- "vmstorage-2"
|
||||
@@ -80,7 +80,7 @@ services:
|
||||
# vmselect is a query fronted. It serves read queries in MetricsQL or PromQL.
|
||||
# vmselect collects results from configured `--storageNode` shards.
|
||||
vmselect-1:
|
||||
image: victoriametrics/vmselect:v1.149.0-cluster
|
||||
image: victoriametrics/vmselect:v1.148.0-cluster
|
||||
depends_on:
|
||||
- "vmstorage-1"
|
||||
- "vmstorage-2"
|
||||
@@ -90,7 +90,7 @@ services:
|
||||
- "--vmalert.proxyURL=http://vmalert:8880"
|
||||
restart: always
|
||||
vmselect-2:
|
||||
image: victoriametrics/vmselect:v1.149.0-cluster
|
||||
image: victoriametrics/vmselect:v1.148.0-cluster
|
||||
depends_on:
|
||||
- "vmstorage-1"
|
||||
- "vmstorage-2"
|
||||
@@ -105,7 +105,7 @@ services:
|
||||
# read requests from Grafana, vmui, vmalert among vmselects.
|
||||
# It can be used as an authentication proxy.
|
||||
vmauth:
|
||||
image: victoriametrics/vmauth:v1.149.0
|
||||
image: victoriametrics/vmauth:v1.148.0
|
||||
depends_on:
|
||||
- "vmselect-1"
|
||||
- "vmselect-2"
|
||||
@@ -119,7 +119,7 @@ services:
|
||||
|
||||
# vmalert executes alerting and recording rules
|
||||
vmalert:
|
||||
image: victoriametrics/vmalert:v1.149.0
|
||||
image: victoriametrics/vmalert:v1.148.0
|
||||
depends_on:
|
||||
- "vmauth"
|
||||
ports:
|
||||
|
||||
@@ -3,7 +3,7 @@ services:
|
||||
# It scrapes targets defined in --promscrape.config
|
||||
# And forward them to --remoteWrite.url
|
||||
vmagent:
|
||||
image: victoriametrics/vmagent:v1.149.0
|
||||
image: victoriametrics/vmagent:v1.148.0
|
||||
depends_on:
|
||||
- "victoriametrics"
|
||||
ports:
|
||||
@@ -18,7 +18,7 @@ services:
|
||||
# VictoriaMetrics instance, a single process responsible for
|
||||
# storing metrics and serve read requests.
|
||||
victoriametrics:
|
||||
image: victoriametrics/victoria-metrics:v1.149.0
|
||||
image: victoriametrics/victoria-metrics:v1.148.0
|
||||
ports:
|
||||
- 8428:8428
|
||||
- 8089:8089
|
||||
@@ -59,7 +59,7 @@ services:
|
||||
|
||||
# vmalert executes alerting and recording rules
|
||||
vmalert:
|
||||
image: victoriametrics/vmalert:v1.149.0
|
||||
image: victoriametrics/vmalert:v1.148.0
|
||||
depends_on:
|
||||
- "victoriametrics"
|
||||
- "alertmanager"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
services:
|
||||
vmagent:
|
||||
image: victoriametrics/vmagent:v1.149.0
|
||||
image: victoriametrics/vmagent:v1.148.0
|
||||
depends_on:
|
||||
- "victoriametrics"
|
||||
ports:
|
||||
@@ -14,7 +14,7 @@ services:
|
||||
restart: always
|
||||
|
||||
victoriametrics:
|
||||
image: victoriametrics/victoria-metrics:v1.149.0
|
||||
image: victoriametrics/victoria-metrics:v1.148.0
|
||||
ports:
|
||||
- 8428:8428
|
||||
volumes:
|
||||
@@ -40,7 +40,7 @@ services:
|
||||
restart: always
|
||||
|
||||
vmalert:
|
||||
image: victoriametrics/vmalert:v1.149.0
|
||||
image: victoriametrics/vmalert:v1.148.0
|
||||
depends_on:
|
||||
- "victoriametrics"
|
||||
ports:
|
||||
|
||||
@@ -10,9 +10,9 @@ sitemap:
|
||||
|
||||
- To use *vmanomaly*, part of the enterprise package, a license key is required. Obtain your key [here](https://victoriametrics.com/products/enterprise/trial/) for this tutorial or for enterprise use.
|
||||
- In the tutorial, we'll be using the following VictoriaMetrics components:
|
||||
- [VictoriaMetrics Single-Node](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/) (v1.149.0)
|
||||
- [vmalert](https://docs.victoriametrics.com/victoriametrics/vmalert/) (v1.149.0)
|
||||
- [vmagent](https://docs.victoriametrics.com/victoriametrics/vmagent/) (v1.149.0)
|
||||
- [VictoriaMetrics Single-Node](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/) (v1.148.0)
|
||||
- [vmalert](https://docs.victoriametrics.com/victoriametrics/vmalert/) (v1.148.0)
|
||||
- [vmagent](https://docs.victoriametrics.com/victoriametrics/vmagent/) (v1.148.0)
|
||||
- [Grafana](https://grafana.com/) (v12.2.0)
|
||||
- [Docker](https://docs.docker.com/get-docker/) and [Docker Compose](https://docs.docker.com/compose/)
|
||||
- [Node exporter](https://github.com/prometheus/node_exporter#node-exporter) (v1.9.1) and [Alertmanager](https://prometheus.io/docs/alerting/latest/alertmanager/) (v0.28.1)
|
||||
@@ -323,7 +323,7 @@ Let's wrap it all up together into the `docker-compose.yml` file.
|
||||
services:
|
||||
vmagent:
|
||||
container_name: vmagent
|
||||
image: victoriametrics/vmagent:v1.149.0
|
||||
image: victoriametrics/vmagent:v1.148.0
|
||||
depends_on:
|
||||
- "victoriametrics"
|
||||
ports:
|
||||
@@ -340,7 +340,7 @@ services:
|
||||
|
||||
victoriametrics:
|
||||
container_name: victoriametrics
|
||||
image: victoriametrics/victoria-metrics:v1.149.0
|
||||
image: victoriametrics/victoria-metrics:v1.148.0
|
||||
ports:
|
||||
- 8428:8428
|
||||
volumes:
|
||||
@@ -373,7 +373,7 @@ services:
|
||||
|
||||
vmalert:
|
||||
container_name: vmalert
|
||||
image: victoriametrics/vmalert:v1.149.0
|
||||
image: victoriametrics/vmalert:v1.148.0
|
||||
depends_on:
|
||||
- "victoriametrics"
|
||||
ports:
|
||||
|
||||
@@ -240,23 +240,23 @@ vmagent will write data into VictoriaMetrics single-node and cluster (with tenan
|
||||
# compose.yaml
|
||||
services:
|
||||
vmsingle:
|
||||
image: victoriametrics/victoria-metrics:v1.149.0
|
||||
image: victoriametrics/victoria-metrics:v1.148.0
|
||||
|
||||
vmstorage:
|
||||
image: victoriametrics/vmstorage:v1.149.0-cluster
|
||||
image: victoriametrics/vmstorage:v1.148.0-cluster
|
||||
|
||||
vminsert:
|
||||
image: victoriametrics/vminsert:v1.149.0-cluster
|
||||
image: victoriametrics/vminsert:v1.148.0-cluster
|
||||
command:
|
||||
- -storageNode=vmstorage:8400
|
||||
|
||||
vmselect:
|
||||
image: victoriametrics/vmselect:v1.149.0-cluster
|
||||
image: victoriametrics/vmselect:v1.148.0-cluster
|
||||
command:
|
||||
- -storageNode=vmstorage:8401
|
||||
|
||||
vmagent:
|
||||
image: victoriametrics/vmagent:v1.149.0
|
||||
image: victoriametrics/vmagent:v1.148.0
|
||||
volumes:
|
||||
- ./scrape.yaml:/etc/vmagent/config.yaml
|
||||
command:
|
||||
@@ -308,7 +308,7 @@ Now add the vmauth service to `compose.yaml`:
|
||||
# compose.yaml
|
||||
services:
|
||||
vmauth:
|
||||
image: docker.io/victoriametrics/vmauth:v1.149.0
|
||||
image: docker.io/victoriametrics/vmauth:v1.148.0
|
||||
ports:
|
||||
- 8427:8427
|
||||
volumes:
|
||||
|
||||
@@ -155,15 +155,15 @@ These services will store and query the metrics scraped by vmagent.
|
||||
# compose.yaml
|
||||
services:
|
||||
vmstorage:
|
||||
image: victoriametrics/vmstorage:v1.149.0-cluster
|
||||
image: victoriametrics/vmstorage:v1.148.0-cluster
|
||||
|
||||
vminsert:
|
||||
image: victoriametrics/vminsert:v1.149.0-cluster
|
||||
image: victoriametrics/vminsert:v1.148.0-cluster
|
||||
command:
|
||||
- -storageNode=vmstorage:8400
|
||||
|
||||
vmselect:
|
||||
image: victoriametrics/vmselect:v1.149.0-cluster
|
||||
image: victoriametrics/vmselect:v1.148.0-cluster
|
||||
command:
|
||||
- -storageNode=vmstorage:8401
|
||||
ports:
|
||||
@@ -196,7 +196,7 @@ Add the vmauth service to `compose.yaml`:
|
||||
# compose.yaml
|
||||
services:
|
||||
vmauth:
|
||||
image: victoriametrics/vmauth:v1.149.0-enterprise
|
||||
image: victoriametrics/vmauth:v1.148.0-enterprise
|
||||
ports:
|
||||
- 8427:8427
|
||||
volumes:
|
||||
@@ -251,7 +251,7 @@ Add the vmagent service to `compose.yaml` with OAuth2 configuration:
|
||||
# compose.yaml
|
||||
services:
|
||||
vmagent:
|
||||
image: victoriametrics/vmagent:v1.149.0
|
||||
image: victoriametrics/vmagent:v1.148.0
|
||||
volumes:
|
||||
- ./scrape.yaml:/etc/vmagent/config.yaml
|
||||
command:
|
||||
|
||||
@@ -107,7 +107,7 @@ The final piece is the Docker Compose file. This ties all the services together
|
||||
# compose.yml
|
||||
services:
|
||||
victoriametrics:
|
||||
image: victoriametrics/victoria-metrics:v1.149.0
|
||||
image: victoriametrics/victoria-metrics:v1.148.0
|
||||
command:
|
||||
- "--storageDataPath=/victoria-metrics-data"
|
||||
- "--selfScrapeInterval=10s"
|
||||
@@ -128,7 +128,7 @@ services:
|
||||
- ./alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro
|
||||
|
||||
vmalert:
|
||||
image: victoriametrics/vmalert:v1.149.0
|
||||
image: victoriametrics/vmalert:v1.148.0
|
||||
depends_on:
|
||||
- victoriametrics
|
||||
- alertmanager
|
||||
|
||||
@@ -27,5 +27,5 @@ to [the latest available releases](https://docs.victoriametrics.com/victoriametr
|
||||
|
||||
## Currently supported LTS release lines
|
||||
|
||||
- v1.148.x - the latest one is [v1.148.1 LTS release](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.148.1)
|
||||
- v1.136.x - the latest one is [v1.136.15 LTS release](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.136.15)
|
||||
- v1.148.x - the latest one is [v1.148.0 LTS release](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.148.0)
|
||||
- v1.136.x - the latest one is [v1.136.14 LTS release](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.136.14)
|
||||
|
||||
@@ -53,8 +53,8 @@ and unpack it. It contains a single `victoria-metrics-prod` binary.
|
||||
For example, on Linux with `amd64` architecture:
|
||||
|
||||
```sh
|
||||
wget https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.149.0/victoria-metrics-linux-amd64-v1.149.0.tar.gz
|
||||
tar xzf victoria-metrics-linux-amd64-v1.149.0.tar.gz
|
||||
wget https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.148.0/victoria-metrics-linux-amd64-v1.148.0.tar.gz
|
||||
tar xzf victoria-metrics-linux-amd64-v1.148.0.tar.gz
|
||||
```
|
||||
|
||||
The binary is self-contained and requires no installation - it is ready to run as is.
|
||||
@@ -229,9 +229,9 @@ Download the newest available [VictoriaMetrics release](https://docs.victoriamet
|
||||
from [DockerHub](https://hub.docker.com/r/victoriametrics/victoria-metrics) or [Quay](https://quay.io/repository/victoriametrics/victoria-metrics?tab=tags):
|
||||
|
||||
```sh
|
||||
docker pull victoriametrics/victoria-metrics:v1.149.0
|
||||
docker pull victoriametrics/victoria-metrics:v1.148.0
|
||||
docker run -it --rm -v `pwd`/victoria-metrics-data:/victoria-metrics-data -p 8428:8428 \
|
||||
victoriametrics/victoria-metrics:v1.149.0 --selfScrapeInterval=5s -storageDataPath=victoria-metrics-data
|
||||
victoriametrics/victoria-metrics:v1.148.0 --selfScrapeInterval=5s -storageDataPath=victoria-metrics-data
|
||||
```
|
||||
|
||||
_For Enterprise images, see [this link](https://docs.victoriametrics.com/victoriametrics/enterprise/#docker-images)._
|
||||
|
||||
@@ -25,10 +25,11 @@ The sandbox cluster installation runs under the constant load generated by
|
||||
See also [LTS releases](https://docs.victoriametrics.com/victoriametrics/lts-releases/).
|
||||
|
||||
## tip
|
||||
* BUGFIX: [vmsingle](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/), `vmstorage` and `vmselect` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/): persist the previous working set cache during graceful shutdown when it is likely to contain the active working set. This prevents saving an empty or cold current cache right after split-mode cache rotation, which could otherwise slow down ingestion or queries after restart until the cache warms up again. See [#11299](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/11299).
|
||||
|
||||
## [v1.149.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.149.0)
|
||||
|
||||
Released at 2026-08-05
|
||||
Release candidate
|
||||
|
||||
**Update Note 1:** `vminsert` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/): the default value of `-disableRerouting` flag has changed from `true` to `false`, enabling [slowness-based re-routing](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/#slowness-based-re-routing) by default. Slowness re-routing is automatically disabled when `-replicationFactor` is greater than 1. If you rely on the old behavior, pass `-disableRerouting` command-line flag to `vminsert`. See [#11287](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/11287).
|
||||
|
||||
@@ -53,25 +54,6 @@ Released at 2026-08-05
|
||||
* BUGFIX: [stream aggregation](https://docs.victoriametrics.com/victoriametrics/stream-aggregation/): fix incorrect [sum_samples_total](https://docs.victoriametrics.com/victoriametrics/stream-aggregation/configuration/#sum_samples_total) results when `enable_windows: true` is set. See [#11261](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/11261). Thanks to @beyond-infra for contribution.
|
||||
* BUGFIX: [vmsingle](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/), `vmselect` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/) and [vmctl](https://docs.victoriametrics.com/victoriametrics/vmctl/): accept scientific notation with sub-second precision (e.g. `1.784144612388E9`) for timestamp args such as `start` and `end` in `/api/v1/query_range` and `--vm-native-filter-time-start` and `--vm-native-filter-time-end` in `vmctl`. Previously, values with this pattern were rejected, which is incompatible with Prometheus. See [#11268](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/11268). Thanks to @STiFLeR7 for contribution.
|
||||
|
||||
## [v1.148.1](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.148.1)
|
||||
|
||||
Released at 2026-07-31
|
||||
|
||||
**v1.148.x is a line of [LTS releases](https://docs.victoriametrics.com/victoriametrics/lts-releases/). It contains important up-to-date bugfixes for [VictoriaMetrics enterprise](https://docs.victoriametrics.com/victoriametrics/enterprise/).
|
||||
All these fixes are also included in [the latest community release](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest).
|
||||
The v1.148.x line will be supported for at least 12 months since [v1.148.0](https://docs.victoriametrics.com/victoriametrics/changelog/#v11480) release**
|
||||
|
||||
**Update Note 1:** [vmsingle](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/) and `vmselect` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/): the `/api/v1/admin/tsdb/delete_series`, `/tags/delSeries` endpoints now require `POST` method. Previously, it also accepted `GET` requests. If you use `GET` requests for this endpoint, update your scripts or tooling to use `POST` instead. See [#5552](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5552).
|
||||
|
||||
* SECURITY: [vmsingle](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/) and `vmselect` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/): restrict `/api/v1/admin/tsdb/delete_series`, `/tags/delSeries` endpoints to `POST` method only to prevent some [SSRF](https://en.wikipedia.org/wiki/Server-side_request_forgery)-based data deletion attacks. See [#5552](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5552).
|
||||
|
||||
* BUGFIX: [MetricsQL](https://docs.victoriametrics.com/victoriametrics/metricsql/): properly drop data points filtered out by an inner [comparison operation](https://prometheus.io/docs/prometheus/latest/querying/operators/#comparison-binary-operators) when its result is used on the right side of another comparison. Previously, queries like `foo != (bar > 100)` could return unexpected results because filtered-out data points are represented internally as `NaN`, and `value != NaN` evaluates to `true`. Comparisons against explicitly present `NaN` values keep the previous behavior. See [#10018](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/10018). Thanks to @zasdaym for contribution.
|
||||
* BUGFIX: [vmagent](https://docs.victoriametrics.com/victoriametrics/vmagent/) and [vmsingle](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/): ignore HTTP proxy environment variables when scraping targets over Unix domain sockets. See [#11318](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/11318). Thanks to @lwmacct for contribution.
|
||||
* BUGFIX: [vmalert](https://docs.victoriametrics.com/victoriametrics/vmalert/): fixed the display of rule state badges on the `Groups` page in the web UI. See [#11160](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/11160).
|
||||
* BUGFIX: [vmbackupmanager](https://docs.victoriametrics.com/victoriametrics/vmbackupmanager/): previously, `vmbackupmanager` was crashing on startup when it failed to restore backup state from remote storage, causing a crash loop. Now it logs the error and continues running, retrying the state restore before each scheduled backup. Added `vm_backup_errors_total{type="restoreState"}` metric to track backup state restore failures. See [#11217](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/11217).
|
||||
* BUGFIX: [stream aggregation](https://docs.victoriametrics.com/victoriametrics/stream-aggregation/): fix incorrect [sum_samples_total](https://docs.victoriametrics.com/victoriametrics/stream-aggregation/configuration/#sum_samples_total) results when `enable_windows: true` is set. See [#11261](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/11261). Thanks to @beyond-infra for contribution.
|
||||
* BUGFIX: [vmsingle](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/), `vmselect` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/) and [vmctl](https://docs.victoriametrics.com/victoriametrics/vmctl/): accept scientific notation with sub-second precision (e.g. `1.784144612388E9`) for timestamp args such as `start` and `end` in `/api/v1/query_range` and `--vm-native-filter-time-start` and `--vm-native-filter-time-end` in `vmctl`. Previously, values with this pattern were rejected, which is incompatible with Prometheus. See [#11268](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/11268). Thanks to @STiFLeR7 for contribution.
|
||||
|
||||
## [v1.148.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.148.0)
|
||||
|
||||
Released at 2026-07-20
|
||||
@@ -394,20 +376,6 @@ It enables back `Discovered targets` debug UI by default.
|
||||
* BUGFIX: `vmstorage` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/): properly apply `extra_filters[]` filter when querying `vm_account_id` or `vm_project_id` labels via [multitenant](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/#multitenancy) request for `/api/v1/label/…/values` API. Before, `extra_filters` was ignored. See [#10503](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/10503).
|
||||
* BUGFIX: [vmsingle](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/) and `vmselect` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/): revert the use of rollup result cache for [instant queries](https://docs.victoriametrics.com/keyConcepts.html#instant-query) that contain [`rate`](https://docs.victoriametrics.com/MetricsQL.html#rate) function with a lookbehind window larger than `-search.minWindowForInstantRollupOptimization`. The cache usage was removed since [v1.132.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.132.0). See [#10098](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/10098#issuecomment-3895011084) for more details.
|
||||
|
||||
## [v1.136.15](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.136.15)
|
||||
|
||||
Released at 2026-07-31
|
||||
|
||||
**v1.136.x is a line of [LTS releases](https://docs.victoriametrics.com/victoriametrics/lts-releases/). It contains important up-to-date bugfixes for [VictoriaMetrics enterprise](https://docs.victoriametrics.com/victoriametrics/enterprise/).
|
||||
All these fixes are also included in [the latest community release](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest).
|
||||
The v1.136.x line will be supported for at least 12 months since [v1.136.0](https://docs.victoriametrics.com/victoriametrics/changelog/#v11360) release**
|
||||
|
||||
**Update Note 1:** [vmsingle](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/) and `vmselect` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/): the `/api/v1/admin/tsdb/delete_series`, `/tags/delSeries` endpoints now require `POST` method. Previously, it also accepted `GET` requests. If you use `GET` requests for this endpoint, update your scripts or tooling to use `POST` instead. See [#5552](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5552).
|
||||
|
||||
* SECURITY: [vmsingle](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/) and `vmselect` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/): restrict `/api/v1/admin/tsdb/delete_series`, `/tags/delSeries` endpoints to `POST` method only to prevent some [SSRF](https://en.wikipedia.org/wiki/Server-side_request_forgery)-based data deletion attacks. See [#5552](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5552).
|
||||
|
||||
* BUGFIX: [vmbackupmanager](https://docs.victoriametrics.com/victoriametrics/vmbackupmanager/): previously, `vmbackupmanager` was crashing on startup when it failed to restore backup state from remote storage, causing a crash loop. Now it logs the error and continues running, retrying the state restore before each scheduled backup. Added `vm_backup_errors_total{type="restoreState"}` metric to track backup state restore failures. See [#11217](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/11217).
|
||||
|
||||
## [v1.136.14](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.136.14)
|
||||
|
||||
Released at 2026-07-17
|
||||
|
||||
@@ -121,7 +121,7 @@ It is allowed to run Enterprise components in [cases listed here](https://docs.v
|
||||
Binary releases of Enterprise components are available at [the releases page for VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest),
|
||||
[the releases page for VictoriaLogs](https://github.com/VictoriaMetrics/VictoriaLogs/releases/latest)
|
||||
and [the releases page for VictoriaTraces](https://github.com/VictoriaMetrics/VictoriaTraces/releases/latest).
|
||||
Enterprise binaries and packages have `enterprise` suffix in their names. For example, `victoria-metrics-linux-amd64-v1.149.0-enterprise.tar.gz`.
|
||||
Enterprise binaries and packages have `enterprise` suffix in their names. For example, `victoria-metrics-linux-amd64-v1.148.0-enterprise.tar.gz`.
|
||||
|
||||
In order to run binary release of Enterprise component, please download the `*-enterprise.tar.gz` archive for your OS and architecture
|
||||
from the corresponding releases page and unpack it. Then run the unpacked binary.
|
||||
@@ -139,8 +139,8 @@ For example, the following command runs VictoriaMetrics Enterprise binary with t
|
||||
obtained at [this page](https://victoriametrics.com/products/enterprise/trial/):
|
||||
|
||||
```sh
|
||||
wget https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.149.0/victoria-metrics-linux-amd64-v1.149.0-enterprise.tar.gz
|
||||
tar -xzf victoria-metrics-linux-amd64-v1.149.0-enterprise.tar.gz
|
||||
wget https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.148.0/victoria-metrics-linux-amd64-v1.148.0-enterprise.tar.gz
|
||||
tar -xzf victoria-metrics-linux-amd64-v1.148.0-enterprise.tar.gz
|
||||
./victoria-metrics-prod -license=BASE64_ENCODED_LICENSE_KEY
|
||||
```
|
||||
|
||||
@@ -155,7 +155,7 @@ Alternatively, VictoriaMetrics Enterprise license can be stored in the file and
|
||||
It is allowed to run Enterprise components in [cases listed here](https://docs.victoriametrics.com/victoriametrics/enterprise/#valid-cases-for-victoriametrics-enterprise).
|
||||
|
||||
Docker images for Enterprise components are available at [VictoriaMetrics Docker Hub](https://hub.docker.com/u/victoriametrics) and [VictoriaMetrics Quay](https://quay.io/organization/victoriametrics).
|
||||
Enterprise docker images have `enterprise` suffix in their names. For example, `victoriametrics/victoria-metrics:v1.149.0-enterprise`.
|
||||
Enterprise docker images have `enterprise` suffix in their names. For example, `victoriametrics/victoria-metrics:v1.148.0-enterprise`.
|
||||
|
||||
In order to run Docker image of VictoriaMetrics Enterprise component, it is required to provide the license key via the command-line
|
||||
flag as described in the [binary-releases](https://docs.victoriametrics.com/victoriametrics/enterprise/#binary-releases) section.
|
||||
@@ -165,13 +165,13 @@ Enterprise license key can be obtained at [this page](https://victoriametrics.co
|
||||
For example, the following command runs VictoriaMetrics Enterprise Docker image with the specified license key:
|
||||
|
||||
```sh
|
||||
docker run --name=victoria-metrics victoriametrics/victoria-metrics:v1.149.0-enterprise -license=BASE64_ENCODED_LICENSE_KEY
|
||||
docker run --name=victoria-metrics victoriametrics/victoria-metrics:v1.148.0-enterprise -license=BASE64_ENCODED_LICENSE_KEY
|
||||
```
|
||||
|
||||
Alternatively, the license code can be stored in the file and then referred via `-licenseFile` command-line flag:
|
||||
|
||||
```sh
|
||||
docker run --name=victoria-metrics -v /vm-license:/vm-license victoriametrics/victoria-metrics:v1.149.0-enterprise -licenseFile=/path/to/vm-license
|
||||
docker run --name=victoria-metrics -v /vm-license:/vm-license victoriametrics/victoria-metrics:v1.148.0-enterprise -licenseFile=/path/to/vm-license
|
||||
```
|
||||
|
||||
Example docker-compose configuration:
|
||||
@@ -181,7 +181,7 @@ version: "3.5"
|
||||
services:
|
||||
victoriametrics:
|
||||
container_name: victoriametrics
|
||||
image: victoriametrics/victoria-metrics:v1.149.0
|
||||
image: victoriametrics/victoria-metrics:v1.148.0
|
||||
ports:
|
||||
- 8428:8428
|
||||
volumes:
|
||||
@@ -213,7 +213,7 @@ is used to provide the license key in plain-text:
|
||||
```yaml
|
||||
server:
|
||||
image:
|
||||
tag: v1.149.0-enterprise
|
||||
tag: v1.148.0-enterprise
|
||||
|
||||
license:
|
||||
key: {BASE64_ENCODED_LICENSE_KEY}
|
||||
@@ -224,7 +224,7 @@ In order to provide the license key via existing secret, the following values fi
|
||||
```yaml
|
||||
server:
|
||||
image:
|
||||
tag: v1.149.0-enterprise
|
||||
tag: v1.148.0-enterprise
|
||||
|
||||
license:
|
||||
secret:
|
||||
@@ -274,7 +274,7 @@ spec:
|
||||
license:
|
||||
key: {BASE64_ENCODED_LICENSE_KEY}
|
||||
image:
|
||||
tag: v1.149.0-enterprise
|
||||
tag: v1.148.0-enterprise
|
||||
```
|
||||
|
||||
In order to provide the license key via an existing secret, the following custom resource is used:
|
||||
@@ -291,7 +291,7 @@ spec:
|
||||
name: vm-license
|
||||
key: license
|
||||
image:
|
||||
tag: v1.149.0-enterprise
|
||||
tag: v1.148.0-enterprise
|
||||
```
|
||||
|
||||
Example secret with license key:
|
||||
@@ -342,7 +342,7 @@ Builds are available for amd64 and arm64 architectures.
|
||||
|
||||
Example archive:
|
||||
|
||||
`victoria-metrics-linux-amd64-v1.149.0-enterprise.tar.gz`
|
||||
`victoria-metrics-linux-amd64-v1.148.0-enterprise.tar.gz`
|
||||
|
||||
Includes:
|
||||
|
||||
@@ -351,7 +351,7 @@ Includes:
|
||||
|
||||
Example Docker image:
|
||||
|
||||
`victoriametrics/victoria-metrics:v1.149.0-enterprise-fips` – uses the FIPS-compatible binary and based on `scratch` image.
|
||||
`victoriametrics/victoria-metrics:v1.148.0-enterprise-fips` – uses the FIPS-compatible binary and based on `scratch` image.
|
||||
|
||||
## What Happens to Licensed Components When a License Expires
|
||||
|
||||
|
||||
@@ -35,8 +35,8 @@ scrape_configs:
|
||||
After you created the `scrape.yaml` file, download and unpack [single-node VictoriaMetrics](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/) to the same directory:
|
||||
|
||||
```sh
|
||||
wget https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.149.0/victoria-metrics-linux-amd64-v1.149.0.tar.gz
|
||||
tar xzf victoria-metrics-linux-amd64-v1.149.0.tar.gz
|
||||
wget https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.148.0/victoria-metrics-linux-amd64-v1.148.0.tar.gz
|
||||
tar xzf victoria-metrics-linux-amd64-v1.148.0.tar.gz
|
||||
```
|
||||
|
||||
Then start VictoriaMetrics and instruct it to scrape targets defined in `scrape.yaml` and save scraped metrics
|
||||
@@ -150,8 +150,8 @@ Then start [single-node VictoriaMetrics](https://docs.victoriametrics.com/victor
|
||||
|
||||
```yaml
|
||||
# Download and unpack single-node VictoriaMetrics
|
||||
wget https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.149.0/victoria-metrics-linux-amd64-v1.149.0.tar.gz
|
||||
tar xzf victoria-metrics-linux-amd64-v1.149.0.tar.gz
|
||||
wget https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.148.0/victoria-metrics-linux-amd64-v1.148.0.tar.gz
|
||||
tar xzf victoria-metrics-linux-amd64-v1.148.0.tar.gz
|
||||
|
||||
# Run single-node VictoriaMetrics with the given scrape.yaml
|
||||
./victoria-metrics-prod -promscrape.config=scrape.yaml
|
||||
|
||||
@@ -640,7 +640,7 @@ See the docs at https://docs.victoriametrics.com/victoriametrics/
|
||||
-vmalert.proxyURL string
|
||||
Optional URL for proxying requests to vmalert. For example, if -vmalert.proxyURL=http://vmalert:8880 , then alerting API requests such as /api/v1/rules from Grafana will be proxied to http://vmalert:8880/api/v1/rules . See https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#vmalert
|
||||
-vmselectAddr string
|
||||
TCP address to listen for incoming connections from vmselect. When set, the node will be able to accept cluster-native vmselect RPC requests as if it were vmstorage. The tenant ID assigned to this node's data is controlled by -accountID and -projectID flags. See https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#multi-tenancy
|
||||
TCP address to accept connections from vmselect services
|
||||
-vmui.customDashboardsPath string
|
||||
Optional path to vmui dashboards. See https://github.com/VictoriaMetrics/VictoriaMetrics/tree/master/app/vmui/packages/vmui/public/dashboards
|
||||
-vmui.defaultTimezone string
|
||||
|
||||
@@ -468,7 +468,7 @@ See the docs at https://docs.victoriametrics.com/victoriametrics/vmagent/ .
|
||||
-remoteWrite.maxRowsPerBlock int
|
||||
The maximum number of samples to send in each block to remote storage. Higher number may improve performance at the cost of the increased memory usage. See also -remoteWrite.maxBlockSize (default 10000)
|
||||
-remoteWrite.mdx.enable array
|
||||
Whether to only retain metrics from VictoriaMetrics services before sending them to the corresponding -remoteWrite.url. Can be combined with -remoteWrite.obfuscateLabels to hide sensitive label values in the forwarded metrics. Please see https://docs.victoriametrics.com/victoriametrics/vmagent/#monitoring-data-exchange
|
||||
Whether to only retain metrics from VictoriaMetrics services before sending them to the corresponding -remoteWrite.url. Please see https://docs.victoriametrics.com/victoriametrics/vmagent/#monitoring-data-exchange
|
||||
Supports array of values separated by comma or specified via multiple flags.
|
||||
Empty values are set to false.
|
||||
-remoteWrite.oauth2.clientID array
|
||||
@@ -495,10 +495,6 @@ See the docs at https://docs.victoriametrics.com/victoriametrics/vmagent/ .
|
||||
Optional OAuth2 tokenURL to use for the corresponding -remoteWrite.url
|
||||
Supports an array of values separated by comma or specified via multiple flags.
|
||||
Each array item can contain comma inside single-quoted or double-quoted string, {}, [] and () braces.
|
||||
-remoteWrite.obfuscateLabels ^^
|
||||
List of label names whose values will be obfuscated before being sent to the corresponding -remoteWrite.url. Multiple label names should be separated by ^^, e.g. "job^^instance,ip". Can be combined with -remoteWrite.mdx.enable to hide sensitive label values in VictoriaMetrics self-monitoring metrics. Please see https://docs.victoriametrics.com/victoriametrics/vmagent/#obfuscating-label-values
|
||||
Supports an `array` of values separated by comma or specified via multiple flags.
|
||||
Each array item can contain comma inside single-quoted or double-quoted string, {}, [] and () braces.
|
||||
-remoteWrite.proxyURL array
|
||||
Optional proxy URL for writing data to the corresponding -remoteWrite.url. Supported proxies: http, https, socks5. Example: -remoteWrite.proxyURL=socks5://proxy:1234
|
||||
Supports an array of values separated by comma or specified via multiple flags.
|
||||
|
||||
@@ -404,7 +404,7 @@ See the docs at https://docs.victoriametrics.com/victoriametrics/vmalert/ .
|
||||
Optional TLS server name to use for connections to -remoteWrite.url. By default, the server name from -remoteWrite.url is used
|
||||
-remoteWrite.url string
|
||||
Optional URL to persist alerts state and recording rules results in form of timeseries. It must support either VictoriaMetrics remote write protocol or Prometheus remote_write protocol. Supports address in the form of IP address with a port (e.g., http://127.0.0.1:8428) or DNS SRV record. For example, if -remoteWrite.url=http://127.0.0.1:8428 is specified, then the alerts state will be written to http://127.0.0.1:8428/api/v1/write . See also -remoteWrite.disablePathAppend, '-remoteWrite.showURL'.
|
||||
-replay.continueWithExecutionErr
|
||||
-replay.continueWithExecutionErr bool
|
||||
Whether to continue replaying other rules if a rule execution fails with a 422 response code, which can happen due to an expression syntax error or a resource limit being hit.
|
||||
-replay.disableProgressBar
|
||||
Whether to disable rendering progress bars during the replay. Progress bar rendering might be verbose or break the logs parsing, so it is recommended to be disabled when not used in interactive mode.
|
||||
|
||||
@@ -34,9 +34,9 @@ vmctl command-line tool is available as:
|
||||
|
||||
Download and unpack vmctl:
|
||||
```sh
|
||||
wget https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.149.0/vmutils-darwin-arm64-v1.149.0.tar.gz
|
||||
wget https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.148.0/vmutils-darwin-arm64-v1.148.0.tar.gz
|
||||
|
||||
tar xzf vmutils-darwin-arm64-v1.149.0.tar.gz
|
||||
tar xzf vmutils-darwin-arm64-v1.148.0.tar.gz
|
||||
```
|
||||
|
||||
Once binary is unpacked, see the full list of supported modes by running the following command:
|
||||
|
||||
@@ -31,7 +31,7 @@ See the docs at https://docs.victoriametrics.com/victoriametrics/cluster-victori
|
||||
-denyQueryTracing
|
||||
Whether to disable the ability to trace queries. See https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#query-tracing
|
||||
-disableRerouting
|
||||
Whether to disable re-routing when some of vmstorage nodes accept incoming data at slower speed compared to other storage nodes. Disabled re-routing limits the ingestion rate by the slowest vmstorage node. On the other side, disabled re-routing minimizes the number of active time series in the cluster during rolling restarts and during spikes in series churn rate. See also -disableReroutingOnUnavailable and -dropSamplesOnOverload
|
||||
Whether to disable re-routing when some of vmstorage nodes accept incoming data at slower speed compared to other storage nodes. Disabled re-routing limits the ingestion rate by the slowest vmstorage node. On the other side, disabled re-routing minimizes the number of active time series in the cluster during rolling restarts and during spikes in series churn rate. See also -disableReroutingOnUnavailable and -dropSamplesOnOverload (default true)
|
||||
-disableReroutingOnUnavailable
|
||||
Whether to disable re-routing when some of vmstorage nodes are unavailable. Disabled re-routing stops ingestion when some storage nodes are unavailable. On the other side, disabled re-routing minimizes the number of active time series in the cluster during rolling restarts and during spikes in series churn rate. See also -disableRerouting
|
||||
-dropSamplesOnOverload
|
||||
|
||||
@@ -132,7 +132,7 @@ See the docs at https://docs.victoriametrics.com/victoriametrics/cluster-victori
|
||||
-loggerWarnsPerSecondLimit int
|
||||
Per-second limit on the number of WARN messages. If more than the given number of warns are emitted per second, then the remaining warns are suppressed. Zero values disable the rate limit
|
||||
-maxConcurrentInserts int
|
||||
The maximum number of concurrent insert requests. Set higher value when clients send data over slow networks. Default value depends on the number of available CPU cores. It should work fine in most cases since it minimizes resource usage. See also -insert.maxQueueDuration (default 20)
|
||||
The maximum number of concurrent insert requests. Set higher value when clients send data over slow networks. Default value depends on the number of available CPU cores. It should work fine in most cases since it minimizes resource usage. See also -insert.maxQueueDuration (default 24)
|
||||
-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. The process may behave unexpectedly if this flag is set too small (e.g., 1 byte).
|
||||
Supports the following optional suffixes for size values: KB, MB, GB, TB, KiB, MiB, GiB, TiB (default 0)
|
||||
|
||||
@@ -24,62 +24,62 @@ func TestTryParseUnixTimestamp_Success(t *testing.T) {
|
||||
f("0", 0)
|
||||
|
||||
// nanoseconds
|
||||
f("-1234567890123456789", -1234567890_123_456_789)
|
||||
f("1234567890123456789", 1234567890_123_456_789)
|
||||
f("1234567890123456.789", 1234567890_123_456_789)
|
||||
f("-1234567890123456789", -1234567890123456789)
|
||||
f("1234567890123456789", 1234567890123456789)
|
||||
f("1234567890123456.789", 1234567890123456789)
|
||||
|
||||
// microseconds
|
||||
f("-1234567890123456", -1234567890_123_456_000)
|
||||
f("1234567890123456", 1234567890_123_456_000)
|
||||
f("1234567890123456.789", 1234567890_123_456_789)
|
||||
f("-1234567890123456", -1234567890123456000)
|
||||
f("1234567890123456", 1234567890123456000)
|
||||
f("1234567890123456.789", 1234567890123456789)
|
||||
|
||||
// milliseconds
|
||||
f("-1234567890123", -1234567890_123_000_000)
|
||||
f("1234567890123", 1234567890_123_000_000)
|
||||
f("1234567890123.456", 1234567890_123_456_000)
|
||||
f("-1234567890123", -1234567890123000000)
|
||||
f("1234567890123", 1234567890123000000)
|
||||
f("1234567890123.456", 1234567890123456000)
|
||||
|
||||
// seconds
|
||||
f("-1234567890", -1234567890_000_000_000)
|
||||
f("1234567890", 1234567890_000_000_000)
|
||||
f("1234567890.123456789", 1234567890_123_456_789)
|
||||
f("1234567890.12345678", 1234567890_123_456_780)
|
||||
f("1234567890.1234567", 1234567890_123_456_700)
|
||||
f("-1234567890.123456", -1234567890_123_456_000)
|
||||
f("-1234567890.12345", -1234567890_123_450_000)
|
||||
f("-1234567890.1234", -1234567890_123_400_000)
|
||||
f("-1234567890.123", -1234567890_123_000_000)
|
||||
f("-1234567890.12", -1234567890_120_000_000)
|
||||
f("-1234567890.1", -1234567890_100_000_000)
|
||||
f("-1234567890", -1234567890000000000)
|
||||
f("1234567890", 1234567890000000000)
|
||||
f("1234567890.123456789", 1234567890123456789)
|
||||
f("1234567890.12345678", 1234567890123456780)
|
||||
f("1234567890.1234567", 1234567890123456700)
|
||||
f("-1234567890.123456", -1234567890123456000)
|
||||
f("-1234567890.12345", -1234567890123450000)
|
||||
f("-1234567890.1234", -1234567890123400000)
|
||||
f("-1234567890.123", -1234567890123000000)
|
||||
f("-1234567890.12", -1234567890120000000)
|
||||
f("-1234567890.1", -1234567890100000000)
|
||||
|
||||
// scientific notation
|
||||
f("1e9", 1000000000_000_000_000)
|
||||
f("1.234e9", 1234000000_000_000_000)
|
||||
f("-1.23456789e9", -1234567890_000_000_000)
|
||||
f("1.234567890123456789e18", 1234567890_123_456_789)
|
||||
f("-1.234567890123456789e18", -1234567890_123_456_789)
|
||||
f("0.23456789e9", 234567890_000_000_000)
|
||||
f("123.456789123e9", 123456789_123_000_000)
|
||||
f("-1234.5678912e9", -1234567891_200_000_000)
|
||||
f("123.678912e7", 1236789120_000_000_000)
|
||||
f("1.23e7", 12300000_000_000_000)
|
||||
f("1.23e6", 1230000_000_000_000)
|
||||
f("1.23e5", 123000_000_000_000)
|
||||
f("1.23e4", 12300_000_000_000)
|
||||
f("1.23e3", 1230_000_000_000)
|
||||
f("1.23e2", 123_000_000_000)
|
||||
f("1.2e1", 12_000_000_000)
|
||||
f("1123.456789123456789E15", 1123456789_123_456_789)
|
||||
f("1e9", 1000000000000000000)
|
||||
f("1.234e9", 1234000000000000000)
|
||||
f("-1.23456789e9", -1234567890000000000)
|
||||
f("1.234567890123456789e18", 1234567890123456789)
|
||||
f("-1.234567890123456789e18", -1234567890123456789)
|
||||
f("0.23456789e9", 234567890000000000)
|
||||
f("123.456789123e9", 123456789123000000)
|
||||
f("-1234.5678912e9", -1234567891200000000)
|
||||
f("123.678912e7", 1236789120000000000)
|
||||
f("1.23e7", 12300000000000000)
|
||||
f("1.23e6", 1230000000000000)
|
||||
f("1.23e5", 123000000000000)
|
||||
f("1.23e4", 12300000000000)
|
||||
f("1.23e3", 1230000000000)
|
||||
f("1.23e2", 123000000000)
|
||||
f("1.2e1", 12000000000)
|
||||
f("1123.456789123456789E15", 1123456789123456789)
|
||||
|
||||
// scientific notation with sub-second precision, i.e. more fractional digits
|
||||
// than the exponent shifts (https://github.com/VictoriaMetrics/VictoriaMetrics/issues/11268).
|
||||
// These must match the equivalent plain fractional form.
|
||||
f("1.784144612388E9", 1784144612_388_000_000) // == 1784144612.388
|
||||
f("1.784144612388e9", 1784144612_388_000_000)
|
||||
f("-1.784144612388e9", -1784144612_388_000_000)
|
||||
f("1.5000000005e9", 1500000000_500_000_000) // == 1500000000.5
|
||||
f("1.23456789e9", 1234567890_000_000_000) // exponent consumes all frac digits (integer result)
|
||||
f("1.23e1", 12300_000_000_000) // == 12.3
|
||||
f("1.234e0", 1234_000_000_000) // == 1.234
|
||||
f("1.784144612388E9", 1784144612388000000) // == 1784144612.388
|
||||
f("1.784144612388e9", 1784144612388000000)
|
||||
f("-1.784144612388e9", -1784144612388000000)
|
||||
f("1.5000000005e9", 1500000000500000000) // == 1500000000.5
|
||||
f("1.23456789e9", 1234567890000000000) // exponent consumes all frac digits (integer result)
|
||||
f("1.23e1", 12300000000000) // == 12.3
|
||||
f("1.234e0", 1234000000000) // == 1.234
|
||||
}
|
||||
|
||||
func TestTryParseUnixTimestamp_Failure(t *testing.T) {
|
||||
@@ -146,27 +146,27 @@ func TestParseTimeAtSuccess(t *testing.T) {
|
||||
now := time.Now().UnixNano()
|
||||
|
||||
// unix timestamp in seconds
|
||||
f("1562529662", now, 1562529662_000_000_000)
|
||||
f("1562529662.6", now, 1562529662_600_000_000)
|
||||
f("1562529662.67", now, 1562529662_670_000_000)
|
||||
f("1562529662.678", now, 1562529662_678_000_000)
|
||||
f("1562529662.678123", now, 1562529662_678_123_000)
|
||||
f("1562529662.678123456", now, 1562529662_678_123_456)
|
||||
f("1562529662", now, 1562529662*1e9)
|
||||
f("1562529662.6", now, 1562529662600*1e6)
|
||||
f("1562529662.67", now, 1562529662670*1e6)
|
||||
f("1562529662.678", now, 1562529662678*1e6)
|
||||
f("1562529662.678123", now, 1562529662678123*1e3)
|
||||
f("1562529662.678123456", now, 1562529662678123456)
|
||||
|
||||
// unix timestamp in milliseconds
|
||||
f("1562529662678", now, 1562529662_678_000_000)
|
||||
f("1562529662678.9", now, 1562529662_678_900_000)
|
||||
f("1562529662678.901", now, 1562529662_678_901_000)
|
||||
f("1562529662678.901324", now, 1562529662_678_901_324)
|
||||
f("1562529662678", now, 1562529662678*1e6)
|
||||
f("1562529662678.9", now, 1562529662678900*1e3)
|
||||
f("1562529662678.901", now, 1562529662678901*1e3)
|
||||
f("1562529662678.901324", now, 1562529662678901324)
|
||||
|
||||
// unix timestamp in microseconds
|
||||
f("1562529662678901", now, 1562529662_678_901_000)
|
||||
f("1562529662678901.3", now, 1562529662_678_901_300)
|
||||
f("1562529662678901.32", now, 1562529662_678_901_320)
|
||||
f("1562529662678901.321", now, 1562529662_678_901_321)
|
||||
f("1562529662678901", now, 1562529662678901*1e3)
|
||||
f("1562529662678901.3", now, 1562529662678901300)
|
||||
f("1562529662678901.32", now, 1562529662678901320)
|
||||
f("1562529662678901.321", now, 1562529662678901321)
|
||||
|
||||
// unix timestamp in nanoseconds
|
||||
f("1562529662678901234", now, 1562529662_678_901_234)
|
||||
f("1562529662678901234", now, 1562529662678901234)
|
||||
|
||||
// duration relative to the current time
|
||||
f("now", now, now)
|
||||
@@ -175,7 +175,7 @@ func TestParseTimeAtSuccess(t *testing.T) {
|
||||
// negative duration relative to the current time
|
||||
f("-5m", now, now-5*60*1e9)
|
||||
f("-123", now, now-123*1e9)
|
||||
f("-123.456", now, now-123_456*1e6)
|
||||
f("-123.456", now, now-123456*1e6)
|
||||
f("now-1h5m", now, now-(3600+5*60)*1e9)
|
||||
|
||||
// Year
|
||||
@@ -209,9 +209,9 @@ func TestParseTimeAtSuccess(t *testing.T) {
|
||||
f("2023-05-20T04:57:43-02:30", now, 1.684567663e+09*1e9)
|
||||
|
||||
// milliseconds
|
||||
f("2023-05-20T04:57:43.123Z", now, 1684558663_123_000_000)
|
||||
f("2023-05-20T04:57:43.123456789+02:30", now, 1684549663_123_456_789)
|
||||
f("2023-05-20T04:57:43.123456789-02:30", now, 1684567663_123_456_789)
|
||||
f("2023-05-20T04:57:43.123Z", now, 1684558663123000000)
|
||||
f("2023-05-20T04:57:43.123456789+02:30", now, 1684549663123456789)
|
||||
f("2023-05-20T04:57:43.123456789-02:30", now, 1684567663123456789)
|
||||
}
|
||||
|
||||
func TestParseTimeAtLimits(t *testing.T) {
|
||||
|
||||
@@ -30,6 +30,12 @@ const (
|
||||
modeWhole = 2
|
||||
)
|
||||
|
||||
const (
|
||||
// minCurrCacheSaveMissRate is the minimum miss rate of curr cache
|
||||
// for saving prev instead of curr during split mode.
|
||||
minCurrCacheSaveMissRate = 0.8
|
||||
)
|
||||
|
||||
// Cache is a cache for working set entries.
|
||||
//
|
||||
// The cache evicts inactive entries after the given expireDuration.
|
||||
@@ -41,6 +47,10 @@ type Cache struct {
|
||||
// csHistory holds cache stats history
|
||||
csHistory fastcache.Stats
|
||||
|
||||
// prevStatsAtRotation holds prev cache stats at the moment it became prev from curr.
|
||||
// It is used for calculating prev miss rate since the last cache rotation.
|
||||
prevStatsAtRotation fastcache.Stats
|
||||
|
||||
// mode indicates whether to use only curr and skip prev.
|
||||
//
|
||||
// This flag is set to modeSwitching if curr is filled for more than 50% space.
|
||||
@@ -145,6 +155,7 @@ func newCacheInternal(curr, prev *fastcache.Cache, mode, maxBytes int, expireDur
|
||||
c.maxBytes = maxBytes
|
||||
c.curr.Store(curr)
|
||||
c.prev.Store(prev)
|
||||
prev.UpdateStats(&c.prevStatsAtRotation)
|
||||
c.stopCh = make(chan struct{})
|
||||
c.mode.Store(uint32(mode))
|
||||
c.runWatchers(expireDuration)
|
||||
@@ -184,7 +195,7 @@ func (c *Cache) expirationWatcher(expireDuration time.Duration) {
|
||||
prev := c.prev.Load()
|
||||
curr := c.curr.Load()
|
||||
c.updateCacheStatsHistoryBeforeRotationLocked(prev, curr)
|
||||
|
||||
c.storeCurrStatsBeforeRotationLocked(curr)
|
||||
c.prev.Store(curr)
|
||||
prev.Reset()
|
||||
c.curr.Store(prev)
|
||||
@@ -305,7 +316,7 @@ func (c *Cache) transitIntoWholeModeLocked(maxBytesSize uint64, t *time.Ticker)
|
||||
prev := c.prev.Load()
|
||||
curr := c.curr.Load()
|
||||
c.updateCacheStatsHistoryBeforeRotationLocked(prev, curr)
|
||||
|
||||
c.storeCurrStatsBeforeRotationLocked(curr)
|
||||
c.prev.Store(curr)
|
||||
prev.Reset()
|
||||
|
||||
@@ -356,6 +367,7 @@ func (c *Cache) transitIntoWholeModeLocked(maxBytesSize uint64, t *time.Ticker)
|
||||
c.updateCacheStatsHistoryBeforeRotationLocked(prev, curr)
|
||||
|
||||
c.prev.Store(newWithAutoCleanup(1024))
|
||||
c.prevStatsAtRotation.Reset()
|
||||
prev.Reset()
|
||||
}
|
||||
|
||||
@@ -363,14 +375,15 @@ func (c *Cache) transitIntoWholeModeLocked(maxBytesSize uint64, t *time.Ticker)
|
||||
func (c *Cache) MustSave(filePath string) {
|
||||
startTime := time.Now()
|
||||
|
||||
var cs fastcache.Stats
|
||||
curr := c.curr.Load()
|
||||
curr.UpdateStats(&cs)
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
cacheToSave, cs, cacheName := c.selectCacheToSave()
|
||||
|
||||
concurrency := cgroup.AvailableCPUs()
|
||||
|
||||
logger.Infof("saving cache to %s by using %d concurrent workers", filePath, concurrency)
|
||||
err := curr.SaveToFileConcurrent(filePath, concurrency)
|
||||
logger.Infof("saving %s cache to %s by using %d concurrent workers", cacheName, filePath, concurrency)
|
||||
err := cacheToSave.SaveToFileConcurrent(filePath, concurrency)
|
||||
if err != nil {
|
||||
logger.Panicf("FATAL: cannot save cache to %s: %s", filePath, err)
|
||||
}
|
||||
@@ -378,6 +391,47 @@ func (c *Cache) MustSave(filePath string) {
|
||||
logger.Infof("cache has been successfully saved to %s in %.3f seconds; entriesCount: %d, sizeBytes: %d", filePath, time.Since(startTime).Seconds(), cs.EntriesCount, cs.BytesSize)
|
||||
}
|
||||
|
||||
func (c *Cache) selectCacheToSave() (*fastcache.Cache, fastcache.Stats, string) {
|
||||
curr := c.curr.Load()
|
||||
|
||||
var csCurr fastcache.Stats
|
||||
curr.UpdateStats(&csCurr)
|
||||
|
||||
if c.mode.Load() != modeSplit {
|
||||
return curr, csCurr, "curr"
|
||||
}
|
||||
|
||||
prev := c.prev.Load()
|
||||
|
||||
var csPrev fastcache.Stats
|
||||
prev.UpdateStats(&csPrev)
|
||||
|
||||
if csPrev.EntriesCount == 0 || csPrev.GetCalls == 0 {
|
||||
return curr, csCurr, "curr"
|
||||
}
|
||||
|
||||
csPrevAtRotation := &c.prevStatsAtRotation
|
||||
prevMissRateAfterRotation := float64(1)
|
||||
if csPrev.GetCalls > csPrevAtRotation.GetCalls {
|
||||
prevGetCallsAfterRotation := csPrev.GetCalls - csPrevAtRotation.GetCalls
|
||||
prevMissesAfterRotation := uint64(0)
|
||||
if csPrev.Misses > csPrevAtRotation.Misses {
|
||||
prevMissesAfterRotation = csPrev.Misses - csPrevAtRotation.Misses
|
||||
}
|
||||
if prevMissesAfterRotation < prevGetCallsAfterRotation {
|
||||
prevMissRateAfterRotation = float64(prevMissesAfterRotation) / float64(prevGetCallsAfterRotation)
|
||||
}
|
||||
}
|
||||
|
||||
// Prefer saving prev cache when:
|
||||
// 1. 80% requests were missed in curr cache and served by prev cache.
|
||||
// 2. less than 80% requests were missed in prev cache since the last rotation.
|
||||
if csCurr.GetCalls < 10 || (float64(csCurr.Misses)/float64(csCurr.GetCalls) > minCurrCacheSaveMissRate && prevMissRateAfterRotation < minCurrCacheSaveMissRate) {
|
||||
return prev, csPrev, "prev"
|
||||
}
|
||||
return curr, csCurr, "curr"
|
||||
}
|
||||
|
||||
// Stop stops the cache.
|
||||
//
|
||||
// The cache cannot be used after the Stop call.
|
||||
@@ -406,12 +460,18 @@ func (c *Cache) Reset() {
|
||||
// so we have to restore it into original size for split mode
|
||||
c.prev.Store(newWithAutoCleanup(c.maxBytes / 2))
|
||||
c.curr.Store(newWithAutoCleanup(c.maxBytes / 2))
|
||||
|
||||
c.prevStatsAtRotation.Reset()
|
||||
c.mode.Store(modeSplit)
|
||||
}
|
||||
|
||||
prev.Reset()
|
||||
curr.Reset()
|
||||
c.prevStatsAtRotation.Reset()
|
||||
}
|
||||
|
||||
func (c *Cache) storeCurrStatsBeforeRotationLocked(curr *fastcache.Cache) {
|
||||
c.prevStatsAtRotation.Reset()
|
||||
curr.UpdateStats(&c.prevStatsAtRotation)
|
||||
}
|
||||
|
||||
// UpdateStats updates fcs with cache stats.
|
||||
|
||||
@@ -5,6 +5,7 @@ package workingsetcache
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"testing/synctest"
|
||||
"time"
|
||||
@@ -165,6 +166,163 @@ func TestSetGetStatsInSplitMode_cacheLoadedFromEmptyFile(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestMustSaveSelectsCacheInSplitMode(t *testing.T) {
|
||||
t.Run("prefers prev cache if curr is rarely visited", func(t *testing.T) {
|
||||
cachePath := filepath.Join(t.TempDir(), "cache")
|
||||
synctest.Test(t, func(t *testing.T) {
|
||||
var (
|
||||
k = []byte("k")
|
||||
v = []byte("v")
|
||||
dst []byte
|
||||
)
|
||||
|
||||
c := Load(cachePath, 1024)
|
||||
c.Set(k, v)
|
||||
for range 10 {
|
||||
dst = c.Get(dst[:0], k)
|
||||
}
|
||||
|
||||
// prev and curr were rotated, k is now in prev, curr is empty.
|
||||
time.Sleep(*cacheExpireDuration + time.Minute)
|
||||
synctest.Wait()
|
||||
assertMode(t, c, modeSplit)
|
||||
|
||||
c.MustSave(cachePath)
|
||||
c.Stop()
|
||||
|
||||
c = Load(cachePath, 1024)
|
||||
defer c.Stop()
|
||||
if got := c.Get(dst[:0], k); string(got) != string(v) {
|
||||
t.Fatalf("unexpected value loaded from saved cache; got %q; want %q", got, v)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("prefers prev cache when prev is still useful", func(t *testing.T) {
|
||||
cachePath := filepath.Join(t.TempDir(), "cache")
|
||||
synctest.Test(t, func(t *testing.T) {
|
||||
const keysCount = 10
|
||||
var (
|
||||
v = []byte("v")
|
||||
dst []byte
|
||||
)
|
||||
|
||||
c := Load(cachePath, 1024)
|
||||
for i := range keysCount {
|
||||
c.Set([]byte(fmt.Sprintf("prev_%d", i)), v)
|
||||
}
|
||||
|
||||
// prev and curr were rotated, prev_0-prev_9 are now in prev, curr is empty.
|
||||
time.Sleep(*cacheExpireDuration + time.Minute)
|
||||
synctest.Wait()
|
||||
assertMode(t, c, modeSplit)
|
||||
|
||||
// all get calls are missed in curr cache, but can be served by prev cache.
|
||||
for i := range keysCount {
|
||||
dst = c.Get(dst[:0], []byte(fmt.Sprintf("prev_%d", i)))
|
||||
if string(dst) != string(v) {
|
||||
t.Fatalf("unexpected value loaded from prev cache for key %q; got %q; want %q", fmt.Sprintf("prev_%d", i), dst, v)
|
||||
}
|
||||
}
|
||||
|
||||
c.MustSave(cachePath)
|
||||
c.Stop()
|
||||
|
||||
c = Load(cachePath, 1024)
|
||||
defer c.Stop()
|
||||
for i := range keysCount {
|
||||
key := []byte(fmt.Sprintf("prev_%d", i))
|
||||
if got := c.Get(dst[:0], key); string(got) != string(v) {
|
||||
t.Fatalf("unexpected value loaded from saved cache for key %q; got %q; want %q", key, got, v)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("prefers curr cache when prev is cold", func(t *testing.T) {
|
||||
cachePath := filepath.Join(t.TempDir(), "cache")
|
||||
synctest.Test(t, func(t *testing.T) {
|
||||
const keysCount = 10
|
||||
var (
|
||||
v = []byte("v")
|
||||
dst []byte
|
||||
)
|
||||
|
||||
c := Load(cachePath, 1024)
|
||||
for i := range keysCount {
|
||||
c.Set([]byte(fmt.Sprintf("prev_%d", i)), v)
|
||||
}
|
||||
|
||||
// prev and curr were rotated, prev_0-prev_9 are now in prev, curr is empty.
|
||||
time.Sleep(*cacheExpireDuration + time.Minute)
|
||||
synctest.Wait()
|
||||
assertMode(t, c, modeSplit)
|
||||
|
||||
// all get calls are missed in both curr and prev cache.
|
||||
for i := range keysCount {
|
||||
newKey := []byte(fmt.Sprintf("new_%d", i))
|
||||
dst = c.Get(dst[:0], newKey)
|
||||
}
|
||||
|
||||
c.MustSave(cachePath)
|
||||
c.Stop()
|
||||
|
||||
c = Load(cachePath, 1024)
|
||||
defer c.Stop()
|
||||
for i := range keysCount {
|
||||
prevKey := []byte(fmt.Sprintf("prev_%d", i))
|
||||
if got := c.Get(dst[:0], prevKey); len(got) != 0 {
|
||||
t.Fatalf("unexpected prev value loaded from saved cache for key %q; got %q; want an empty value", prevKey, got)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("prefers curr cache when prev hits rate is low after rotation", func(t *testing.T) {
|
||||
cachePath := filepath.Join(t.TempDir(), "cache")
|
||||
synctest.Test(t, func(t *testing.T) {
|
||||
const keysCount = 10
|
||||
var (
|
||||
prevKey = []byte("prev")
|
||||
currKey = []byte("curr")
|
||||
v = []byte("v")
|
||||
dst []byte
|
||||
)
|
||||
|
||||
c := Load(cachePath, 1024)
|
||||
c.Set(prevKey, v)
|
||||
// the curr cache hit all the requests.
|
||||
for range keysCount {
|
||||
dst = c.Get(dst[:0], prevKey)
|
||||
}
|
||||
|
||||
// prev and curr were rotated, prevKey is now in prev, whose cache hit ratio is 100%.
|
||||
time.Sleep(*cacheExpireDuration + time.Minute)
|
||||
synctest.Wait()
|
||||
assertMode(t, c, modeSplit)
|
||||
|
||||
c.Set(currKey, v)
|
||||
// the prev cache miss all the requests after the rotation
|
||||
for i := range keysCount {
|
||||
newKey := []byte(fmt.Sprintf("new_%d", i))
|
||||
dst = c.Get(dst[:0], newKey)
|
||||
}
|
||||
|
||||
c.MustSave(cachePath)
|
||||
c.Stop()
|
||||
|
||||
c = Load(cachePath, 1024)
|
||||
defer c.Stop()
|
||||
if got := c.Get(dst[:0], currKey); string(got) != string(v) {
|
||||
t.Fatalf("unexpected value loaded from saved cache for key %q; got %q; want %q", currKey, got, v)
|
||||
}
|
||||
if got := c.Get(dst[:0], prevKey); len(got) != 0 {
|
||||
t.Fatalf("unexpected prev value loaded from saved cache for key %q; got %q; want an empty value", prevKey, got)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func testSetGetStatsInSplitMode(t *testing.T, c *Cache) {
|
||||
var (
|
||||
k1, v1 = []byte("k1"), []byte("v1")
|
||||
|
||||
Reference in New Issue
Block a user