System Design Problem

Design a Real-Time Bidding System (Ad Tech)

Commonly Asked By:GoogleTradeDeskMetaYahoo

Interview Setup

Interview Prompt

Design a real-time bidding (RTB) ad exchange processing 10M auctions/sec with a 50ms bid deadline, fanning out to 5-20 DSPs per auction and logging 864 TB/day of auction data.

Clarifying Questions (ask before designing)

QuestionWhy it matters
Hard 50ms deadline or best-effort with timeout?
  • Page load blocks on ad slot
  • every ms of latency costs revenue. 50ms is industry standard.
First-price or second-price auction?
  • Industry shifted to first-price (pay your bid)
  • second-price simpler but gameable.
How do DSPs connect: HTTP OpenRTB or dedicated connections?With 100M outbound bid requests per second, connection pooling and pre-warming are critical.
Budget pacing: spend evenly across the day or allow bursts?A $10,000 daily budget at 10M auctions/sec requires per-millisecond spend tracking.

Scope

In scope

  • 50ms server-side bid deadline (industry standard, while client-side page rendering adds additional time)
  • Bid request/response protocol (OpenRTB)
  • Budget pacing
  • Frequency capping
  • Auction types (first-price vs second-price)
  • Capacity estimation with shown math

Out of scope (state explicitly)

  • Detailed frontend/UI pixel implementation
  • Org structure, staffing, and hiring plan

Functional Requirements

Start by confirming the 50ms server-side auction deadline and OpenRTB fan-out scope. Inquire about first-price vs second-price auction mechanics, budget enforcement, and frequency capping requirements.

  • Real-time auction within 50ms server-side when a user loads a webpage containing ad slots using OpenRTB fan-out and auction resolution
  • Send bid requests to multiple Demand-Side Platforms (DSPs) simultaneously
  • Each DSP evaluates the user context and returns a bid price alongside an ad creative
  • Select the winning bidder, render the ad creative, and record the impression event
  • Support multiple ad formats including display banners, outstream video, native placements, and rich media
  • Frequency capping to restrict how many times an individual user sees the same advertisement
  • Budget management to halt bidding immediately when an advertiser budget is exhausted
  • Win notifications to alert the winning DSP for spend accounting
  • Click and conversion tracking with attribution modeling
  • Fraud detection to filter bot traffic, invalid clicks, and ad stacking schemes

Non-Functional Requirements

Interviewers focus primarily on the 50ms p99 auction deadline and sustaining 10M+ auctions/sec throughput. Every millisecond on the critical path is strictly budgeted, so Kafka logging and billing reconciliation must remain decoupled from the synchronous response path.

  • Ultra-Low Latency: Server-side auction path completes in < 50ms p99, while the total page-to-ad-render budget is approximately 100ms including client rendering
  • Massive Throughput: 10M+ auctions per second globally, translating to 100M+ outbound bid requests per second
  • High Availability: 99.99% uptime because any edge downtime directly discards publisher monetization
  • Consistency: Budget enforcement must prevent overspending, targeting within a 2% to 5% contractual tolerance window
  • Geographic Distribution: Edge clusters deployed in every major metropolitan market near DSP data centers
  • Auditability: Complete append-only audit trail for every submitted bid, auction outcome, and impression event

Capacity Estimations

Calculate capacity constraints before sizing edge clusters. Auctions per second and DSP fan-out counts determine the sizing of persistent HTTP/2 connection pools, while the strict 30ms DSP timeout drives no-bid fallback rates.

MetricCalculationValue
Auctions / secDerived from daily volume ÷ 86400 (+ peak factor)10M
DSPs per auctionGiven5 to 20
Bid requests / sec (outbound)Derived from daily volume ÷ 86400 (+ peak factor)100M
Bid response time SLAGiven< 50ms
Win notifications / secDerived from daily volume ÷ 86400 (+ peak factor)5M
Impressions / day (peak illustrative)5M wins/sec peak x 3,600 x 8 active hours~144B
Auction log size / day864B auctions x ~1 KB~864 TB/day

Architecture Diagram

In the interview room, establish the 50ms hard deadline first by budgeting Redis lookup, DSP fan-out, auction resolution, and creative markup delivery before the user scrolls past the ad unit.

