Design a Metrics Collection System
AmperitySoftware Engineer · Technical ScreenLast updated
Design an end-to-end distributed metrics collection and monitoring pipeline capable of ingesting millions of data points per second, handling label cardinality risks, and supporting low-latency time-series queries.
Scenario
Your organization operates thousands of services and batch processing pipelines across distributed clusters. To support real-time observability, alerting, and internal customer SLAs, you need to design a centralized metrics collection and query service.
The system must ingest metrics from applications and host daemons, aggregate time-series data, protect against cardinality explosions, store rollups efficiently, and serve queries for operational dashboards.
Requirements
Functional Requirements
- Metric Types: Support counters, gauges, and histograms/timers.
- Ingestion: Provide APIs or client SDKs for services to emit metrics with arbitrary key-value dimensions (labels).
- Cardinality Management: Prevent runaway dimension explosions (e.g., accidental inclusion of unique UUIDs or user IDs in labels).
- Query Interface: Support aggregation queries across dimensions (e.g.,
sum(rate(http_requests_total[5m])) by (service)), time-range windowing, and percentile computations (e.g., p95, p99 latency). - Retention and Downsampling: Maintain raw granular metrics for short periods, and roll up older data for long-term trend analysis.
- Self-Monitoring: Alert when ingestion falls behind or when metric drops occur.
Non-Functional Requirements
- High Availability & Durability: Write path must handle bursts gracefully without dropping critical metrics; ingestion must remain available even if the query layer degrades.
- Low Latency Queries: Operational dashboards should load typical queries in under 500 ms.
- Scalability: Scale horizontally as host counts and service instances increase.
Scale Assumptions
- Throughput: 2,000,000 metric data points per second at peak.
- Active Series: Approximately 10,000,000 active unique time series at any given time.
- Retention:
- Raw data (10-second resolution): 7 days.
- 1-minute downsampled: 30 days.
- 1-hour downsampled: 1 year.
Key Areas to Cover
- Data Model & Ingestion Architecture: Push vs. pull model, client buffering, and gateway/queue design (e.g., Kafka/Pulsar).
- Cardinality & Validation: How and where to detect and bound metric cardinality.
- Storage Tiering: In-memory index, time-series storage engine (TSDB/LSM trees), and long-term object storage rollups.
- Query Engine & Aggregations: How to serve real-time and historical queries without scanning massive unindexed datasets.
- Fault Tolerance & Monitoring: Backpressure handling, dead-lettering, and self-health tracking.
Hints
Hint 1
Consider the trade-offs between push and pull collection models regarding network topology, service discovery, and client-side buffering.
Hint 2
Address metric cardinality at the edge or ingestion gateway using an LRU cache or bloom filters before data enters distributed storage.
Hint 3
Separate storage tiers for raw ingestion and downsampled rollups to keep dashboard queries fast over large time ranges.
Follow-up questions
- How would you compute and store latency percentiles across distributed nodes without merging raw samples (e.g., using DDSketch or t-digest)?
- If the ingestion message bus experiences severe backpressure, what load-shedding or throttling strategies protect core platform metrics over non-critical ones?
- How does your system handle out-of-order or late-arriving metrics caused by client network partitions or clock skew?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.