High cardinality

A field with a huge number of distinct values, like user_id or a raw URL. Priceless in traces, ruinous as a metric label.

tagging by user blows up the billtoo many unique valueshigh cardinaltiycardinality explosionwhy did my metrics bill go up 10xadding user_id as a labeltoo many label combinationsunique values per field

See it

Live demo coming soon

What it is

Cardinality is just the count of distinct values a field can take. Status code is low cardinality (about a dozen values). user_id, session_id, request URL, and email are high cardinality (millions). The word only becomes scary in metrics, because a time-series database stores one separate series per unique combination of label values. Add user_id to a metric that already has 100 routes and 5 status codes and you did not create one chart, you created millions of series, each with its own memory, index entry, and line item on the invoice.

The fix is not 'avoid high cardinality', it is 'put it in the right store'. Metrics want low-cardinality labels: route template, status class, region. Traces, logs, and wide events are built for the high stuff, and columnar backends (Honeycomb, ClickHouse, most trace storage) will happily let you filter by user_id, which is exactly the question you actually have during an incident: not 'is the error rate up' but 'which customers are hitting this'.

Gotcha: the explosion usually sneaks in, it is rarely someone typing user_id on purpose. Raw paths like /orders/8821, error messages with a timestamp inside, Kubernetes pod names that change every deploy, and full user agent strings are the usual culprits. Normalize paths to route templates, strip variable text out of labels, and put a hard cardinality limit in the collector so one bad deploy cannot take the metrics store down with it.

Ask AI for it

Audit this service's metric labels for cardinality problems and fix them. Replace raw request paths with route templates (/orders/:id), drop user_id, session_id, email, full URL, and user agent from all metric labels, and collapse status codes to status classes (2xx, 4xx, 5xx). Move that high-cardinality context onto spans and structured log events instead, where it can still be filtered during an incident. Then add a cardinality limit in the OpenTelemetry Collector or Prometheus scrape config, and a query that reports the top 10 highest-cardinality label keys so regressions get caught early.

You might have meant

metriccardinality explosionwide eventsamplingtime series database