The architecture divides cleanly into a synchronous low-latency auction path and an asynchronous logging and billing pipeline. When a publisher page triggers an ad slot, the Supply-Side Platform (SSP) edge enriches user context from a local Redis cache cluster, fans out an OpenRTB bid request to 5 to 20 DSPs in parallel over pre-warmed HTTP/2 connections, executes a first-price auction within a hard 50ms deadline, and returns the winning creative markup. Completed auction outcomes stream asynchronously to a Kafka event log for billing and fraud analysis, ensuring the user response path never blocks on storage durability.

Loading...

Component Deep Dives

This section explores each major component on the auction path, starting with the auction engine mechanics, proceeding to the strict latency budget breakdown, and examining how distributed edge nodes pace advertiser budgets.

Auction Engine Mechanics

First-price auctions are the industry standard since 2019, making bid shading the primary operational challenge for DSP algorithms.

Second-Price Auction: Given bids of $3.10, $2.50, and $1.80, the highest bidder at $3.10 wins and pays $2.51 (the second-highest bid plus one cent). This pricing rule encourages bidders to submit their true valuation without fear of overpaying.

First-Price Auction: The highest bidder wins and pays their exact bid price ($3.10). DSPs rely on real-time machine learning models to shade their bids down to the minimum price likely to clear the auction, balancing win probability against margin.

Latency Budget Breakdown

Examine the millisecond budget line by line. The DSP processing timeout at 30ms represents the largest single slice of time and directly dictates the no-bid fallback rate.

Total server-side budget: 50ms p99 (hard DSP timeout)
  Ad request to SSP edge:       5ms
  User data lookup (Redis):     2ms
  Bid request to DSPs:          5ms (parallel HTTP/2, pre-warmed)
  DSP processing + response:   30ms (timeout: no-bid if exceeded)
  Auction logic + winner pick:  1ms
  Ad markup to publisher:       5ms
  Win notification + Kafka log: async (not on critical path)
  Client ad render:            ~50ms additional (browser)

Budget Enforcement at Scale

Enforcing advertiser budgets across 10M auctions per second requires a tiered architecture with local edge slicing and asynchronous global reconciliation, balancing latency against an agreed overspend tolerance.

Tier 1 (hot path, Redis):
  Each edge server receives an allocated "budget slice" from the central campaign pool.
  Check local slice only, avoiding cross-server network coordination.
  When slice is exhausted, request a fresh slice from central store.

Tier 2 (near real-time, Flink):
  Aggregate all win notifications per campaign across Kafka partitions.
  If spend approaches limit, broadcast a "stop bidding" signal to edge caches.
  Processing latency: ~5 seconds behind real-time.

Tier 3 (daily reconciliation):
  ClickHouse aggregation reconciles edge logs against DSP billing reports.

Overspend tolerance: ~2% to 5% (industry standard, contractually agreed)

Event Bus Design (Kafka)

High-throughput event streaming decouples the time-critical auction response loop from offline billing, conversion attribution, and model retraining pipelines.

Topic: auction-logs
  Partitions: 512 (partition by auction_id)
  Retention: 7 days (~864 TB/day at 10M auctions/sec, tiered to S3 after 24h)
  Producers: Ad Request Handler after auction completes (< 50ms path)
  Payload: bid requests sent, DSP responses, winner, clearing price (second-price or first-price)
  Consumers: billing settlement, fraud detection, ML bid-shading retraining

Topic: impression-events
  Partitions: 256 (partition by user_id)
  Events: ad_served, viewable_impression (MRC standard)
  Consumers: frequency-cap updater (Redis), attribution pipeline

Topic: win-notifications
  Partitions: 128 (partition by dsp_id)
  Consumers: DSP billing adapters, budget decrement workers

Auction path: fan-out to DSPs (50ms timeout) -> collect bids -> return creative to publisher
  Logging to Kafka is asynchronous fire-and-forget, so the auction response never waits on broker acknowledgment.

API Design

OpenRTB Bid Request

The SSP edge dispatches this standardized payload in parallel to all eligible DSPs matching the inventory targeting criteria.

JSON
POST /bid
{
  "id": "auction-uuid-123",
  "imp": [{
    "id": "1", "banner": {"w": 300, "h": 250}, "bidfloor": 0.50
  }],
  "site": { "domain": "example.com" },
  "user": { "id": "user-cookie-hash", "geo": {"country": "US"} },
  "device": { "ua": "Mozilla/5.0...", "ip": "203.0.113.42" },
  "tmax": 50
}

Bid Response

The DSP returns its seat bid, indicating the price offered, creative markup, and win notice tracking URL.

