Forward-deployed / Learning zone
System Designa standalone module
Lesson 07

Data infrastructure

TL;DR

Data infrastructure is the plumbing beneath every system in this track. Distributed message queues (Kafka) decouple producers from consumers, using append-only logs, partitioned topics, and consumer groups. This same pattern appears as a building block in metrics, ad aggregation, email, and a dozen other designs. Metrics monitoring combines pull-based collection (Prometheus) with time-series databases and down-sampling, to track 10M metrics without drowning in data. Ad click aggregation applies MapReduce and stream processing (Kappa architecture) to produce billing-accurate counts under exactly-once semantics. Distributed email handles 100K messages per second by separating SMTP processing from metadata storage, search indexing, and deliverability infrastructure. These four systems share a throughput-first, eventual-consistency design philosophy.

🎯 For the technical PM

Why it matters — Message queues, metrics pipelines, and event aggregation are invisible to users but determine whether your system can absorb traffic spikes, detect problems before users do, and produce accurate billing. They are the foundations your visible features rest on.

What it changes in your decisions — You design for throughput and acceptable delay (seconds to minutes), not for sub-millisecond latency. You accept eventual consistency in exchange for fault tolerance. You budget for data retention and down-sampling rather than keeping everything forever.

Ask your eng team — "What's our exactly-once guarantee for billing-critical events, and where in the pipeline can we lose or double-count?"

Risk if ignored — You double-bill advertisers because the click pipeline has at-least-once semantics, or you miss a production outage because your metrics pipeline silently dropped data during a traffic spike.


Distributed message queue

Scale and requirements

Core concepts

Distributed message queue - broker architecture
Producer 1order-service
Producer 2payment-service
Producer 3user-service
partition key ⟶ hash(key) % N
Broker Cluster (3 nodes)
topic: orders replication = 3
P0Broker 1
P0Broker 2
P0Broker 3
topic: payments replication = 3
P0Broker 1
P0Broker 2
P1Broker 3
pull / long poll ⟶ per partition
Group: analytics
C1
C2
Group: search
C1
C2
C3
Write-ahead log
Each partition is an append-only log on disk
Messages get sequential offset
Consumers track their position by offset
ISR replication
In-Sync Replicas = followers caught up to leader
Write acks: 0 (fire+forget), 1 (leader), all (ISR)
Leader fails → ISR member elected
Consumer offsets
Each group tracks offset per partition
At-least-once: commit after processing
Exactly-once: transactional produce + consume

Topics — named streams of messages (e.g., "user-events", "order-updates"). Each topic is divided into partitions.

Partitions — the unit of parallelism. Each partition is an ordered, append-only log. Messages within a partition are assigned a monotonically increasing offset. Ordering is guaranteed within a partition but not across partitions.

Consumer groups — a set of consumers that cooperate to consume a topic. Each partition is assigned to exactly one consumer in the group. This guarantees that each message is processed once per group, enabling parallel consumption.

WAL: the append-only log

Each partition is backed by a write-ahead log on disk:

The append-only log

Sequential writes to the active segment — the fastest disk I/O pattern

Old segments are immutable and can be served from page cache.

Segment 0
offsets 0–999
→
Segment 1
offsets 1000–1999
→
Segment 2 (active)
offsets 2000–2487
New messages append to the active segment only. The log is segmented into files (e.g., 1 GB each) for easier retention management.

Pull model vs. push model

Kafka uses a pull model: consumers request messages from brokers at their own pace.

Property Pull (Kafka) Push (traditional MQ)
Backpressure Consumer controls rate Broker must handle slow consumers
Batching Consumer batches reads Push granularity set by broker
Reprocessing Consumer resets offset Not possible without replay
Empty queue Consumer polls (long-poll to avoid busy-wait) No wasted requests

The pull model's killer feature is offset replay: a consumer can reset its offset to any point in the log and reprocess messages. This enables recovery from bugs, backfilling new features, and exactly-once semantics via idempotent reprocessing.

ISR replication

Each partition has one leader and N-1 followers. The In-Sync Replica set (ISR) is the set of followers that have caught up to the leader within a configurable lag threshold:

