Skip to content

Commit

Permalink
QLSWG: Add PromQL DSL interview response from Julius Volz.
Browse files Browse the repository at this point in the history
Signed-off-by: Chris Larsen <[email protected]>
  • Loading branch information
manolama committed Oct 5, 2023
1 parent 8fe7f1b commit e1b2519
Showing 1 changed file with 194 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
# Prometheus Query Language DSL Survey Response

### **Short Description:**

The Prometheus Query Language (PromQL) DSL is widely used for metrics and alerting, originating from
the Prometheus monitoring solution. A number of vendors have adopted the language for interoperability
and various extensions exist to work with non-metric data types.

### Overview

1. **List any over-arching design goals for the DSL. For example URI friendliness, minimal syntax,
advanced analytical capabilities, etc.**:

* Optimize for common metrics-based systems monitoring use cases. Don't try to solve every use
case under the sun that isn't systems monitoring or close to it.
* Support not only dashboarding and ad-hoc querying, but also fully integrate alerting use cases
with the query language.
* VECTOR MATH! Leverage the dimensional data model (labels) not only for flexible data selection,
but especially also for correlating / joining entire sets of metrics together on compatible label
sets without a lot of syntax: binary arithmetic, binary filter operators, binary set operators. Very
important for quickly calculating sets of ratios, sums, etc. between correlated series
(e.g. 100 disk usages divided by their respective disk sizes to get 100 labeled disk usage ratios).
* Terse, functional syntax that's quick to write and read.
* Functional language used only for reading, writes are handled out of band (e.g. via scrapes).
* Deep analytical capabilities kept to a minimum (at least for a start), again, mainly focused on live
systems monitoring use cases and less on deep data crunching / ML / statistics.
* Absolute timestamps (e.g. begin and end of a graph range) mostly kept out of the language
(the PromQL query text) itself and sent as a separate set of parameters. PromQL expressions mostly
just look backward some time range from the current evaluation step along the range of a graph
(or from a single evaluation step in the case of an instant query or rule query).

1. **What deficiencies or omissions in other DSLs lead to your decision to design a new language?**:

Prometheus was created at SoundCloud in 2012, coming from multiple years of Google.

* In 2012, most open-source TSDBs didn't have any query language at all. And alerting systems like
Nagios didn't even really have time series.
* Graphite was the closest thing to having a time series query language, but:

* It mixed data calculation and display concerns to a large degree.
* It didn't allow any kind of complex math between sets of correlated series (vector math).
* It didn't support a dimensional data model or the scale and dynamism that we needed.
* It wasn't meant for alerting in any way, although some people bolted alerting on top of it.

* A SQL-style language seemed very cumbersome for the way we wanted to deal both with vector math
(automatic joins on all labels) and time parameters. InfluxDB later tried a SQL-style language for
TSDB data and ended up regretting it.

1. **Were there any languages that inspired the DSL?**:

PromQL and Prometheus were heavily inspired by Google's Borgmon monitoring system that we had used
at Google in the years before joining SoundCloud. Basically we missed a similar system for our job
at SoundCloud and started building Prometheus and PromQL with a very similar architecture and design.
PromQL has diverged from and added to the Borgmon query language in major ways by now, but especially
the core principles such as the dimensional data model and the vector math / correlation of time series
are basically the same.

1. **Are there specific observability use cases the language was designed for?**:

Metrics-based systems monitoring in dynamic environments with a lot of dimensionality in the metrics
data, as well as potentially many short-lived time series (e.g. Kubernetes pods appearing and disappearing, etc.).

1. **Are there specific observability use cases that were intentionally _omitted_ in the design?**:

Prometheus and PromQL are 100% focused on time series / metrics. So no traces, logs, events, and the
like, for which you'll still want to run some other system.

1. **Are there any particular strengths or weaknesses in the language after observing it in use?**:

**Strengths:**

Mainly just refer back to the design goals here, which I think have been largely fulfilled and have been
very useful for flexible and powerful queries on dimensional data. Especially the syntactically brief but
powerful vector math / binary operators were new at the time and are still awesome (modulo the caveats
mentioned below).

**Weaknesses:**

* PromQL looks and works differently from many other languages, especially if you are expecting something SQL-like
or something where the query text itself contains all absolute timestamps / time ranges for the overall query as
well (these are sent separately from the query text for PromQL). This can make it a bit of a learning hurdle at
first. However, I think this was probably necessary.
* It's too easy to write PromQL expressions that accidentally turn out empty (without returning an error or warning).
For example, by referencing a metric or label combination for which there is simply no data. Or when getting binary
operator matching modifiers slightly wrong between sets of time series (vectors) that don't have compatible label
sets. This can get annoying especially when you build very deeply nested queries, and you don't know which part
makes the entire query result become empty. I've built tools like https://promlens.com/ (now OSS, part of the
Prometheus project) to help visualize the structure and data within each part of a query to help with this
and some other issues. Unless one introduces a super rigid schema into the expected data and the selection process
though, I'm not sure how to 100% "fix" this without making everything super verbose or cumbersome in other ways.
* Related to the above point, alerting rule outputs are considered "ok" if their PromQL expression returns an empty
result (on the flip side, any output series that do get returned are treated as alerts). This means that in the
worst case your alerting rules will silently fail if you are accidentally producing empty outputs vs. things
actually being ok.
* PromQL is relatively weak on the "deep statistics" front, e.g. doing more ML-y or deeper statistical analysis on
data. More focused on live monitoring.
* Some more namespacing for metrics or labels (and/or well-known metric or label names) might have helped to build
automatic and standardized tooling (dashboards, alerts, etc.) around things.