JSON
{
  "seatbid": [{ "bid": [{
    "id": "bid-456", "impid": "1", "price": 3.10,
    "adm": "<div>...ad creative HTML...</div>",
    "nurl": "https://dsp.example.com/win?price=${AUCTION_PRICE}"
  }] }]
}

Internal Operational Endpoints

Internal services query campaign budget status, trigger manual or automated campaign pauses, and fetch real-time spend analytics.

HTTP
GET  /api/campaigns/{id}/budget
POST /api/campaigns/{id}/pause
GET  /api/analytics/spend?campaign={id}&date={date}

Common Error Responses

JSON
400 Bad Request: invalid input, missing required fields, or malformed JSON payload
401 Unauthorized: missing or invalid authentication token or API key
403 Forbidden: authenticated caller lacks required permissions for this resource
404 Not Found: requested resource ID does not exist
409 Conflict: duplicate write or version conflict, retry with a unique idempotency key
422 Unprocessable Entity: syntactically valid request failed semantic business validation
429 Too Many Requests: rate limit quota exceeded, client should honor Retry-After header
500 Internal Error: unexpected server failure, retry safely with an idempotency key
503 Service Unavailable: downstream dependency is unavailable or overloaded, retry with exponential backoff

Data Model

Redis Key-Value Schema (Hot Path)

Hot-path lookups for user profile segments, frequency capping counters, and regional budget slice tracking reside entirely in an in-memory Redis cluster to ensure sub-millisecond access.

REDIS
# User profile
HSET user:{cookie_hash} segments "sports,tech" age_range "25-34"
EXPIRE user:{cookie_hash} 2592000

# Frequency cap
INCR freq:{user_id}:{campaign_id}:{date}
EXPIRE freq:{user_id}:{campaign_id}:{date} 86400
# Check: IF counter < max_freq THEN allow bid ELSE suppress

# Budget tracking
HSET budget:{campaign_id} daily_spent 4523.50 daily_limit 5000.00
# Check: IF daily_spent >= daily_limit THEN suppress bid

ClickHouse Analytics Schema

ClickHouse ingests auction outcomes from Kafka, supporting column-oriented analytical rollups for spend pacing, fill rate monitoring, and attribution.

SQL
CREATE TABLE auction_logs (
    auction_id UUID,
    timestamp DateTime,
    publisher_id UInt64,
    ad_slot_size String,
    user_id String,
    country LowCardinality(String),
    device_type LowCardinality(String),
    num_bids UInt8,
    winning_dsp LowCardinality(String),
    winning_price Float64,
    second_price Float64,
    floor_price Float64,
    campaign_id UInt64,
    is_click UInt8,
    is_conversion UInt8
) ENGINE = MergeTree()
PARTITION BY toYYYYMMDD(timestamp)
ORDER BY (publisher_id, timestamp);

Fault Tolerance

TechniqueApplication
DSP timeout (50ms)If a DSP does not respond within 50ms, it is excluded from the auction.
No-bid fallbackServe a house ad or collapse to an empty slot.
Kafka RF=3Auction logs and impression events survive broker failures through replication.
Redis ClusterUser profiles and budget counters remain available despite node failures.
Edge redundancyDeploy multiple edge servers per region with load balancer health checks.
Budget reconciliationDaily background reconciliation catches any tracking drift between edge slices and central totals.

DSP Failure Handling

If a DSP consistently times out or returns HTTP 5xx responses, an edge circuit breaker opens and stops dispatching bid requests for 60 seconds before sending test probe traffic.

Fraud Detection Pipeline

Fraud mitigation operates across three distinct time horizons to safeguard advertiser budgets without violating latency constraints:

Real-time (< 5ms): Synchronous IP blocklists, known bot user-agent signatures, and invalid traffic (IVT) heuristic scores filter fraudulent bid opportunities before fan-out.

Near real-time (Flink): Stream processing detects click-through rate anomalies, sub-100ms click timing patterns indicating automated bots, and rapid geographic jumps.

Batch (daily): Offline analytical pipelines discover distributed click farms and compute publisher traffic quality scores to adjust inventory floor prices.

Additional Considerations

How a DSP Bidder Operates (< 50ms)

When the DSP bidder receives an OpenRTB request from the exchange, it executes the following sequential evaluation pipeline before returning its bid:

1. Cookie sync: map SSP user ID to DSP internal user profile (2ms)
2. Campaign matching: evaluate which active campaigns target this user and placement (5ms)
3. Bid price prediction: run ML inference models to calculate click probability and optimal bid (10ms)
4. Budget check: verify campaign has sufficient remaining spend allowance (2ms)
5. Frequency check: confirm user has not exceeded the campaign impression threshold (2ms)
6. Select creative: pick the highest-performing creative asset for the user and slot format (2ms)
7. Return bid response: serialize JSON payload and return over persistent connection (1ms)

