Compare commits

..

3 Commits

Author SHA1 Message Date
Artem Fetishev
1ee29098f5 Update lib/storage/raw_row.go
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Signed-off-by: Artem Fetishev <149964189+rtm0@users.noreply.github.com>
2026-07-15 13:05:12 +02:00
Artem Fetishev
164a072e02 Fix add-flush-search
Signed-off-by: Artem Fetishev <rtm@victoriametrics.com>
2026-07-15 12:46:41 +02:00
Artem Fetishev
151f13dbdf add a test that reprocudes flush data race
Signed-off-by: Artem Fetishev <rtm@victoriametrics.com>
2026-07-14 12:21:38 +02:00
7 changed files with 75 additions and 45 deletions

View File

@@ -154,13 +154,6 @@ See [our blog](https://victoriametrics.com/blog) for the latest articles written
* [Why irate from Prometheus doesn't capture spikes](https://valyala.medium.com/why-irate-from-prometheus-doesnt-capture-spikes-45f9896d7832)
* [VictoriaMetrics: PromQL compliance](https://medium.com/@romanhavronenko/victoriametrics-promql-compliance-d4318203f51e)
* [How do open source solutions for logs work: Elasticsearch, Loki and VictoriaLogs](https://itnext.io/how-do-open-source-solutions-for-logs-work-elasticsearch-loki-and-victorialogs-9f7097ecbc2f)
* [How vmagent Collects and Ships Metrics Fast with Aggregation, Deduplication, and More](https://victoriametrics.com/blog/vmagent-how-it-works/)
* [When Metrics Meet vminsert: A Data-Delivery Story](https://victoriametrics.com/blog/vminsert-how-it-works/)
* [How vmstorage Handles Data Ingestion From vminsert](https://victoriametrics.com/blog/vmstorage-how-it-handles-data-ingestion/)
* [How vmstorage Processes Data: Retention, Merging, Deduplication...](https://victoriametrics.com/blog/vmstorage-retention-merging-deduplication/)
* [How vmstorage's IndexDB Works](https://victoriametrics.com/blog/vmstorage-how-indexdb-works/)
* [How vmstorage Handles Query Requests From vmselect](https://victoriametrics.com/blog/vmstorage-how-it-handles-query-requests/)
* [Inside vmselect: The Query Processing Engine of VictoriaMetrics](https://victoriametrics.com/blog/vmselect-how-it-works/)
### Tutorials, guides and how-to articles
@@ -178,12 +171,6 @@ See [our guides](https://docs.victoriametrics.com/guides/) for the up-to-date gu
* [Prometheus storage: tech terms for humans](https://valyala.medium.com/prometheus-storage-technical-terms-for-humans-4ab4de6c3d48)
* [Cardinality explorer](https://victoriametrics.com/blog/cardinality-explorer/)
* [Rules backfilling via vmalert](https://victoriametrics.com/blog/rules-replay/)
* [vmagent: Key Features Explained in Under 15 Minutes](https://victoriametrics.com/blog/vmagent-key-features-explained/)
* [Prometheus Metrics Explained: Counters, Gauges, Histograms & Summaries](https://victoriametrics.com/blog/prometheus-monitoring-metrics-counters-gauges-histogram-summaries/)
* [Prometheus Monitoring: Instant Queries and Range Queries Explained](https://victoriametrics.com/blog/prometheus-monitoring-instant-range-query/)
* [Prometheus Monitoring: Functions, Subqueries, Operators, and Modifiers](https://victoriametrics.com/blog/prometheus-monitoring-function-operator-modifier/)
* [Prometheus Alerting 101: Rules, Recording Rules, and Alertmanager](https://victoriametrics.com/blog/alerting-recording-rules-alertmanager/)
* [Alerting Best Practices](https://victoriametrics.com/blog/alerting-best-practices/)
### Other articles

View File

@@ -57,10 +57,6 @@ Each service may scale independently and may run on the most suitable hardware.
This is a [shared nothing architecture](https://en.wikipedia.org/wiki/Shared-nothing_architecture).
It increases cluster availability, and simplifies cluster maintenance as well as cluster scaling.
> Further reading, deep dives into how each service works internally:
> - `vmstorage`: [How vmstorage Handles Data Ingestion From vminsert](https://victoriametrics.com/blog/vmstorage-how-it-handles-data-ingestion/), [How vmstorage's IndexDB Works](https://victoriametrics.com/blog/vmstorage-how-indexdb-works/), [How vmstorage Handles Query Requests From vmselect](https://victoriametrics.com/blog/vmstorage-how-it-handles-query-requests/).
> - `vmselect`: [Inside vmselect: The Query Processing Engine of VictoriaMetrics](https://victoriametrics.com/blog/vmselect-how-it-works/).
![Cluster Scheme](Cluster-VictoriaMetrics-components.webp)
## vmui
@@ -838,7 +834,7 @@ This ensures that incoming metrics are evenly distributed across all `vmstorage`
The downside is that a single slow vmstorage node can throttle the entire cluster.
When `-disableRerouting=false` is enabled on `vminsert`,
the cluster will automatically [re-route writes](https://victoriametrics.com/blog/vminsert-how-it-works/#31-rerouting) away from the slowest vmstorage node to preserve maximum ingestion throughput.
the cluster will automatically re-route writes away from the slowest vmstorage node to preserve maximum ingestion throughput.
Re-routing occurs only when all of the following conditions hold:
- the storage send buffer is full.
@@ -881,7 +877,7 @@ See also [resource usage limits docs](#resource-usage-limits).
## Rebalancing
Every `vminsert` node [evenly spreads (shards) incoming data](https://victoriametrics.com/blog/vminsert-how-it-works/#3-sharding-and-buffering) among `vmstorage` nodes specified in the `-storageNode` command-line flag.
Every `vminsert` node evenly spreads (shards) incoming data among `vmstorage` nodes specified in the `-storageNode` command-line flag.
This guarantees even distribution of the ingested data among `vmstorage` nodes. When new `vmstorage` nodes are added to the `-storageNode`
command-line flag at `vminsert`, then only newly ingested data is distributed evenly among old and new `vmstorage` nodes, while
historical data remains on the old `vmstorage` nodes. This speeds up data ingestion and querying for the majority of production workloads,
@@ -1029,7 +1025,7 @@ By default, VictoriaMetrics offloads replication to the underlying storage point
which guarantees data durability. VictoriaMetrics supports application-level replication if replicated durable persistent disks cannot be used for some reason.
The replication can be enabled by passing `-replicationFactor=N` command-line flag to `vminsert`. This instructs `vminsert` to store `N` copies for every ingested sample
on `N` distinct `vmstorage` nodes. This guarantees that all the stored data remains available for querying if up to `N-1` `vmstorage` nodes are unavailable. See [how `vminsert` replicates each sample to `N` `vmstorage` nodes](https://victoriametrics.com/blog/vminsert-how-it-works/#4-replication-and-sending-data-to-vmstorage) for details.
on `N` distinct `vmstorage` nodes. This guarantees that all the stored data remains available for querying if up to `N-1` `vmstorage` nodes are unavailable.
Passing `-replicationFactor=N` command-line flag to `vmselect` instructs it to not mark responses as `partial` if less than `-replicationFactor` vmstorage nodes are unavailable during the query.
See [cluster availability docs](#cluster-availability) for details.
@@ -1064,7 +1060,7 @@ deduplication can't be guaranteed when samples and sample duplicates for the sam
- when `vmstorage` node has no enough capacity for processing incoming data stream. Then `vminsert` re-routes new samples to other `vmstorage` nodes.
It is recommended to set **the same** `-dedup.minScrapeInterval` command-line flag value to both `vmselect` and `vmstorage` nodes
to ensure query results consistency, even if [storage layer didn't complete deduplication](https://victoriametrics.com/blog/vmstorage-retention-merging-deduplication/#deduplication) yet.
to ensure query results consistency, even if storage layer didn't complete deduplication yet.
## Metrics Metadata

View File

@@ -1397,7 +1397,7 @@ in separate files under `part` directory - `timestamps.bin` and `values.bin`.
The `part` directory also contains `index.bin` and `metaindex.bin` files - these files contain index
for fast block lookups, which belong to the given `TSID` and cover the given time range.
`Parts` are periodically merged into bigger parts in background. The [background merge](https://victoriametrics.com/blog/vmstorage-retention-merging-deduplication/#merge-process) provides the following benefits:
`Parts` are periodically merged into bigger parts in background. The background merge provides the following benefits:
* keeping the number of data files under control, so they don't exceed limits on open files
* improved data compression, since bigger parts are usually compressed better than smaller parts
@@ -1532,7 +1532,6 @@ are **eventually deleted** during [background merge](https://medium.com/@valyala
The time range covered by data part is **not limited by retention period unit**. One data part can cover hours or days of
data. Hence, a data part can be deleted only **when fully outside the configured retention**.
See more about partitions and parts in the [Storage section](#storage).
See [how retention frees disk space](https://victoriametrics.com/blog/vmstorage-retention-merging-deduplication/#retention-free-disk-space-guard-and-downsampling) for details.
The maximum disk space usage for a given `-retentionPeriod` is going to be (`-retentionPeriod` + 1) months.
For example, if `-retentionPeriod` is set to 1, data for January is deleted on March 1st.
@@ -1635,7 +1634,6 @@ See how to request a [free trial license](https://victoriametrics.com/products/e
This command-line flag instructs leaving the last sample per each `interval` for [time series](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#time-series)
[samples](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#raw-samples) older than the `offset`. The `offset` must be a multiple of `interval`. For example, `-downsampling.period=30d:5m` instructs leaving the last sample
per each 5-minute interval for samples older than 30 days, while the rest of samples are dropped.
See [Enterprise downsampling internals](https://victoriametrics.com/blog/vmstorage-retention-merging-deduplication/#retention-filters-and-downsampling-enterprise-plan) for details.
The `-downsampling.period` command-line flag can be specified multiple times in order to apply different downsampling levels for different time ranges (aka multi-level downsampling).
For example, `-downsampling.period=30d:5m,180d:1h` instructs leaving the last sample per each 5-minute interval for samples older than 30 days,

View File

@@ -141,7 +141,6 @@ to other remote storage systems that support Prometheus `remote_write` protocol
If a single remote storage instance is temporarily unavailable, the collected data remains available on the other remote storage instances.
`vmagent` buffers the collected data in files at `-remoteWrite.tmpDataPath` until the remote storage becomes available again.
Then it sends the buffered data to the remote storage in order to prevent data gaps.
See how `vmagent` [selects shards and places replicas](https://victoriametrics.com/blog/vmagent-how-it-works/#step-4-sharding--replication) for implementation details.
[VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/) already supports replication,
so there is no need to specify multiple `-remoteWrite.url` flags when writing data to the same cluster.
@@ -151,8 +150,7 @@ See [these docs](https://docs.victoriametrics.com/victoriametrics/cluster-victor
`vmagent` can add, remove, or update labels on the collected data before sending it to the remote storage.
It can filter scrape targets or remove unwanted samples via Prometheus-like relabeling.
Please see the [Relabeling cookbook](https://docs.victoriametrics.com/victoriametrics/relabeling/) for configuration examples.
For ingestion pipeline internals, see how `vmagent` [applies global relabeling and cardinality limits](https://victoriametrics.com/blog/vmagent-how-it-works/#step-2-global-relabeling-cardinality-reduction).
Please see the [Relabeling cookbook](https://docs.victoriametrics.com/victoriametrics/relabeling/) for details.
### Sharding among remote storages
@@ -270,9 +268,7 @@ for the collected samples. Examples:
```sh
./vmagent -remoteWrite.url=http://remote-storage/api/v1/write -streamAggr.dropInputLabels=replica -streamAggr.dedupInterval=60s
```
See how `vmagent` [orders global deduplication and stream aggregation](https://victoriametrics.com/blog/vmagent-how-it-works/#step-3-global-deduplication--stream-aggregation) in the ingestion pipeline.
### Monitoring Data eXchange
The Monitoring Data eXchange (MDX){{% available_from "v1.147.0" %}} feature allows `vmagent` to forward only VictoriaMetrics metrics to selected `-remoteWrite.url` destinations while dropping metrics from non-VictoriaMetrics services.
@@ -361,8 +357,6 @@ in addition to the pull-based Prometheus-compatible targets' scraping:
* Prometheus exposition format via `http://<vmagent>:8429/api/v1/import/prometheus`. See [these docs](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#how-to-import-data-in-prometheus-exposition-format) for details.
* Arbitrary CSV data via `http://<vmagent>:8429/api/v1/import/csv`. See [these docs](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#how-to-import-csv-data).
See how `vmagent` [handles concurrency, decompression, and stream parsing](https://victoriametrics.com/blog/vmagent-how-it-works/#step-1-receiving-data-via-api-or-scrape) during ingestion.
## How to collect metrics in Prometheus format
Specify the path to the `prometheus.yml` file via the `-promscrape.config` command-line flag. `vmagent` takes into account the following
@@ -1004,7 +998,6 @@ This behavior can be changed with the `-remoteWrite.inmemoryQueues` {{% availabl
When set to a non-zero value, vmagent starts the given number of additional workers,
which send only recently ingested data from the in-memory queue, while the workers configured via `-remoteWrite.queues` drain the file-based backlog concurrently.
This reduces the delivery lag for fresh samples after remote storage outages or slowdowns. The flag can be set individually per each `-remoteWrite.url`.
See how the [in-memory and file-based queues manage blocks](https://victoriametrics.com/blog/vmagent-how-it-works/#in-memory-queue) for implementation details.
Note that these workers are started in addition to the workers configured via `-remoteWrite.queues`, so the total number of concurrent connections to
the remote storage becomes the sum of both flags. Take this into account if the remote storage limits the number of concurrent requests.

View File

@@ -982,9 +982,6 @@ Try the following tips to avoid common issues:
In that case, the default step will be used (`-datasource.queryStep`) and may cause unexpected results compared to
executing this query in vmui/Grafana, where step is adjusted differently.
See [practical examples for reducing alert noise](https://victoriametrics.com/blog/alerting-best-practices/#reducing-noise),
including aggregating alerts and configuring inhibition.
### Rule state
vmalert keeps the last `-rule.updateEntriesLimit` updates (or `update_entries_limit` [per-rule config](https://docs.victoriametrics.com/victoriametrics/vmalert/#alerting-rules))
@@ -1040,9 +1037,6 @@ Sometimes, it's hard to understand why a specific alert fired or not. Keep in mi
If evaluation returns error (i.e. datasource is unavailable), alert state doesn't change.
If at least one evaluation returns no data, then alert's `for` state resets.
See [how to tune the `for` parameter](https://victoriametrics.com/blog/alerting-best-practices/#the-for-param),
including its tradeoff with the query lookbehind window.
> Note: The alert state is tracked separately for each time series returned during evaluation.
> For example, if the 1st evaluation returns series A and B, and the 2nd evaluation returns only B the alert will remain active **only for B**.
@@ -1116,9 +1110,6 @@ How to reduce the chance for a rule to flap:
See [common mistakes](#common-mistakes) for rules config.
See [how to tune `keep_firing_for`](https://victoriametrics.com/blog/alerting-best-practices/#the-keep_firing_for-param)
to avoid alert flapping during brief data gaps.
### Never-firing alerts
vmalert can detect {{% available_from "v1.91.0" %}} if alert's expression doesn't match any time series in runtime.

View File

@@ -236,16 +236,24 @@ func (rrss *rawRowsShards) updateFlushDeadline() {
rrss.flushDeadlineMs.Store(time.Now().Add(pendingRowsFlushInterval).UnixMilli())
}
// flush calls flush callback on all rawRows that are stored in rrss internal
// buffers and are ready to be flushed.
//
// A rawRow is ready to be flushed either when it has spent enough time in rrss
// internal buffers (see pendingRowsFlushInterval) or if the operation is final
// and the rawRow needs to be flushed immediately.
//
// The flushed rawRows are removed from rrss internal buffers.
func (rrss *rawRowsShards) flush(flush func(rrs [][]rawRow), isFinal bool) {
var dst [][]rawRow
rrss.rowssToFlushLock.Lock()
defer rrss.rowssToFlushLock.Unlock()
var dst [][]rawRow
currentTimeMs := time.Now().UnixMilli()
flushDeadlineMs := rrss.flushDeadlineMs.Load()
if isFinal || currentTimeMs >= flushDeadlineMs {
rrss.rowssToFlushLock.Lock()
dst = rrss.rowssToFlush
rrss.rowssToFlush = nil
rrss.rowssToFlushLock.Unlock()
}
for i := range rrss.shards {

View File

@@ -8,6 +8,7 @@ import (
"reflect"
"regexp"
"sort"
"sync"
"testing"
"testing/quick"
"time"
@@ -191,6 +192,62 @@ func TestSearch_VariousTimeRanges(t *testing.T) {
testStorageOpOnVariousTimeRanges(t, f)
}
func TestStorageAddThenSearchConcurrently(t *testing.T) {
defer testRemoveAll(t)
s := MustOpenStorage(t.Name(), OpenOptions{})
defer s.MustClose()
const numMetrics = 100
f := func(workerID int, tr TimeRange) error {
mrs := make([]MetricRow, numMetrics)
step := (tr.MaxTimestamp - tr.MinTimestamp) / int64(numMetrics)
for i := range numMetrics {
name := fmt.Sprintf("metric_%04d_%04d", workerID, i)
mn := MetricName{MetricGroup: []byte(name)}
mrs[i].MetricNameRaw = mn.marshalRaw(nil)
mrs[i].Timestamp = tr.MinTimestamp + int64(i)*step
mrs[i].Value = float64(i)
}
s.AddRows(mrs, defaultPrecisionBits)
s.DebugFlush()
tfs := NewTagFilters()
re := fmt.Sprintf(`metric_%04d.*`, workerID)
if err := tfs.Add(nil, []byte(re), false, true); err != nil {
return fmt.Errorf("tfs.Add(%q) failed unexpectedly: %w", re, err)
}
return testAssertSearchResult(s, tr, tfs, mrs)
}
const concurrency = 20
var wg sync.WaitGroup
errs := make([]error, concurrency)
for workerID := range concurrency {
wg.Go(func() {
for m := time.Month(1); m <= 12; m++ {
tr := TimeRange{
MinTimestamp: time.Date(2025, m, 1, 0, 0, 0, 0, time.UTC).UnixMilli(),
MaxTimestamp: time.Date(2025, m+1, 0, 0, 0, 0, 0, time.UTC).UnixMilli() - 1,
}
err := f(workerID, tr)
if err != nil {
errs[workerID] = fmt.Errorf("worker %d failed on tr=%v: %w", workerID, &tr, err)
break
}
}
})
}
wg.Wait()
for _, err := range errs {
if err != nil {
t.Errorf("%s", err)
}
}
}
func testSearchInternal(s *Storage, tr TimeRange, mrs []MetricRow) error {
for i := range 10 {
// Prepare TagFilters for search.