Time-series database lab
Inside a time-series database: validate InfluxDB line protocol and Prometheus exposition text and see the series keys; watch Gorilla, Prometheus XOR/XOR2 and InfluxDB TSM compression bit by bit on your data (byte-identical to Prometheus's and InfluxDB's own encoders); estimate cardinality and memory; downsample counters correctly; size retention tiers; and watch Prometheus cut and compact blocks.
Added
How to use it
Time-series databases get their speed and their size from a few ideas: a series is a name plus a set of tags, samples arrive in time order at a steady rate, and neighbouring values are alike. This page takes those ideas apart on data you paste or generate. Everything runs in the page.
How to use it
Line protocol. Paste lines you would write to InfluxDB, or switch to Prometheus exposition and
paste the output of a /metrics endpoint. Each line is checked the way the server checks it:
escaping (a backslash escapes commas and spaces in measurements; commas, equals signs and spaces
in tag keys, tag values and field keys; quotes and backslashes in string fields), field types
(1.5 and 1 are floats, 1i an int64, 1u a uint64, "…" a string, t/true/False… a
boolean), ranges, timestamps in the chosen precision, and type conflicts between lines. The table
shows each point and its typed fields; Series keys lists the series (measurement plus tags sorted
by key) and the TSM keys InfluxDB stores (series key#!~#field). For exposition text it checks
names, label escapes, TYPE/HELP order, duplicate series and histogram buckets (increasing le,
cumulative counts, a +Inf bucket equal to _count). To query metrics, take them to the
PromQL and LogQL playground.
Compression. Pick a generated signal (a constant, a counter with and without a restart, a gauge,
temperatures to one decimal place, CPU percentages, integers…), a series from the first tab, or
paste timestamp_ms,value lines. The table compares bytes per sample: raw (16), varints, Gorilla
as in the paper, Prometheus’s XOR and XOR2 chunks of 120 samples, InfluxDB’s TSM blocks, and the
browser’s deflate of the raw and of pre-differenced columns as a stand-in for a general-purpose
compressor such as zstd or Snappy. Bit view writes out the first samples of one codec bit by
bit — header, timestamp and value fields in different colours, every field labelled (hover, or open
Field by field) — with the hex and a table of deltas, deltas of deltas and XORs.
| Codec | What it does |
|---|---|
Gorilla (paper) |
Pelkonen et al. 2015 §4.1: a 2-hour block with a 64-bit start time, the first delta in 14 bits, then the delta of deltas in |
Prometheus XOR |
|
Prometheus XOR2 |
|
InfluxDB TSM |
|
simple-8b |
64-bit words: a 4-bit selector and 60 bits of data split 240 or 120 ones, 60×1, 30×2 … 1×60 bits. |
Cardinality. Enter the metrics and the number of distinct values of each tag. The page multiplies them (the worst case, when every combination occurs), flags tags with 10,000 or more values, and estimates memory at a size per series you can change. The usual culprits are user IDs, request IDs, full URLs and email addresses in tags or labels.
Rollups and retention. Downsample a generated series into windows: min, max, average, last, and for counters the increase and per-second rate with restarts handled (a drop means the counter started again from zero). The chart shows why a naive difference of window values goes negative at a restart. Below, add retention tiers — interval, how long to keep it, values per point — and get the storage for your series count.
Storage engines. Drag the slider to move time on a Prometheus server: the head block, a block cut every 2 hours once the head spans 3, compaction into 6 h, 18 h and 54 h blocks, and blocks deleted at the retention. Beside it, the same story for InfluxDB’s TSM engine: WAL and cache, snapshots to level-1 files, compaction levels and shards.
Checked against
The tests encode 33 series with Prometheus’s own chunkenc package (Prometheus v0.315.1 — the
3.x line — NewXORChunk and NewXOR2Chunk) and InfluxDB 1.11.8’s TSM codecs (int.go,
timestamp.go, float.go) with jwilder/encoding/simple8b, and require this page’s output to be
byte-identical — including stale markers, negative and huge timestamps, every delta bucket edge,
and InfluxDB’s quirk of masking leading zeros to five bits before clamping. Every codec also
decodes its output back to the same bits. The Gorilla bucket layout is checked field by field
against the paper. Line protocol is checked against the escaping examples in InfluxDB’s
documentation, and the exposition parser against the example in Prometheus’s. The block planner is
a port of Prometheus’s db.go and compact.go (head.compactable, ExponentialBlockRanges,
selectDirs, splitByRange).
Sources: T. Pelkonen et al., "Gorilla: A Fast, Scalable, In-Memory Time Series Database", VLDB
2015; Prometheus tsdb/chunkenc and tsdb/docs/format/chunks.md; InfluxData,
line protocol reference
and In-memory indexing and the TSM
storage engine; Prometheus exposition
formats and storage; V. N. Anh and A. Moffat,
"Index compression using 64-bit words" (simple-8b), 2010.
Limits
-
XOR2 is shown without start timestamps (the optional
STdata) and for up to 127 samples a chunk. Histograms and native histograms are not encoded. -
Cardinality multiplies independent tags; real data is usually smaller. Memory per series is a rule of thumb — measure your own server.
-
The block simulation ingests continuously from time zero with no gaps, out-of-order samples or deletes.
Related: PromQL and LogQL playground, Storage engines: LSM-tree vs B-tree, Postings lab (simple-9/16, PForDelta and other integer codecs), Probabilistic sketches, Row key design (time-series keys in Bigtable and HBase), DuckDB lab.
Feedback is a gift. Something to improve, a feature to add, or a bug? Tell me.
Runs entirely in your browser; nothing you type leaves this page.