Interview Walkthrough

  • 25-minute cut

    Focus on the core 50ms latency breakdown, parallel fan-out mechanics, and budget slicing.

    • 50ms hard deadline: allocate strict latency budgets across each hop (8 min)
    • Fan-out to 5 to 20 DSPs in parallel over pre-warmed HTTP/2 connections (9 min)
    • No-bid is a valid response: enforce hard timeouts rather than waiting indefinitely (8 min)
  • State the hard constraint first: 50ms server-side auction p99, where every millisecond on the critical path must be budgeted across Redis lookup, fan-out, auction resolution, and markup generation.
  • Walk through the OpenRTB flow: the SSP receives an ad request, fans out in parallel to eligible DSPs with a 30ms timeout each, collects responses, runs a first-price auction, and returns the ad markup within 50ms on the server.
  • Detail the Redis hot path: user segments, frequency caps, and budget checks execute in sub-millisecond latencies with zero database calls during the auction window.
  • Explain budget slicing across edge servers: divide daily budgets locally every 30 seconds to avoid coordination races without requiring per-bid network calls.
  • Apply circuit breakers on consistently timing-out DSPs by skipping them and reallocating the timeout budget to responsive bidders.
  • Contrast second-price against first-price auction mechanics and explain why bid-shading machine learning models are critical under first-price rules.
  • Highlight the common pitfall of centralized budget checks per bid at auction time, which introduces network latency and creates a severe coordination bottleneck at millions of auctions per second.

Engineering Trade-offs

Ad exchanges continuously balance publisher revenue maximization against tight client latency budgets, as detailed in the following trade-offs.

Second-Price Auction: How the Winner Is Selected

Second-price (Vickrey) auctions encourage truthful bidding, whereas modern first-price auctions demand sophisticated bid-shading algorithms from DSPs.

Bid request goes to 5 DSPs. Responses:
  DSP A: $3.20, DSP B: $2.80, DSP C: no-bid, DSP D: $4.10, DSP E: $1.50

Second-price auction:
  Winner: DSP D ($4.10)
  Price paid: MAX(second_highest, floor_price) + $0.01 = MAX($3.20, $1.00) + $0.01 = $3.21

  DSP D bid $4.10 but pays only $3.21
  Result: DSPs are incentivized to bid their true valuation (Vickrey auction)

Industry transition:
  Major exchanges switched to first-price in 2019
  Under first-price, winner pays their exact bid ($4.10), prompting DSPs to employ bid-shading ML models.

Budget Pacing: Preventing Exhaustion Before Noon

Without active pacing, high-converting morning traffic consumes the entire campaign allowance, leaving evening inventory unmonetized.

Target hourly spend = daily_budget / 24

Pacing algorithm:
  pacing_factor = target_spend_so_far / actual_spend_so_far
  If pacing_factor > 1.2: underspending -> participate in MORE auctions
  If pacing_factor < 0.8: overspending -> participate in FEWER auctions

Implementation: probabilistic throttling
  participation_rate = min(1.0, pacing_factor)
  For each eligible auction: IF random() < participation_rate THEN bid ELSE pass

Business impact: on a $100M annual spend, a 5% pacing inefficiency wastes $5M in sub-optimal ad placements.

Budget Race Condition: Budget Slicing Across Edge Clusters

Centralized locks cannot sustain 10M queries per second. Slicing budgets regionally eliminates cross-edge coordination during auctions.

Problem: Campaign budget = $5,000/day across 10 regional edge servers
  Without coordination: all 10 edges see $5,000 allowance, risking 10x overspend

Budget slicing solution:
  Divide budget across edge servers proportionally every 30 seconds.
  Each edge manages its own slice locally in in-memory Redis.
  No network round-trip for budget checks yields sub-millisecond execution.
  No inter-edge locks eliminates distributed lock contention.

Overspend risk: bounded by the 30-second reconciliation window.
  Mitigation: conservative slicing (allocate 90% of allowance, keep 10% central reserve).
  Observed overspend in production remains below 0.1%.

💬Review

Help Us Improve

How helpful was this walkthrough?

Click a star to rate. We actively use this feedback to refine and update our system design content.

Placeholder
Optional but highly appreciated!

Discussion

Share your thoughts, ask questions, or help others.

Loading comments...