If a follower falls too far behind, it's removed from the ISR. If the leader fails, a new leader is elected from the ISR.

Consumer rebalancing

When consumers join or leave a group, partitions are rebalanced — reassigned across the remaining consumers. This is necessary but disruptive:

Delivery semantics

Guarantee How Cost
At-most-once Commit offset before processing Messages may be lost
At-least-once Commit offset after processing Messages may be duplicated
Exactly-once Idempotent producer + transactional consumer Highest complexity, ~10-20% throughput reduction

Exactly-once in Kafka requires:

  1. The producer assigns a sequence number to each message; the broker deduplicates.
  2. The consumer reads, processes, and commits the offset in a single atomic transaction (Kafka transactions).
  3. Downstream systems must be idempotent — if the consumer crashes and retries, the side effect must be safe to repeat.

Metrics monitoring

Scale and requirements

Collection: pull vs. push

Collection: pull vs. push

Most production systems use a hybrid of both

Prometheus pull for long-lived services, push gateways for batch jobs and lambdas.

Pull — Prometheus
Prometheus server
↓ HTTP scrape every 15–60s
Target /metrics ×N
Push — CloudWatch
Agents ×N
↓ push every 60s
Gateway / aggregator
↓
CloudWatch backend
Property Pull (Prometheus) Push (CloudWatch/StatsD)
Discovery Service discovery required Targets self-register
Firewall Scraper must reach targets Agents push outbound (easier)
Short-lived jobs Misses jobs that finish between scrapes Captures all events
Health detection Scrape failure = target down Must infer from missing data
Scale Single scraper bottleneck Horizontally scalable gateways

Most production systems use a hybrid: Prometheus pull for long-lived services, push gateways for batch jobs and lambdas.

Kafka as a buffer

Between collectors and the time-series database, a Kafka buffer absorbs traffic spikes:

Kafka as a buffer

Absorbs traffic spikes between collectors and the time-series database

Without the buffer, a spike overwhelms the write path exactly when you need metrics most.

Metric collectors
→
Kafka — metrics topic
→ TSDB writer pool → Time-series DB (InfluxDB, Thanos)
→ Alert evaluator
Kafka absorbs the burst. The TSDB writer pool processes at a sustainable rate.

Without the buffer, a traffic spike (deployment, incident, Black Friday) overwhelms the TSDB write path, causing data loss exactly when you need metrics most. Kafka absorbs the burst. The TSDB writer pool processes at a sustainable rate.

Time-series storage: down-sampling and encoding

Raw metrics at 10-second intervals generate enormous data volumes. Down-sampling reduces older data:

Age Resolution Aggregation
0-7 days 10 seconds Raw
7-30 days 1 minute Average, min, max
30-365 days 1 hour Average, min, max
1+ year 1 day Average, min, max

Double-delta encoding compresses time-series data efficiently:

Alert system

The alert system

Evaluation decoupled from notification via Kafka

Alert fatigue is the biggest operational risk — too many alerts train teams to ignore them.

Alert rules — YAML config
→
Rule evaluator — every 30–60s
→
Kafka — alert events
→
Notification channels
Email
PagerDuty
Slack

Alert rules are evaluated continuously (every 30-60 seconds):

Fired alerts go through Kafka (decoupling evaluation from notification) and fan out to configured channels. Alert fatigue is the biggest operational risk — too many alerts train teams to ignore them.


Ad click aggregation

Scale and requirements

MapReduce aggregation

The click stream flows through a MapReduce-style pipeline:

MapReduce aggregation

Billions of raw events become millions of counts, then final totals

The click stream flows through a MapReduce-style pipeline.

Raw click events — Kafka
→
Map — extract (ad_id, click)
→
Aggregate — count per ad_id per window
→
Reduce — merge partial counts
Aggregated store — real-time queries
OLAP warehouse — historical analytics

Map — extract the relevant fields from raw click events: ad_id, timestamp, user_id, device_id.

Aggregate — count clicks per ad_id per time window (e.g., per minute). This is the first reduction: billions of raw events become millions of (ad_id, window, count) tuples.

