Compare commits

..

4 Commits

Author SHA1 Message Date
“Jayice”
28a1fbdb4a store curr cache stat as the baseline of prev cache before the rotation
Signed-off-by: “Jayice” <jzhou@victoriametrics.com>
2026-08-04 18:47:54 +08:00
JAYICE
c1d342ff02 Update lib/workingsetcache/cache.go
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Signed-off-by: JAYICE <jayice.zhou@qq.com>
2026-08-04 18:15:04 +08:00
“Jayice”
db93881959 polish CHANGELOG.md
Signed-off-by: “Jayice” <jzhou@victoriametrics.com>
2026-08-04 16:48:33 +08:00
“Jayice”
b39fd34106 persist the previous working set cache during graceful shutdown when it is likely to contain the active working set
Signed-off-by: “Jayice” <jzhou@victoriametrics.com>
2026-08-04 15:21:47 +08:00
22 changed files with 359 additions and 185 deletions

View File

@@ -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 }}

View File

@@ -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:

View File

@@ -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"

View File

@@ -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:

View File

@@ -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:

View File

@@ -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:

View File

@@ -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:

View File

@@ -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

View File

@@ -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)

View File

@@ -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)._

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

@@ -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.

View File

@@ -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:

View File

@@ -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

View File

@@ -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)

View File

@@ -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) {

View File

@@ -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.

View File

@@ -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")