* Add basic initial developer docs for TSDB There's a decent amount of content already out there (blog posts, conference talks, etc), but: * when they get stale, they don't tend to get updated * they still leave me with questions that I'ld like to answer for developers (like me) who want to use, or work with, TSDB What I propose is developer docs inside the prometheus repository. Easy to find and harness the power of the community to expand it and keep it up to date. * perfect is the enemy of good. Let's have a base and incrementally improve * Markdown docs should be broad but not too deep. Source code comments can complement them, and are the ideal place for implementation details. Signed-off-by: Dieter Plaetinck <dieter@grafana.com> * use example code that works out of the box Signed-off-by: Dieter Plaetinck <dieter@grafana.com> * Apply suggestions from code review Co-authored-by: Ganesh Vernekar <15064823+codesome@users.noreply.github.com> Signed-off-by: Dieter Plaetinck <dieter@grafana.com> * PR feedback Signed-off-by: Dieter Plaetinck <dieter@grafana.com> * more docs Signed-off-by: Dieter Plaetinck <dieter@grafana.com> * PR feedback Signed-off-by: Dieter Plaetinck <dieter@grafana.com> * Apply suggestions from code review Signed-off-by: Dieter Plaetinck <dieter@grafana.com> Co-authored-by: Bartlomiej Plotka <bwplotka@gmail.com> * Apply suggestions from code review Signed-off-by: Dieter Plaetinck <dieter@grafana.com> Co-authored-by: Ganesh Vernekar <15064823+codesome@users.noreply.github.com> * feedback Signed-off-by: Dieter Plaetinck <dieter@grafana.com> * Update tsdb/docs/usage.md Signed-off-by: Dieter Plaetinck <dieter@grafana.com> Co-authored-by: Ganesh Vernekar <15064823+codesome@users.noreply.github.com> * final tweaks Signed-off-by: Dieter Plaetinck <dieter@grafana.com> * workaround docs versioning issue Signed-off-by: Dieter Plaetinck <dieter@grafana.com> * Move example code to real executable, testable example. Signed-off-by: Dieter Plaetinck <dieter@grafana.com> * cleanup example test and make sure it always reproduces Signed-off-by: Dieter Plaetinck <dieter@grafana.com> * obtain temp dir in a way that works with older Go versions Signed-off-by: Dieter Plaetinck <dieter@grafana.com> * Fix Ganesh's comments Signed-off-by: Ganesh Vernekar <ganeshvern@gmail.com> Co-authored-by: Ganesh Vernekar <15064823+codesome@users.noreply.github.com> Co-authored-by: Bartlomiej Plotka <bwplotka@gmail.com> Co-authored-by: Ganesh Vernekar <ganeshvern@gmail.com>
5 KiB
Usage
TSDB can be - and is - used by other applications such as Cortex and Thanos. This directory contains documentation for any developers who wish to work on or with TSDB.
For a full example of instantiating a database, adding and querying data, see the tsdb example in the docs.
tsdb/db_test.go
also demonstrates various specific usages of the TSDB library.
Instantiating a database
Callers should use tsdb.Open
to open a TSDB
(the directory may be new or pre-existing).
This returns a *tsdb.DB
which is the actual database.
A DB
has the following main components:
- Compactor: a leveled compactor. Note: it is currently the only compactor implementation. It runs automatically.
Head
- Blocks (persistent blocks)
The Head
is responsible for a lot. Here are its main components:
- WAL (Write Ahead Log).
stripeSeries
: this holds all the active series by linking tomemSeries
by an ID (aka "ref") and by labels hash.- Postings list (reverse index): For any label-value pair, holds all the corresponding series refs. Used for queries.
- Tombstones.
Adding data
Use db.Appender()
to obtain an "appender".
The golang docs speak mostly for themselves.
Remember:
- Use
Commit()
to add the samples to the DB and update the WAL. - Create a new appender each time you commit.
- Appenders are not concurrency safe, but scrapes run concurrently and as such, leverage multiple appenders concurrently. This reduces contention, although Commit() contend the same critical section (writing to the WAL is serialized), and may inflate append tail latency if multiple appenders try to commit at the same time.
Append may reject data due to these conditions:
timestamp < minValidTime
whereminValidTime
is the highest of:
- the maxTime of the last block (i.e. the last truncation time of Head) - updated via
Head.Truncate()
andDB.compactHead()
tsdb.min-block-duration/2
older than the max time in the Head block. Note that while technicallystorage.tsdb.min-block-duration
is configurable, it's a hidden option and changing it is discouraged. So We can assume this value to be 2h.
Breaching this condition results in "out of bounds" errors.
The first condition assures the block that will be generated doesn't overlap with the previous one (which simplifies querying)
The second condition assures the sample won't go into the so called "compaction window", that is the section of the data that might be in process of being saved into a persistent block on disk. (because that logic runs concurrently with ingestion without a lock)
2) The labels don't validate. (if the set is empty or contains duplicate label names)
3) If the sample, for the respective series (based on all the labels) is out of order or has a different value for the last (highest) timestamp seen. (results in storage.ErrOutOfOrderSample
and storage.ErrDuplicateSampleForTimestamp
respectively)
Commit()
may also refuse data that is out of order with respect to samples that were added via a different appender.
Querying data
Use db.Querier()
to obtain a "querier".
The golang docs speak mostly for themselves.
Remember:
- A querier can only see data that was committed when it was created. This limits the lifetime of a querier.
- A querier should be closed when you're done with it.
- Use mint/maxt to avoid loading unneeded data.
Example code
Find the example code for ingesting samples and querying them in tsdb/example_test.go