OpenObserve vs Prometheus & Mimir: Metrics Benchmark
Upcoming Webinar:<br>Getting Started with OpenObserve
August 27, 2026<br>11:00 AM ET
Register
\n\n## Why compare OpenObserve with Prometheus and Mimir\n\nPrometheus earned its place as the reference metrics database honestly. It is the storage engine behind a majority of self-hosted monitoring, its PromQL is the lingua franca of metrics queries, and it is battle-tested at the scale of most single-node deployments. Grafana Mimir extends that same data model and query language across a cluster, which is why teams already committed to the Grafana ecosystem reach for it when Prometheus runs out of headroom.\n\nThe difference is what happens as cardinality grows. Prometheus and Mimir are built around a time-series database that is extremely efficient for a specific access pattern (sequential scans over contiguous time series), but their cost on large, high-cardinality queries scales with the number of output points and the series the query touches. OpenObserve takes the other path: it stores metrics in a general-purpose columnar format, which is why the same data can serve PromQL, SQL, and dimensional analysis together, and why its query cost scales with the data actually scanned rather than the points emitted. Those files are open formats: Parquet is an Apache standard and Vortex is a Linux Foundation project, so tools like Spark, DuckDB, and Pandas can read the data directly. Prometheus and Mimir keep the same data in the Prometheus TSDB block format, readable only within that ecosystem rather than by general-purpose tools.\n\nCost keeps this comparison honest. In Grafana's 2025 observability survey, 74 percent of respondents said cost is a top factor when picking observability tools, and the average organization runs eight observability technologies ([Grafana 2025 survey](https://grafana.com/observability-survey/2025/)). Metrics cardinality is a big part of that bill: the difference between a million-series query that answers in seconds and one that refuses or restarts a container is not a latency annoyance, it is an incident. See our [metrics monitoring](https://openobserve.ai/blog/red-metrics-monitoring/) and [Prometheus metrics types](https://openobserve.ai/blog/prometheus-metrics-types/) guides for the broader picture on where cardinality shows up.\n\n## How we ran it\n\nThe methodology matters more than any single number, so here it is in full. The driver, the configurations, and every query live in the [benchmark repository](https://github.com/openobserve/openobserve-metrics-benchmark), so you can reproduce or dispute anything below.\n\n### Hardware and versions\n\nFour deployments, fully aligned: Prometheus, Grafana Mimir, OpenObserve on Parquet, and OpenObserve on Vortex. Each gets a dedicated EC2 `m7gd.2xlarge` (7 CPU, 474 GB local NVMe) with its data on the node's local instance store, so neither the disk nor a shared host decides the outcome. All are single-node deployments.\n\n- Prometheus `quay.io/prometheus/prometheus:v3.6.0`\n- Mimir `grafana/mimir:latest`\n- OpenObserve `v0.92.0`, deployed twice as an A/B differing only in `ZO_FILE_FORMAT`: one `parquet`, one `vortex`\n\n### The dataset\n\nThe workload comes from [openobserve/fake-webserver:v2](https://github.com/openobserve/fake-webserver): 24 pods, each producing ~45,000 time series, so the histogram's `_bucket` metric carries **1,085,760 active series**. A separately deployed OTel Collector writes the same data to all four systems simultaneously, so every system receives the exact same samples: **~2.2 billion across the `codelab_api_*` metrics**. Cardinality of the two key metrics:\n\n- `codelab_api_request_duration_seconds_bucket`: **1,085,760** series (the histogram queries)\n- `codelab_api_request_duration_seconds_count`: **41,760** series (the irate query)\n\nIngestion ran 2026-08-09 04:47–13:10 UTC (8h23m) and then stopped. Every query runs against a frozen dataset over absolutely-pinned time windows, so a run repeated an hour later sees the same bytes.\n\n### How the measurement is taken\n\nFour choices here move the numbers more than any configuration, so they are worth stating outright.\n\n- **Queries are issued from inside the cluster.** Driving a benchmark from a laptop over `kubectl port-forward` invalidates the result: the fastest query in this set answers in ~100 ms, and forwarding added 1,656 ms to 2,862 ms of pure overhead across repeats. Everything is measured from a pod in the same availability zone as all four systems, on a node that is not under test.\n- **Every system's data is on node-local NVMe.** Storage is not a variable, and no query is measuring EBS throughput.\n- **Ingestion is stopped before anything is measured.** Load still arriving during measurement would make each system's numbers depend on what it happened to be compacting.\n- **The step is computed, not pinned.** A fixed 15s step makes the point count grow with the window (1,440 points at...