@@ -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