Bird
Raised Fist0

Metrics Collection System Design - Push vs Pull Model Trade-offs

HLDmediumInterview freq: common
Choose your preparation mode4 modes available
🏗️
Metrics Collection System Design - Push vs Pull Model Trade-offs
Designing scalable metrics collection systems: evaluating push and pull ingestion models at scale
mediumMonitoring and ObservabilityFreq: common
Prerequisites:System Design FundamentalsCAP TheoremDistributed Systems BasicsMonitoring and Observability Concepts
⚙️
Functional Requirements
  • Ingest metrics data from millions to billions of clients reliably
  • Support both push and pull ingestion models for metrics collection
  • Store time-series metrics efficiently with retention policies
  • Provide low-latency querying for recent metrics and aggregated views
  • Support multi-tenant isolation and authentication for clients
  • Allow flexible metric schemas and labels/tags for filtering
📊
Non-Functional Requirements
  • Handle ingestion rate of up to 2 billion metrics per day
  • Ensure 99.99% availability for ingestion and query APIs
  • Support 100ms P99 latency for recent metrics queries
  • Data retention configurable up to 30 days with automatic expiry
  • Scale horizontally to handle 10x growth without downtime
❓
Clarifying Questions to Ask
  • What is the expected cardinality of unique metrics and labels?
  • Are metrics pushed by clients or scraped by the system, or both?
  • What is the SLA for data freshness and query latency?
  • What authentication and multi-tenancy requirements exist?
  • Is data loss acceptable during transient failures?
  • What is the expected query pattern: recent data vs historical aggregates?
Out of Scope
✗ Designing alerting or anomaly detection on metrics
✗ Long-term archival storage beyond 30 days
✗ Detailed visualization or dashboarding components
✗ Client-side SDK implementation details
📌
Assumptions
  • 2 billion metrics ingested per day
  • Each metric message size ~100 bytes
  • Average 40 metrics emitted per user per day
  • Retention period of 30 days
⚡
QPS Calculation
write qps2B metrics / 86400 seconds ≈ 23148 writes/sec
peak write qpsAssuming 5x peak factor → 23148 × 5 = 115740 writes/sec
read qpsAssuming 10% of write QPS for queries → 115740 × 0.1 = 11574 reads/sec
💾
Storage Estimate
daily storage2B × 100 bytes = 200 GB/day
retention storage200 GB/day × 30 days = 6 TB
with replication6 TB × 3 replicas = 18 TB total storage
🖥️
Server Estimate
ingestion serversAssuming each server handles 10K writes/sec → 115740 / 10K ≈ 12 servers
storage nodesAssuming each node stores 2 TB with replication → 18 TB / 2 TB = 9 nodes
🏗️
Architecture Diagram
Architecture Diagram
          +-------------+
          |  Metrics    |
          |  Clients    |
          +------+------+
                 | Push or Pull
                 v
          +------+-------+
          |  Ingestion   |
          |  Layer       |
          +------+-------+
                 |
                 v
          +------+-------+
          |  Message     |
          |  Broker      |
          |  (Kafka)     |
          +------+-------+
                 |
                 v
          +------+-------+
          |  Processing  |
          |  Layer       |
          | (Flink/Beam) |
          +------+-------+
                 |
                 v
          +------+-------+
          |  Storage     |
          |  (Cassandra) |
          +------+-------+
                 |
                 v
          +------+-------+
          |  Query API   |
          |  (gRPC/REST) |
          +--------------+
