Skip to content

Commit 8b06220

Browse files
committed
doc: Improve metric doc to talk about cardinality limits
1 parent 4be1a32 commit 8b06220

File tree

1 file changed

+57
-1
lines changed

1 file changed

+57
-1
lines changed

docs/metrics.md

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,63 @@ The exported metrics would be:
560560
words, attributes used to create `Meter` or `Resource` attributes are not
561561
subject to this cap.
562562

563-
// TODO: Document how to pick cardinality limit.
563+
#### Cardinality Limits - How to Choose the Right Limit
564+
565+
Choosing the right cardinality limit is crucial for maintaining efficient memory
566+
usage and predictable performance in your metrics system. The optimal limit
567+
depends on your temporality choice and application characteristics.
568+
569+
Setting the limit incorrectly can have consequences:
570+
571+
* **Limit too high**: Due to the SDK's [memory preallocation](#memory-preallocation)
572+
strategy, excess memory will be allocated upfront and remain unused, leading to
573+
resource waste.
574+
* **Limit too low**: Measurements will be folded into the overflow bucket
575+
(`{"otel.metric.overflow": true}`), losing granular attribute information and
576+
making attribute-based queries unreliable.
577+
578+
Consider these guidelines when determining the appropriate limit:
579+
580+
**1. For Cumulative Temporality:**
581+
582+
* Cumulative metrics retain their state across export cycles, so the total
583+
cardinality equals the Cartesian product of all attribute combinations.
584+
* **Example:** Using the fruit sales example, if the metric has two attributes
585+
(`name` with 2 possible values and `color` with 3 possible values), the total
586+
cardinality is `2 × 3 = 6`. The cardinality limit can hence be set to 6.
587+
588+
**2. For Delta Temporality:**
589+
590+
* Delta temporality resets aggregations after each export cycle, enabling more
591+
flexible cardinality management based on actual usage patterns rather than
592+
theoretical maximums.
593+
* When all possible attribute combinations are known (eg: Fruit example from above), use the same calculation
594+
approach as cumulative temporality.
595+
* For dynamic scenarios where not all combinations appear in every export cycle,
596+
base the limit on expected total measurements within a single interval.
597+
* **Example 1:** With a 60-second export interval and 1,000 measurements per
598+
interval, set the cardinality limit to 1,000. Delta temporality allows the
599+
SDK to reset after each export, accommodating different attribute combinations
600+
across intervals without accumulating state.
601+
* **Example 2:** For web applications with known Request Per Second (RPS) rates,
602+
calculate the maximum measurements per interval: `RPS × Export Interval`. With
603+
500 RPS and a 60-second interval: `500 × 60 = 30,000` measurements per cycle.
604+
Set the cardinality limit to 30,000.
605+
* **High-Cardinality Attributes:** Delta temporality excels with attributes like
606+
`user_id` where not all values appear simultaneously. Base the limit on
607+
concurrent active users within an interval rather than total possible users.
608+
Using the same calculation (`500 RPS × 60 seconds = 30,000`), this
609+
accommodates realistic concurrent user activity.
610+
* **Export Interval Tuning:** Reducing export intervals lowers cardinality
611+
requirements. With 30-second intervals: `500 × 30 = 15,000` measurements,
612+
allowing a lower limit. However, balance this against increased serialization
613+
and network overhead from more frequent exports.
614+
615+
TODO: Add the memory cost incurred by each data points, so users
616+
can know the memory impact of setting a higher limits.
617+
618+
TODO: Add example of how query can be affected when overflow occurs,
619+
use [Aspire](https://github.com/dotnet/aspire/pull/7784) tool.
564620

565621
### Memory Preallocation
566622

0 commit comments

Comments
 (0)