Reduce — merge partial counts from multiple aggregation nodes into final counts.

Kappa architecture

Traditional Lambda architecture maintains two pipelines: a batch layer for accuracy and a speed layer for latency. Kappa architecture simplifies this to a single stream-processing pipeline:

The tradeoff: replay for recomputation can be slow for large windows, but for click aggregation (daily/weekly windows), it's manageable.

Event time vs. processing time

Clicks don't arrive in order. A click at 14:00:03 might arrive at the server at 14:00:07 due to network delays. Which timestamp matters?

Watermarking handles late events:

Windowing strategies

Window type How it works Use case
Tumbling Fixed, non-overlapping intervals (e.g., every 1 minute) Per-minute click counts
Sliding Fixed size, advances by a slide interval (e.g., 5-min window, 1-min slide) Moving averages
Session Dynamic, grouped by activity gaps User session analysis

For billing, tumbling windows are the standard: each click falls into exactly one window, guaranteeing no double-counting.

Exactly-once for billing

Billing demands exactly-once semantics. The pipeline achieves this through:

  1. Kafka transactions — consume input, produce output, and commit offsets atomically.
  2. Idempotent writes — each aggregation result carries a unique (ad_id, window_start) key. Duplicate writes overwrite with the same value.
  3. Click deduplication — same user clicking the same ad within a short window (1 minute) is deduplicated using a Bloom filter or Redis set keyed on (ad_id, user_id, minute).

Star schema pre-aggregation

For analytics queries ("show me clicks by country, by device, by hour for campaign X"), raw events are pre-aggregated into a star schema:

Pre-aggregation reduces query-time computation: instead of scanning billions of raw events, the OLAP engine scans millions of pre-aggregated rows.


Distributed email service

Scale and requirements

Architecture overview

Architecture overview

Inbound, outbound, and storage as separate, decoupled paths

100,000 emails sent/received per second, 99.99% availability.

Inbound path
Inbound SMTP workers
→
Message queue
→
Email processor — spam, virus scan
→
Write to storage
Outbound path
API servers — compose, send
→
Message queue
→
Outbound SMTP workers
→
External mail servers
Storage layer
Metadata store — Cassandra-like
Blob store — attachments
Elasticsearch — search index
Client access: Web · Mobile · IMAP/POP3 server → API / metadata store

SMTP workers + message queues

Email processing is inherently asynchronous — the sender doesn't wait for the recipient to read it. Message queues decouple each stage:

Metadata storage: Cassandra-like store

Email metadata (sender, recipients, subject, timestamp, folder, read/unread status, labels) is stored in a wide-column store (Cassandra, HBase) partitioned by user_id:

Partition key Clustering key Data
user_id (folder, timestamp DESC) subject, from, snippet, is_read, labels

This partitioning guarantees:

Attachments are stored separately in blob storage (S3 or equivalent), with only a reference (blob_id, size, content_type) in the metadata row.

Full-text search across email bodies, subjects, and metadata is powered by Elasticsearch:

Deliverability: SPF, DKIM, and IP warm-up

Sending email is easy. Getting it delivered to inboxes (not spam folders) is hard:

SPF (Sender Policy Framework): a DNS TXT record listing the IP addresses authorized to send email for a domain. Receiving servers check the sending IP against this list.

DKIM (DomainKeys Identified Mail): the sending server signs each email with a private key. The receiving server verifies the signature using a public key published in DNS. This proves the email wasn't tampered with in transit.

IP warm-up: a new sending IP has no reputation. Sending a million emails from a cold IP triggers spam filters. The warm-up process:

  1. Start with 50-100 emails/day to engaged recipients.
  2. Gradually increase volume over 4-6 weeks.
  3. Monitor bounce rates, spam complaints, and inbox placement.
  4. Maintain consistent volume — sudden spikes damage reputation.

DMARC ties SPF and DKIM together with a policy: "if an email fails both SPF and DKIM, reject it / quarantine it / let it through." This protects the domain from spoofing.


Failure modes

Practitioner checklist