Schedule DemoStart Free Trial

Unified Observability Platform for Modern IT Operations

Summarize with AI what Motadata does:

ObserveOps

  • Network Observability
  • Network Configuration & Compliance Management
  • Hybrid Infrastructure Monitoring
  • Log Monitoring
  • Application Performance Monitoring
  • Real User Monitoring

ServiceOps

  • Service Management
  • IT Asset & Configuration Management
  • Patch & Deployment Management
  • Agentic AI & Orchestration
  • MSP Edition

By Use Cases

  • Data Centre Monitoring
  • Docker Monitoring
  • Enterprise Service Management
  • IT Service Desk
  • ITSM MSP
  • Enterprise Network Monitoring

By Technologies

  • AWS Monitoring
  • Azure Monitoring
  • Kubernetes Monitoring
  • DevOps Observability
  • REST API Monitoring
  • Storage Monitoring

Resources

  • Getting Started
  • Documentation
  • Integrations
  • IT Glossary
  • Whitepapers
  • Ebooks & Guides
  • Product Brochures
  • Success Stories
  • Comparison
  • Features

Community

  • Blog
  • Press Releases
  • Events
  • Webinar
  • Become a Partner

Company

  • Company
  • Careers
  • Contact Us
  • Customer Support

Get in Touch

  • Request Demo
  • sales@motadata.com
  • support@motadata.com
© 2026 Mindarray Systems Limited. All rights reserved.
Privacy PolicyTerms of Service
Back to Blog
ObserveOps
9 min read

High Cardinality Metrics: What They Are and How to Control Them

Written by

Ramya Shah

Technical Writer

Reviewed by

Keertan Zala

Product Manager

Published

October 12, 2026

9 min read

Metrics bills climb without anyone adding a dashboard. The cause usually sits in the code. A label picked up a customer ID, and a few hundred time series became a few hundred thousand.

High cardinality metrics do that. They rarely give warning before the queries start timing out. Teams meet the word cardinality in two places. Database cardinality measures how unique a column's values are. Your monitoring stack uses the same word for something that decides what you pay.

In this blog, you'll see:

  • The arithmetic that turns three labels into billions of time series.

  • Which labels are safe to ship, which are risky, and which never belong.

  • How to find your worst offenders and cut them without losing the detail.

By the end you'll be able to set a cardinality budget before a metric ships.

What Is High Cardinality?

Cardinality counts the unique time series a metric produces. High cardinality means that number runs large. One of the metric's labels is usually carrying far more values than anyone expected.

A time series is one unique combination of a metric name and its labels. Change any label value and you get a new series. It gets stored and indexed separately from the rest.

So a counter called http_requests_total becomes many separate series in storage. You get one series for every combination of method, status code and service.

Labels make a metric worth collecting (and they also multiply it). A counter with no labels answers one question, and the same counter with five answers hundreds.

Prometheus keeps an index of every active series in memory, so queries can resolve labels fast. Most systems built on the same model do too. That index is where the trouble starts. High cardinality stops being a design question there and becomes an operations problem.

How Cardinality Multiplies Into a Series Count

Each label multiplies the series count by the number of values it can take. The table below walks one HTTP counter through four versions of itself. Each version adds a single label.

What the metric tracks

Labels

Values each

Unique series

Requests by method, status and service

3

5, 8, 10

400

The same, plus the instance it ran on

4

plus 50

20,000

The same, plus the customer who called

5

plus 2,000

40,000,000

The same, plus the raw request path

6

plus 500

20,000,000,000

Two labels took that metric from 400 series to 40 million. The customer ID did most of the damage. Its value count grows every time sales closes a deal.

The raw request path finished the job. Query strings and record IDs make that label effectively unbounded, so the series count never hits a ceiling (20 billion is just where this example stopped counting).

Nobody plans this. A cardinality problem arrives one reasonable-looking label at a time. We've watched a single label take a dashboard from instant to unusable, and the developer who added it had a perfectly good reason.

The diagram below runs the same four steps as the table, with the multiplication made visible.

High Cardinality Metrics: What They Are and How to Control Them

High Cardinality vs Cardinality Explosion: Which One Do You Have?

High cardinality describes a property of a metric. Cardinality explosion describes an event that hits your monitoring system. Telling them apart decides whether you're having a budget conversation or a rollback conversation.

A metric with high cardinality can stay perfectly healthy. Plenty of teams run millions of series deliberately and get real value from the detail. The observability 2.0 argument goes further, treating wide high-cardinality events as the better primitive altogether.

A cardinality explosion happens suddenly. One deploy ships one new label, and the series count jumps by an order of magnitude. Two scrape intervals is all it takes (there's no gradual climb to warn you).

One question sorts them. Did the series count grow with your business over months, or jump on the day of a release?

Growth over months means you buy capacity or start aggregating. A jump after a release means you go find the commit. The faster you tell those apart, the less time you spend arguing about storage.

What Breaks When the Series Count Climbs

Three things break as series counts climb. They break in a predictable order: memory first, then queries, then the invoice.

1. The Index Has to Live in Memory

Time series databases keep an index of active series in RAM. That's what lets a query resolve labels quickly. Every active series takes a share of that memory, queried or not (an abandoned dashboard still costs you RAM).

Prometheus will tell you where the memory goes. Its TSDB status endpoint reports memoryInBytesByLabelName, which attributes consumption to individual label names.

When the index outgrows available RAM, the failure isn't graceful. Scrapes start to queue and the process gets killed. You lose your monitoring at the exact moment you need it.

2. Every Query Scans Every Matching Series

A query that aggregates across a label has to touch every series matching it. Forty million series behind one metric name means forty million entries to resolve. The aggregation only starts once all of those are done.

Dashboards feel this before alerts do. Panels load slowly, then they time out. The timeout usually happens during the incident that made someone open the dashboard.

Alert rules run on the same engine. A rule that can't finish inside its evaluation interval stops producing results. The alert never fires, and nobody gets told why.

3. Your Meter Counts Series, Not Dashboards

Observability pricing meters one of two things. Some vendors count the custom metrics or series you keep. Others count the gigabytes you send. Cardinality drives both numbers upward.

That turns a label into a purchasing decision. A developer adding customer_id to a counter is committing budget. Almost nobody in that review sees it that way (the cost doesn't land for weeks).

Metrics, Logs and Flows on One Backend

ObserveOps Infinity applies structure at ingest, so metrics, logs, traps and flows all arrive as queryable fields.

Explore ObserveOps Infinity

Which Labels Are Safe, Risky or Never Worth Shipping

One question decides whether a label is safe. Can you write down every value it will ever take? According to the Prometheus instrumentation guidelines, you should keep the cardinality of your metrics below 10. Anything with the potential to pass 100 needs a different approach.

That number surprises teams who've been attaching pod names to everything. The table below sorts the labels that turn up most often in real instrumentation.

Label

Typical value count

Verdict

Why

HTTP method

About 8

Safe

Bounded by the spec itself

Status code

Tens

Safe

Bounded, and you need it to find errors

Service or job name

Tens to hundreds

Safe

Grows with the org chart, not with traffic

Region or availability zone

Under 50

Safe

Your provider sets the ceiling

Environment

3 to 5

Safe

Fixed set that rarely changes

Pod or instance name

Hundreds, churning

Risky

Every rollout mints a new batch of values

Templated endpoint path

Tens to hundreds

Risky

Safe templated, fatal if the raw path leaks in

Customer or tenant ID

Thousands

Risky

Fine at 50 tenants, ruinous at 50,000

Version or commit SHA

Unbounded over time

Risky

The value count never stops growing

User ID, email or session ID

Unbounded

Never

One value per person or per visit

Raw URL with query string

Unbounded

Never

Record IDs and parameters make it infinite

Trace ID or request ID

Unbounded

Never

One new series for every single request

The risky rows are the ones that need your judgment. A tenant ID works fine across 50 customers and breaks things across 50,000. The same label belongs in different columns at different companies.

The never rows carry no judgment at all. We've yet to hear a good argument for any of them. A trace ID produces one series per request by definition, so your series count tracks your traffic for as long as you keep the data.

Labels for the golden signals stay cheap, which is why that approach survives contact with scale. Latency, traffic, errors and saturation need service and status code. Both of those stay bounded.

Why Kubernetes Makes Cardinality Worse

Kubernetes multiplies cardinality in ways nobody configured on purpose. The platform mints and retires identifiers constantly. Your monitoring stack then labels metrics with them automatically.

Pod names change on every rollout. Take a deployment with 30 replicas that ships twice a week. It retires 60 pod names a week and creates 60 more. The old series stay queryable until retention clears them.

Container IDs are worse, because a restart changes them and that doesn't need a deploy. A crash-looping pod can generate thousands of label values on its own (and it does that while you watch).

Histograms are the multiplier most teams miss. A histogram with 12 buckets produces 14 series for every label combination. That's the 12 buckets plus the sum and count series. So every label you add gets multiplied by 14 before anything else happens.

On Kubernetes, we would not trust the defaults at scale. Collectors and service meshes inject labels before anyone reviews them. They land on every metric at once.

How Do You Find Your Worst Offenders?

Ask your own time series database which metrics hold the most series. Every major stack can answer that (most teams have simply never asked). Two or three metric names usually hold most of them.

The table below covers where to look on the platforms most teams run.

Where you look

What to run

What it gives you

Prometheus HTTP API

GET /api/v1/status/tsdb

Series counts and label value counts, ranked

Prometheus web UI

Status, then TSDB Status

The same statistics rendered, top 10 by default

Prometheus API, wider view

/api/v1/status/tsdb?limit=100

Raises the default 10 results, up to 10000

PromQL, ranked by metric

topk(10, count by (__name__)({__name__=~".+"}))

The ten metric names holding the most series

OpenTelemetry Collector

The view and attribute processors

Where to drop attributes before they are exported

Read labelValueCountByLabelName first. It names the label carrying the most distinct values. That's usually the one that caused the problem.

Then check seriesCountByMetricName to see which metric holds them. One metric name sitting on half your total series tells you where to spend the afternoon.

Run this on a schedule instead of during an incident. The teams we work with check weekly. That catches a bad label while the number is still small. An OpenTelemetry collector then gives you somewhere to fix it without an application release.

See Where Your Series Count Is Concentrated

Book a session and we'll run your noisiest metric source through the pipeline and show what lands.

Book an ObserveOps Demo

How to Cut Cardinality Without Losing the Detail

Cutting cardinality means moving detail somewhere cheaper. These five steps work in order. The first buys the most time for the least effort.

1. Drop the Label at the Collector

Fix the label at the collection layer, before it reaches storage. A collector rule takes effect across every service at once. That beats waiting on a release from each team that owns a metric.

This route is reversible too. A rule you regret can be removed in minutes. A code change has to go around the release cycle again.

2. Template the Path Before It Becomes a Label

Replace record IDs in a path with a placeholder, so the label stays bounded. The route /users/{id}/orders carries the same operational meaning as the raw path. It holds a few hundred values instead of millions.

Most web frameworks already expose the matched route. Using the raw URL is usually an oversight (nobody argues for it on purpose).

3. Move the Identifier to Logs or Traces

High-detail identifiers belong on the signals built to carry them. A customer ID sits on a log line as one field, costing you a single event. The same ID on a metric multiplies every series behind it.

The split between logs and metrics settles this for you. Metrics answer how many and how fast across a population. Traces answer what happened to one request.

Exemplars are worth knowing about here. They attach a trace ID to a metric sample without adding a label. A slow histogram bucket then links out to a real request.

4. Aggregate Before It Lands

Aggregate away the dimensions nobody queries, at ingest. A telemetry pipeline can roll a per-pod metric up to per-deployment before storage. You keep the number you chart and drop the ones you never opened.

Keep the raw signal for a short window if you need it. We see teams run a few days of full detail plus months of aggregated history. That costs a fraction of keeping everything at full resolution.

5. Put a Label Budget in Code Review

Make cardinality a review question, so the fix lands before the metric ships. The reviewer only has to answer one thing. Can they list every value the new label will take?

Teams who adopt this find the conversation takes about a minute. The developer either names the values or moves the field to a log line. Both outcomes beat a rollback three weeks later.

What Does High Cardinality Do to Your Observability Bill?

High cardinality raises your bill through whichever meter your vendor uses. The table below shows what each meter counts and where cardinality hits it.

Pricing meter

What it counts

What cardinality does to it

Per custom metric or series

Unique time series retained

Every new label value adds a billable series

Per gigabyte ingested

Samples written per scrape

More series means more samples at the same scrape rate

Per source

How many things you watch

Nothing, because the source count does not move

The first two meters punish the same mistake. Neither one tells you which label caused it. The invoice arrives as a single number, weeks after the deploy that moved it.

We price ObserveOps on that third row for the signals where volume runs wildest. Log and flow monitoring are licensed per source, so the meter tracks how many things you watch instead of how much data they emit.

That removes the worst surprise on the log side. A chatty application cannot increase your license cost on its own. It can still fill your storage, so retention policy still needs setting properly.

On the ingest side, the observability pipeline applies structure as data arrives. Logs, events, traps, flows and metrics all land as queryable fields, with policy-driven retention attached. The pipeline ships in the base edition, so controlling what gets stored isn't a capability you upgrade into.

It won't write your label schema for you, and no platform will. Only your team knows whether tenant ID means 50 values or 50,000. That judgment stays with the people who own the service.

Keeping monitoring and the service desk on one unified observability and ITSM platform helps with the follow-up. The alert, the metric behind it and the ticket it raises then live on a single record.

How Do You Set a Cardinality Budget?

A cardinality budget gives every metric a series ceiling before anyone adds a label to it. Four numbers produce that ceiling, and the table below works them out on a mid-sized estate.

Step

What you work out

Worked example

1. Ceiling

The active series your platform and budget can carry

2,000,000 series

2. Keepers

The metric names you actually chart or alert on

400 metrics

3. Share

Ceiling divided by keepers

5,000 series per metric

4. Label test

New label values multiplied by the metric's current series

400 times 2,000 tenants = 800,000, well over the share

Step 4 does the real work. A label that pushes a metric past its share goes onto a log line or a span instead, and the data survives either way.

Start with the metrics you already have, before you write a single rule. Pull the top ten metric names by series count, then the top ten labels by distinct values. Two labels usually explain most of the total.

We'd fix those two at the collector first, because that change needs no application release. Then set the review question for new metrics, so the next one arrives inside the budget already.

Set log retention separately from the metrics work. The two bills move independently. Teams who tune only one of them tend to get surprised by the other.

Point a Trial at Your Noisiest Metric Source

Start a free trial, send one real source through the pipeline, and see what the structure looks like.

Start a Free ObserveOps Trial

Set the Label Budget Before the Next Metric Ships

Treat a label as a commitment. Every value it can take is a series you've agreed to store, index and pay for. That one shift catches most cardinality problems while they're still a line in a pull request.

The discipline itself stays small. Bounded labels on metrics, unbounded identifiers on logs and traces, and a review question that catches the difference.

None of it is free. Dropping a label costs you a slice of detail. That detail might be exactly what you want during the next incident, and log filtering decisions carry the same trade-off.

The teams we see get this right stop buying capacity to store questions nobody asks. The monitoring bill then tracks the size of your estate instead of one careless commit.

FAQs

What is the difference between cardinality and dimensionality?

Dimensionality counts how many labels a metric carries. Cardinality counts how many unique series those labels produce together. A metric with four labels has low dimensionality. It can still reach millions of series if one label runs unbounded.

Can a time series database handle high cardinality metrics?

Modern engines handle millions of series, though each has a limit and a cost curve. A different database buys headroom without removing the need for label discipline. ObserveOps keeps metrics, logs and flows on one backend, so the series count has fewer places to hide.

Does high cardinality affect logs and traces the same way it affects metrics?

Logs and traces handle identifiers very differently. They store them as fields on individual events, so a unique value adds one record instead of a whole new series. That's why moving a customer ID off a metric and onto a log line works.

Will dropping a label delete the history I already collected?

Existing series stay in storage until retention expires, so old dashboards keep working on historical data. New samples arrive without the label. Any query spanning the change will show a gap in that one dimension.

How often should you audit metric cardinality?

Monthly suits most teams, and weekly suits anyone deploying often or running Kubernetes. Pull the top metric names by series count and the top labels by distinct values. Compare against the last run to see what moved.

RS

Author

Ramya Shah

Technical Writer

Ramya Shah is a technical content writer with a computer engineering background and roots in automotive journalism. He covers IT Service Management, observability, IT operations, and AI-driven automation. An early adopter of AI-assisted writing workflows, he turns complex IT processes into clear, engaging content optimized for search and answer engines (AEO), lifting content output and organic visibility.

Share:
Table of Contents
Subscribe to Our Newsletter

Get the latest insights and updates delivered to your inbox.

Related Articles

Continue reading with these related posts

ObserveOps

What is Distributed Tracing? How a Request Becomes a Trace

Ramya ShahOct 21, 202610 min read
ObserveOps

What is Jaeger Tracing and How does It Locate Slowdowns Across Microservices

Poonam LalaniOct 21, 202611 min read
ObserveOps

How to View, Filter and Manage Docker Logs Without Losing Them or Filling the Disk

Poonam LalaniOct 19, 202611 min read