🧩
Components
Metrics Clients
Emit metrics data either by pushing to ingestion endpoints or exposing metrics for scraping
Why thisSupports both push (Prometheus Pushgateway) and pull (Prometheus scraping) models to cover diverse client capabilities
Why notRestricting to only push or only pull limits compatibility with existing monitoring ecosystems
Ingestion Layer
Receives metrics data from clients, validates, and forwards to message broker
Why thisStateless HTTP/gRPC servers horizontally scalable to handle 115K peak writes/sec with load balancing
Why notDirect writes to storage rejected due to inability to buffer spikes and lack of decoupling
Message Broker (Apache Kafka)
Durably buffers incoming metrics streams, decouples ingestion from processing, and supports replay
Why thisKafka scales to millions of messages/sec with partitioning and replication, ensuring durability and ordering
Why notRabbitMQ lacks Kafka's throughput and partitioning scalability at 100K+ writes/sec
Processing Layer (Apache Flink/Beam)
Aggregates, transforms, and enriches metrics streams before storage
Why thisStream processing frameworks provide exactly-once semantics and windowed aggregations needed for metrics
Why notBatch processing (e.g., Hadoop) introduces unacceptable latency for near real-time metrics
Storage (Apache Cassandra)
Stores time-series metrics data with high write throughput and horizontal scalability
Why thisCassandra's wide-column model supports time-series data with tunable consistency and linear write scalability
Why notPostgreSQL rejected due to complex manual sharding and limited write throughput at 115K writes/sec
Query API
Serves low-latency queries for recent and aggregated metrics to clients and dashboards
Why thisgRPC/REST API layer with caching (e.g., Redis) to meet 100ms P99 latency SLA
Why notDirect DB queries rejected due to high latency and load on storage nodes
🔄
Data Flow
1
Metrics Clients → Ingestion Layer
Clients push metrics via HTTP/gRPC or expose endpoints for scraping
Supports both push and pull ingestion models
2
Ingestion Layer → Kafka Broker
Ingestion servers validate and publish metrics to Kafka topics
Decouples ingestion from processing, buffers spikes
3
Kafka Broker → Processing Layer
Stream processing jobs consume metrics, perform aggregation/enrichment
Enables windowed computations and data transformations
4
Processing Layer → Cassandra Storage
Processed metrics are written to Cassandra with time-series schema
Supports high write throughput and retention
5
Clients/Dashboards → Query API
Clients query recent or aggregated metrics via API
API layer uses caching to meet latency SLAs
6
Query API → Cassandra Storage
Query API fetches data from Cassandra to serve client queries
Optimized queries with caching and indexing to meet latency requirements
🗄️
metrics_data
PK: metric_name, tenant_id
metric_name texttenant_id uuidtimestamp timestamplabels map<text,text>value double
Stores raw time-series metrics data
🗄️
metrics_aggregates
PK: metric_name, tenant_id, aggregation_window
metric_name texttenant_id uuidaggregation_window textwindow_start timestampvalue double
Stores pre-aggregated metrics for fast queries
🔌
POST /metrics/push
Request
{
  "tenant_id": "uuid",
  "metrics": "array of {metric_name, labels, value, timestamp}"
}
Response
{
  "status": "success or error",
  "message": "optional error message"
}
Supports push ingestion from clients
🔌
GET /metrics/query
Request
{
  "tenant_id": "uuid",
  "metric_name": "string",
  "start_time": "timestamp",
  "end_time": "timestamp",
  "labels_filter": "optional map<string,string>",
  "aggregation": "optional string (e.g., sum, avg)"
}
Response
{
  "data": "time-series points or aggregated values"
}
Query recent or aggregated metrics with label filtering
🔌
GET /metrics/metadata
Request
{
  "tenant_id": "uuid"
}
Response
{
  "metrics": "list of available metric names and label keys"
}
Fetch metadata for client UI or validation

Practice

(1/5)
1. A Q&A platform needs to handle 1 million new questions and answers per day, ensuring that user feeds update with minimal latency and high availability. Which component is best suited to decouple write-heavy ingestion from real-time feed generation?
easy
A. Use a relational database with immediate synchronous writes for feed updates
B. Use a distributed message queue like Kafka to buffer writes before processing
C. Use a cache-only system like Redis without persistence for feed data
D. Use direct HTTP calls from write API to feed service for immediate consistency

Solution

  1. Step 1: Identify ingestion and feed update decoupling

    Direct synchronous writes (A, D) block user requests and reduce availability under high load. Redis without persistence (C) risks data loss on failure.
  2. Step 2: Evaluate Kafka's role

    Kafka buffers high write throughput, supports partitioning for scalability, and decouples ingestion from feed generation, ensuring durability and replayability.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Kafka buffers high write load, enabling asynchronous feed updates [check]