1. **Is the language intended at-rest data and/or streaming data?**:

At-rest data, though it's usually processing very recent data (e.g. to alert on what has happened in the last few minutes).

1. **Can users specify a source in the query language? E.g. a specific table or database?**:

Not directly as part of the language itself, but there's ways to configure Prometheus to query external databases for
certain vector selectors (see https://www.robustperception.io/promql-queries-against-sql-databases-using-a-read-adapter/ -
this is not super common though).

1. **Can users join with other sources than the primary database? E.g. a CSV file, cloud databases, etc.?**:

See above, it's not common but can be done.

1. **If joining of various time series sources is available, how are differing retentions handled?**:

This depends on the operation. Generally, a PromQL selector will select whatever data is available for the specified
filters and time ranges and not return an error or anything like that if it goes outside of a retention window where
old data has already been deleted (which it knows nothing about) - that part of the data range will just be empty,
and then it depends on whether you just display the data from both sources (one will be gappy, the other not) or
try to join them together somehow (in which case the entire result might become empty, but only for the respective
time range where data from one source is missing).

1. **How tightly coupled is the DSL to the data store model? (1 to 10 with 10 being extremely) tightly coupled)**:

The interface between the PromQL query engine and the underlying TSDB is relatively simple and allows for switching out
or extending the underlying TSDB implementation with something compatible (which has been done in multiple projects, e.g.
Thanos, Cortex/Mimir, or M3).

The PromQL<->TSDB interface only requires:

* Getting all label values for a set of matchers (within a given time range)
* Getting all label names for a set of matchers (within a given time range)
* Getting all series samples for a set of matchers (within a given time range)

1. **Is the DSL flexible enough to operate on data in different storage formats or contexts?**:

Generally PromQL does not care about the storage format at all, as long as it can access the TSDB via the
interface outlined above.

1. **What character sets are supported by the DSL?**:

Generally, PromQL strings and label values can contain any Unicode characters, whereas metric names
("[a-zA-Z_:][a-zA-Z0-9_:]*") and label names ("[a-zA-Z_][a-zA-Z0-9_]*") are more restricted in their character set.
See: https://prometheus.io/docs/concepts/data_model/ for details.

There are ongoing discussions for potentially allowing arbitrary characters via some escaping scheme.

1. **What characters are special or reserved in the DSL**:

See: https://prometheus.io/docs/concepts/data_model/

1. **Does the DSL allow for writing data or configuring the backing store or is it for querying only?**:

PromQL is for querying / reading only. Writes happen via a different path, e.g. data being scraped by Prometheus
or being deleted automatically after some configured retention time has passed.

## Metrics

1. **What metric measurement types are supported? E.g. monotonic counters, gauges, deltas, rates, bucketed
histograms, digests, booleans, etc.**

* Cumulative / monotonic counters (can occasionally reset to 0 when the process that tracks the counter restarts)
* Gauges
* "Classic" histograms: Histogram buckets exposed as one time series per bucket
* Native exponential histograms: Still experimental but getting more stable, entire histogram stored directly in
the sample value of a single series.
* Summaries (which are really just a bunch of gauges containing counts, sums, and quantiles, so nothing in PromQL
actually knows that they represent a "Summary" metric in aggregate)

1. **How does the DSL handle changes to the measurement type over time for a single series? E.g. if a counter
becomes a gauge during the query window?**

From the point of PromQL, counters, gauges, classic histograms, and so on are all just float64 values, and
the TSDB currently does not even permanently store the metric type for those. The only exception to this are
the new native histograms, where a sample value can now not just be a float64, but an entire encoded histogram.
Behavior of various PromQL functions if a series switches between float64 and native histogram over time is
still not 100% fleshed out, as native histograms are still being added / experimental.

1. **What values are supported as metrics? E.g. double precision floating point, integers, booleans, summaries
(sum, min, max, count, etc.), histogram bucket counts, encoded digests, etc.**

* Float64 for counters, gauges, etc.
* Entire exponential histograms (buckets) for native histograms.



## References

* [Querying Prometheus](https://prometheus.io/docs/prometheus/latest/querying/basics/)

## Thanks

Julius Volz and the Prometheus developers.

0 comments on commit e1b2519

Please sign in to comment.