mirror of https://github.com/prometheus/prometheus
278 lines
13 KiB
Markdown
278 lines
13 KiB
Markdown
---
|
||
title: Storage
|
||
sort_rank: 5
|
||
---
|
||
|
||
# Storage
|
||
|
||
Prometheus includes a local on-disk time series database, but also optionally integrates with remote storage systems.
|
||
|
||
## Local storage
|
||
|
||
Prometheus's local time series database stores data in a custom, highly efficient format on local storage.
|
||
|
||
### On-disk layout
|
||
|
||
Ingested samples are grouped into blocks of two hours. Each two-hour block consists
|
||
of a directory containing a chunks subdirectory containing all the time series samples
|
||
for that window of time, a metadata file, and an index file (which indexes metric names
|
||
and labels to time series in the chunks directory). The samples in the chunks directory
|
||
are grouped together into one or more segment files of up to 512MB each by default. When
|
||
series are deleted via the API, deletion records are stored in separate tombstone files
|
||
(instead of deleting the data immediately from the chunk segments).
|
||
|
||
The current block for incoming samples is kept in memory and is not fully
|
||
persisted. It is secured against crashes by a write-ahead log (WAL) that can be
|
||
replayed when the Prometheus server restarts. Write-ahead log files are stored
|
||
in the `wal` directory in 128MB segments. These files contain raw data that
|
||
has not yet been compacted; thus they are significantly larger than regular block
|
||
files. Prometheus will retain a minimum of three write-ahead log files.
|
||
High-traffic servers may retain more than three WAL files in order to keep at
|
||
least two hours of raw data.
|
||
|
||
A Prometheus server's data directory looks something like this:
|
||
|
||
```
|
||
./data
|
||
├── 01BKGV7JBM69T2G1BGBGM6KB12
|
||
│ └── meta.json
|
||
├── 01BKGTZQ1SYQJTR4PB43C8PD98
|
||
│ ├── chunks
|
||
│ │ └── 000001
|
||
│ ├── tombstones
|
||
│ ├── index
|
||
│ └── meta.json
|
||
├── 01BKGTZQ1HHWHV8FBJXW1Y3W0K
|
||
│ └── meta.json
|
||
├── 01BKGV7JC0RY8A6MACW02A2PJD
|
||
│ ├── chunks
|
||
│ │ └── 000001
|
||
│ ├── tombstones
|
||
│ ├── index
|
||
│ └── meta.json
|
||
├── chunks_head
|
||
│ └── 000001
|
||
└── wal
|
||
├── 000000002
|
||
└── checkpoint.00000001
|
||
└── 00000000
|
||
```
|
||
|
||
Note that a limitation of local storage is that it is not clustered or
|
||
replicated. Thus, it is not arbitrarily scalable or durable in the face of
|
||
drive or node outages and should be managed like any other single node
|
||
database. The use of RAID is suggested for storage availability, and
|
||
[snapshots](querying/api.md#snapshot) are recommended for backups. With proper
|
||
architecture, it is possible to retain years of data in local storage.
|
||
|
||
Alternatively, external storage may be used via the
|
||
[remote read/write APIs](https://prometheus.io/docs/operating/integrations/#remote-endpoints-and-storage).
|
||
Careful evaluation is required for these systems as they vary greatly in durability,
|
||
performance, and efficiency.
|
||
|
||
For further details on file format, see [TSDB format](/tsdb/docs/format/README.md).
|
||
|
||
## Compaction
|
||
|
||
The initial two-hour blocks are eventually compacted into longer blocks in the background.
|
||
|
||
Compaction will create larger blocks containing data spanning up to 10% of the retention time,
|
||
or 31 days, whichever is smaller.
|
||
|
||
## Operational aspects
|
||
|
||
Prometheus has several flags that configure local storage. The most important are:
|
||
|
||
- `--storage.tsdb.path`: Where Prometheus writes its database. Defaults to `data/`.
|
||
- `--storage.tsdb.retention.time`: When to remove old data. Defaults to `15d`.
|
||
Overrides `storage.tsdb.retention` if this flag is set to anything other than default.
|
||
- `--storage.tsdb.retention.size`: The maximum number of bytes of storage blocks to retain.
|
||
The oldest data will be removed first. Defaults to `0` or disabled. Units supported:
|
||
B, KB, MB, GB, TB, PB, EB. Ex: "512MB". Based on powers-of-2, so 1KB is 1024B. Only
|
||
the persistent blocks are deleted to honor this retention although WAL and m-mapped
|
||
chunks are counted in the total size. So the minimum requirement for the disk is the
|
||
peak space taken by the `wal` (the WAL and Checkpoint) and `chunks_head`
|
||
(m-mapped Head chunks) directory combined (peaks every 2 hours).
|
||
- `--storage.tsdb.retention`: Deprecated in favor of `storage.tsdb.retention.time`.
|
||
- `--storage.tsdb.wal-compression`: Enables compression of the write-ahead log (WAL).
|
||
Depending on your data, you can expect the WAL size to be halved with little extra
|
||
cpu load. This flag was introduced in 2.11.0 and enabled by default in 2.20.0.
|
||
Note that once enabled, downgrading Prometheus to a version below 2.11.0 will
|
||
require deleting the WAL.
|
||
|
||
Prometheus stores an average of only 1-2 bytes per sample. Thus, to plan the
|
||
capacity of a Prometheus server, you can use the rough formula:
|
||
|
||
```
|
||
needed_disk_space = retention_time_seconds * ingested_samples_per_second * bytes_per_sample
|
||
```
|
||
|
||
To lower the rate of ingested samples, you can either reduce the number of
|
||
time series you scrape (fewer targets or fewer series per target), or you
|
||
can increase the scrape interval. However, reducing the number of series is
|
||
likely more effective, due to compression of samples within a series.
|
||
|
||
If your local storage becomes corrupted for whatever reason, the best
|
||
strategy to address the problem is to shut down Prometheus then remove the
|
||
entire storage directory. You can also try removing individual block directories,
|
||
or the WAL directory to resolve the problem. Note that this means losing
|
||
approximately two hours data per block directory. Again, Prometheus's local
|
||
storage is not intended to be durable long-term storage; external solutions
|
||
offer extended retention and data durability.
|
||
|
||
CAUTION: Non-POSIX compliant filesystems are not supported for Prometheus'
|
||
local storage as unrecoverable corruptions may happen. NFS filesystems
|
||
(including AWS's EFS) are not supported. NFS could be POSIX-compliant,
|
||
but most implementations are not. It is strongly recommended to use a
|
||
local filesystem for reliability.
|
||
|
||
If both time and size retention policies are specified, whichever triggers first
|
||
will be used.
|
||
|
||
Expired block cleanup happens in the background. It may take up to two hours
|
||
to remove expired blocks. Blocks must be fully expired before they are removed.
|
||
|
||
## Remote storage integrations
|
||
|
||
Prometheus's local storage is limited to a single node's scalability and durability.
|
||
Instead of trying to solve clustered storage in Prometheus itself, Prometheus offers
|
||
a set of interfaces that allow integrating with remote storage systems.
|
||
|
||
### Overview
|
||
|
||
Prometheus integrates with remote storage systems in three ways:
|
||
|
||
- Prometheus can write samples that it ingests to a remote URL in a standardized format.
|
||
- Prometheus can receive samples from other Prometheus servers in a standardized format.
|
||
- Prometheus can read (back) sample data from a remote URL in a standardized format.
|
||
|
||
![Remote read and write architecture](images/remote_integrations.png)
|
||
|
||
The read and write protocols both use a snappy-compressed protocol buffer encoding over
|
||
HTTP. The protocols are not considered as stable APIs yet and may change to use gRPC
|
||
over HTTP/2 in the future, when all hops between Prometheus and the remote storage can
|
||
safely be assumed to support HTTP/2.
|
||
|
||
For details on configuring remote storage integrations in Prometheus, see the
|
||
[remote write](configuration/configuration.md#remote_write) and
|
||
[remote read](configuration/configuration.md#remote_read) sections of the Prometheus
|
||
configuration documentation.
|
||
|
||
The built-in remote write receiver can be enabled by setting the
|
||
`--web.enable-remote-write-receiver` command line flag. When enabled,
|
||
the remote write receiver endpoint is `/api/v1/write`.
|
||
|
||
For details on the request and response messages, see the
|
||
[remote storage protocol buffer definitions](https://github.com/prometheus/prometheus/blob/main/prompb/remote.proto).
|
||
|
||
Note that on the read path, Prometheus only fetches raw series data for a set of
|
||
label selectors and time ranges from the remote end. All PromQL evaluation on the
|
||
raw data still happens in Prometheus itself. This means that remote read queries
|
||
have some scalability limit, since all necessary data needs to be loaded into the
|
||
querying Prometheus server first and then processed there. However, supporting
|
||
fully distributed evaluation of PromQL was deemed infeasible for the time being.
|
||
|
||
### Existing integrations
|
||
|
||
To learn more about existing integrations with remote storage systems, see the
|
||
[Integrations documentation](https://prometheus.io/docs/operating/integrations/#remote-endpoints-and-storage).
|
||
|
||
## Backfilling from OpenMetrics format
|
||
|
||
### Overview
|
||
|
||
If a user wants to create blocks into the TSDB from data that is in
|
||
[OpenMetrics](https://openmetrics.io/) format, they can do so using backfilling.
|
||
However, they should be careful and note that it is not safe to backfill data
|
||
from the last 3 hours (the current head block) as this time range may overlap
|
||
with the current head block Prometheus is still mutating. Backfilling will
|
||
create new TSDB blocks, each containing two hours of metrics data. This limits
|
||
the memory requirements of block creation. Compacting the two hour blocks into
|
||
larger blocks is later done by the Prometheus server itself.
|
||
|
||
A typical use case is to migrate metrics data from a different monitoring system
|
||
or time-series database to Prometheus. To do so, the user must first convert the
|
||
source data into [OpenMetrics](https://openmetrics.io/) format, which is the
|
||
input format for the backfilling as described below.
|
||
|
||
### Usage
|
||
|
||
Backfilling can be used via the Promtool command line. Promtool will write the blocks
|
||
to a directory. By default this output directory is ./data/, you can change it by
|
||
using the name of the desired output directory as an optional argument in the sub-command.
|
||
|
||
```
|
||
promtool tsdb create-blocks-from openmetrics <input file> [<output directory>]
|
||
```
|
||
|
||
After the creation of the blocks, move it to the data directory of Prometheus.
|
||
If there is an overlap with the existing blocks in Prometheus, the flag
|
||
`--storage.tsdb.allow-overlapping-blocks` needs to be set for Prometheus versions
|
||
v2.38 and below. Note that any backfilled data is subject to the retention
|
||
configured for your Prometheus server (by time or size).
|
||
|
||
#### Longer Block Durations
|
||
|
||
By default, the promtool will use the default block duration (2h) for the blocks;
|
||
this behavior is the most generally applicable and correct. However, when backfilling
|
||
data over a long range of times, it may be advantageous to use a larger value for
|
||
the block duration to backfill faster and prevent additional compactions by TSDB later.
|
||
|
||
The `--max-block-duration` flag allows the user to configure a maximum duration of blocks.
|
||
The backfilling tool will pick a suitable block duration no larger than this.
|
||
|
||
While larger blocks may improve the performance of backfilling large datasets,
|
||
drawbacks exist as well. Time-based retention policies must keep the entire block
|
||
around if even one sample of the (potentially large) block is still within the
|
||
retention policy. Conversely, size-based retention policies will remove the entire
|
||
block even if the TSDB only goes over the size limit in a minor way.
|
||
|
||
Therefore, backfilling with few blocks, thereby choosing a larger block duration,
|
||
must be done with care and is not recommended for any production instances.
|
||
|
||
## Backfilling for Recording Rules
|
||
|
||
### Overview
|
||
|
||
When a new recording rule is created, there is no historical data for it.
|
||
Recording rule data only exists from the creation time on.
|
||
`promtool` makes it possible to create historical recording rule data.
|
||
|
||
### Usage
|
||
|
||
To see all options, use: `$ promtool tsdb create-blocks-from rules --help`.
|
||
|
||
Example usage:
|
||
|
||
```
|
||
$ promtool tsdb create-blocks-from rules \
|
||
--start 1617079873 \
|
||
--end 1617097873 \
|
||
--url http://mypromserver.com:9090 \
|
||
rules.yaml rules2.yaml
|
||
```
|
||
|
||
The recording rule files provided should be a normal
|
||
[Prometheus rules file](https://prometheus.io/docs/prometheus/latest/configuration/recording_rules/).
|
||
|
||
The output of `promtool tsdb create-blocks-from rules` command is a directory that
|
||
contains blocks with the historical rule data for all rules in the recording rule
|
||
files. By default, the output directory is `data/`. In order to make use of this
|
||
new block data, the blocks must be moved to a running Prometheus instance data dir
|
||
`storage.tsdb.path` (for Prometheus versions v2.38 and below, the flag
|
||
`--storage.tsdb.allow-overlapping-blocks` must be enabled). Once moved, the new
|
||
blocks will merge with existing blocks when the next compaction runs.
|
||
|
||
### Limitations
|
||
|
||
- If you run the rule backfiller multiple times with the overlapping start/end times,
|
||
blocks containing the same data will be created each time the rule backfiller is run.
|
||
- All rules in the recording rule files will be evaluated.
|
||
- If the `interval` is set in the recording rule file that will take priority over
|
||
the `eval-interval` flag in the rule backfill command.
|
||
- Alerts are currently ignored if they are in the recording rule file.
|
||
- Rules in the same group cannot see the results of previous rules. Meaning that rules
|
||
that refer to other rules being backfilled is not supported. A workaround is to
|
||
backfill multiple times and create the dependent data first (and move dependent
|
||
data to the Prometheus server data dir so that it is accessible from the Prometheus API).
|