Hint: Buffer writes with durable queue to decouple ingestion [check]
Common Mistakes:
2. If the Kafka cluster is unavailable, what exactly breaks in the log aggregation pipeline?
medium
A. Logs are lost immediately as producers drop messages without retry
B. Log processors continue processing old logs but cannot enrich new logs
C. The storage layer stops accepting writes but ingestion continues
D. Log producers block on send calls, causing backpressure and delayed ingestion

Solution

  1. Step 1: Identify Kafka's role

    Kafka buffers logs between producers and processors, enabling decoupling.
  2. Step 2: Trace failure impact

    If Kafka is down, producers may retry or block, but processors cannot consume new logs, halting enrichment.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Kafka down -> processors stall on new logs, old logs processed [check]
Hint: Kafka outage stalls processors, not immediate producer loss [check]
Common Mistakes:
3. For a mobile app requiring real-time notifications at 10x scale, which architecture is better and why?
medium
A. Use WebSockets with a scalable connection broker to handle mobile client limitations
B. Use gRPC streaming for persistent connections to push notifications
C. Use long polling HTTP requests to simulate real-time updates
D. Use periodic polling every 5 seconds to reduce server load

Solution

  1. Step 1: Evaluate mobile client support

    gRPC streaming (Use gRPC streaming for persistent connections to push notifications) is efficient but poorly supported on many mobile platforms, causing compatibility issues.
  2. Step 2: WebSockets with connection broker

    WebSockets (Use WebSockets with a scalable connection broker to handle mobile client limitations) are widely supported on mobile and, with a scalable broker, can handle millions of connections efficiently.
  3. Step 3: Polling drawbacks

    Long polling (Use long polling HTTP requests to simulate real-time updates) and periodic polling (Use periodic polling every 5 seconds to reduce server load) increase latency and server load, unsuitable for real-time at scale.
  4. Final Answer:

    Option A -> Option A
  5. Quick Check:

    WebSockets + broker -> scalable, mobile-friendly real-time [check]
Hint: WebSockets scale better on mobile than gRPC streaming [OK]
Common Mistakes:
4. At 10x scale, which component in the ML data infrastructure is most likely to become the bottleneck first, and why?
hard
A. The feature store's online serving layer, because in-memory caches cannot scale linearly with data volume
B. The training pipeline's batch processing cluster, because compute resources scale easily with more nodes
C. The feature metadata registry, because relational databases handle metadata efficiently at scale
D. The ingestion Kafka cluster, because partition count limits throughput and rebalancing causes downtime

Solution

  1. Step 1: Analyze scaling challenges per component

    Feature store caches can be sharded; batch clusters scale horizontally; metadata registries are smaller and less frequently accessed.
  2. Step 2: Identify Kafka bottleneck

    Kafka throughput depends on partition count, which is hard to increase dynamically. Rebalancing partitions at scale causes downtime and latency spikes, making Kafka ingestion the first bottleneck.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Kafka partition limits and rebalancing cause ingestion bottlenecks [check]
Hint: Kafka partitions limit throughput; rebalancing causes downtime [check]
Common Mistakes:
5. At 10x traffic scale, which component is most likely to fail first in a system without rate limiting, and why?
hard
A. The backend cache, because its memory fills up causing evictions and cache misses
B. The database, due to increased write load causing slow queries and deadlocks
C. The network load balancer, as it cannot handle the increased number of TCP connections
D. The API servers, because they maintain stateful connections that cannot be easily sharded

Solution

  1. Step 1: Analyze component scalability at 10x traffic

    Databases (A) and caches (D) can be scaled horizontally or sharded; load balancers (C) can be scaled or replaced with L4/L7 solutions.
  2. Step 2: Identify API servers as bottleneck

    API servers maintaining stateful connections (e.g., WebSockets) are hard to shard or move; connection limits cause saturation and failure first.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Stateful API servers hit connection limits first at scale [check]
Hint: Stateful API servers fail first due to connection limits [check]
Common Mistakes:
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard