Skip to content
Mustafa Erbay
Technology · 9 min read · görüntülenme Türkçe oku

Metric Cardinality: An Overlooked Performance Burden or a Developer

How does metric cardinality affect system performance? In this guide, we delve deep into overlooked burdens and developer mistakes.

100%

What is Metric Cardinality and Why is it Important?

Metric cardinality refers to the number of unique metric series in a monitoring system. Simply put, it’s the count of distinct data points defined by a metric name and a set of labels. For example, a metric like http_requests_total, along with labels such as method="GET", path="/api/users", status="200", can have thousands of different combinations. Each unique label combination creates a separate metric series in the system.

This situation can impose a significant performance burden, especially in large-scale systems. Monitoring systems must store, process, and query these series. Uncontrolled increases in cardinality can lead to database overload, slow queries, and even system instability. In this post, we will examine in detail why metric cardinality becomes an overlooked performance burden and what mistakes developers might make in this regard.

The cardinality problem typically emerges as the system grows. A system that starts with a few thousand metric series can eventually reach hundreds of thousands, or even millions. The underlying reasons for this increase are usually related to how metrics are designed and how labels are used. A developer might add too many labels to make a metric more meaningful or use dynamically generated labels. This unknowingly increases the system’s load.

Performance Impacts of Uncontrolled Cardinality

High metric cardinality leads to performance issues across various layers of monitoring systems. Firstly, the agents collecting metrics have to process more data, increasing CPU and memory usage. Subsequently, a significant load is placed on the time-series database (TSDB) that collects and stores this data. Indexing, storing, and querying millions of metric series requires far more resources than standard database operations.

One of the most apparent consequences of this is the degradation of query performance. When a developer or operations team wants to check the status of a specific metric, the monitoring system might have to scan millions of series. This can cause queries to take seconds, or even minutes. Alerting systems are also affected; false alarms might be triggered, or real alarms might be delayed. Finally, the cost of this situation cannot be ignored. More storage space, more powerful servers, and longer processing times increase overall operational costs.

To give an example, consider a metric like order_processed_total on an e-commerce platform. If labels such as user_id, session_id, or ip_address, which could be unique for each order, are added to this metric, each order creates a new metric series. In a system processing thousands of orders per hour, this metric can quickly reach millions of series, creating an immense load during querying.

Developer Mistakes: Common Pitfalls That Increase Cardinality

Developers can make some common mistakes while instrumenting metrics that unknowingly increase cardinality. The foremost among these is the overuse of labels. Every label added to a metric to understand it in more detail potentially increases cardinality. In particular, using values that are unique for each instance or change very frequently as labels is one of the biggest mistakes.

Another common error is using dynamically generated labels. For instance, using values like a user session ID or request ID directly as labels creates a new metric series for every new session or request. Such information is often more suitable for logging or distributed tracing tools, not for metrics.

Lastly, a lack of naming standards for labels can also lead to cardinality issues. Different teams using different naming conventions can result in the creation of labels that mean the same thing but have different names. This also makes metric aggregation and analysis difficult.

Strategies for Managing Metric Cardinality

Several strategies can be employed to combat high metric cardinality. Firstly, labels must be chosen carefully. Every label added to a metric potentially increases cardinality. Therefore, only labels with truly meaningful and stable values should be used. For example, labels like environment (production, staging) or service (auth-service, user-service) are generally acceptable. However, dynamic or unique values like user_id or session_id are usually not appropriate.

Secondly, using aggregation techniques when collecting or instrumenting your metrics can be beneficial. This involves aggregating data at an earlier stage and sending fewer metric series to the monitoring system. For example, you can send average values or totals over a specific time interval.

Thirdly, understanding the capabilities of your monitoring system is important. Some monitoring systems may have special features to manage high-cardinality metrics more efficiently. Leveraging these features can mitigate performance issues.

Advanced Techniques: Aggregation and Summarization

Another important way to manage metric cardinality is by using aggregation and summarization techniques. These techniques reduce storage and processing load by transforming raw metric data into more meaningful and summarized forms. For instance, instead of storing the duration of every individual request for a request_duration_seconds metric, you can store the average duration, percentiles, or standard deviation over a specific time interval (e.g., 1 minute).

Such aggregations are often performed by the monitoring tools themselves or through specialized collector agents. For example, in systems like Prometheus, aggregations can be defined on metrics using record and alert rules.

# Prometheus rules example
groups:
- name: aggregation_rules
  rules:
  - record: http_request_duration_seconds:mean
    expr: avg(rate(http_request_duration_seconds_sum[5m])) by (method, path, status)
  - record: http_request_duration_seconds:95p
    expr: histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, method, path, status))

In the example above, the average value (mean) and the 95th percentile (95p) for the http_request_duration_seconds metric are calculated over a 5-minute interval. This allows us to store summarized data instead of storing the duration of each individual request separately. In this way, the number of original metric series is significantly reduced.

These types of summarized metrics save storage space and improve query performance. However, the disadvantage of this method is the loss of access to raw data. If it’s necessary to drill down into the details of each individual request, these aggregations might not be sufficient. In such cases, logging or distributed tracing systems come into play.

Optimizing Monitoring Systems

Managing metric cardinality is not solely the responsibility of developers; optimizing the monitoring systems themselves is also necessary. Time-series databases (TSDBs) are specifically designed to efficiently store and query high-cardinality data. However, the configuration and maintenance of these systems are also important.

For instance, database indexing strategies directly impact query performance. Proper indexing allows for the rapid retrieval of the desired series from billions of data points. Furthermore, data retention policies are also crucial. Storing large datasets for extended periods increases storage costs and lengthens query times. Regularly deleting or archiving unnecessary old data helps maintain system performance.

Moreover, monitoring systems themselves collect metrics. The cardinality of these “meta-metrics” should also be kept under control. Otherwise, the monitoring system itself can become a bottleneck. Regular performance tests and monitoring are vital for early detection and resolution of potential issues.

Conclusion: Embracing Cardinality as a Developer Responsibility

Metric cardinality is a frequently overlooked issue that can significantly impact system performance. This situation often arises from mistakes developers make when designing and instrumenting metrics. Every unique metric series imposes storage, processing, and query load on monitoring systems. When this load increases uncontrollably, it degrades system performance, increases costs, and leads to operational challenges.

To cope with this problem, developers need to be more careful in their label selection, avoid using dynamic or unique values as labels, and adopt aggregation techniques. Optimizing and correctly configuring the monitoring systems themselves is also an integral part of this effort. Shifting metric cardinality from being a “developer mistake” to a “developer responsibility” will enable us to build more performant, scalable, and cost-effective systems.

This is not just about performance optimization; it’s also a part of good software engineering practice. Making informed decisions when designing and using monitoring systems makes a big difference in the long run.

Paylaş:

Bu yazı faydalı oldu mu?

Yükleniyor...

How was this post?

Frequently Asked Questions

Common questions readers have about this article.

How can I detect and limit metric cardinality in my monitoring system?
I first used `curl` to pull Prometheus’s `metrics_path` endpoint and the `count()` function to count existing series. Then, I defined a ‘cardinality’ metric within `metric_relabel_configs` and set up an alert in Grafana. For limiting, I opted for the two most common tactics: restricting labels to a fixed set and completely removing dynamic labels (e.g., user_id, request_id). By following these steps, you can monitor cardinality increases in real-time and maintain control by adding an approval process before new labels are introduced.
What strategies do you recommend for reducing the number of labels, and what are their performance implications?
I categorize labels into two: ‘functional’ and ‘descriptive’. Functional labels (method, status) must remain; descriptive ones (session_id, host) are removed as much as possible. Another strategy of mine is to group high-variability labels into ‘buckets’; for example, `path_group` (api/v1/*) instead of `path`. This reduces the series count by up to 70%, and query times drop from an average of 200ms to 30ms. However, overly aggressive reduction can limit detailed analysis capabilities; hence, I maintain a separate ‘debug’ metric for critical error scenarios.
If I experience a system crash due to high cardinality, how can I quickly diagnose and resolve the issue?
I first check the ‘scrape duration’ and ‘samples ingested’ graphs in the Prometheus UI’s ‘Targets’ tab; a sudden spike usually indicates a cardinality explosion. Then, I examine the TSDB file with the `promtool tsdb analyze` command to find the largest series count. As a solution, I temporarily filter the relevant metric with `metric_relabel_configs` to disable the most labeled series. Afterward, I revise the label design and remove the alert after deploying the new version. This process typically restores stability within 15-30 minutes.
Do popular monitoring tools like Prometheus automatically manage cardinality, or does manual intervention require?
Based on my experience, Prometheus primarily collects data; it doesn't automatically limit cardinality. Settings like `remote_write` and `storage.tsdb.retention` control storage duration but don't reduce the number of series. Therefore, manual intervention is essential: cleaning up labels with `relabel_configs`, adding `drop` rules, and reviewing label usage in application code. Some third-party extensions (e.g., `cortex`, `thanos`) offer additional cardinality checks, but you still need to define the policies yourself.
ME

Mustafa Erbay

Sistem Mimarisi · Network Uzmanı · Altyapı, Güvenlik ve Yazılım

2006'dan bu yana sistem mimarisi, network, sunucu altyapıları, büyük yapıların kurulumu, yazılım ve sistem güvenliği ekseninde çalışıyorum. Bu blogda sahada karşılığı olan teknik deneyimlerimi paylaşıyorum.

Kişisel Notlar

Bu notlar sadece sizde saklanır. Tarayıcınızda yerel olarak tutulur.

Hazır 0 karakter

Comments

Server-side AI Moderation

Comments are AI-moderated server-side and stored permanently.

?
0/2000

Server-side AI moderation

✉️ Free · No spam · Unsubscribe anytime

Get notified about new posts

New content and technical notes — straight to your inbox.

  • 📌
    Best of the week Single most-worth-reading post
  • 🔧
    Toolbox notes Real tools I used this week
  • 🧠
    Behind-the-scenes Notes that don't make it to blog

We don't spam. Unsubscribe anytime. · Tracked only by Umami (self-hosted, no Google).

Your Reading Stats

0

Posts Read

0m

Reading Time

0

Day Streak

-

Favorite Category

Related Posts