Low Level Design: Surge Pricing Service

What Is a Surge Pricing Service?

Surge pricing (dynamic pricing) automatically adjusts ride fares based on real-time supply and demand imbalances. When demand significantly outpaces available drivers in a zone, fares increase to attract more drivers and moderate inbound requests. The service must compute multipliers quickly, apply them consistently across the platform, and communicate them clearly to riders before they confirm a trip.

Data Model

Surge state is zone-scoped and time-bounded. The active multiplier for each zone is the single most-read value on the platform during high-demand periods.

-- Surge multiplier history (append-only audit log)
CREATE TABLE surge_events (
  event_id      UUID PRIMARY KEY,
  zone_id       VARCHAR(20),
  multiplier    DECIMAL(4,2),
  reason        VARCHAR(50),   -- 'demand_spike', 'supply_drop', 'weather'
  started_at    TIMESTAMP,
  ended_at      TIMESTAMP
);

-- Current active surge per zone
CREATE TABLE active_surge (
  zone_id       VARCHAR(20) PRIMARY KEY,
  multiplier    DECIMAL(4,2),
  updated_at    TIMESTAMP,
  expires_at    TIMESTAMP
);

Active multipliers are cached in Redis for low-latency reads by the fare estimation and ride request services:

-- Write surge multiplier with TTL
SET surge:<zone_id> <multiplier> EX 300

-- Read multiplier at fare calculation time
GET surge:<zone_id>

Core Algorithm: Multiplier Calculation

The surge pricing engine runs every 60 seconds per zone. The calculation proceeds as follows:

  1. Fetch inputs: Read current supply ratio from the supply-demand balancing service (available drivers / active requests) and the forecasted demand for the next 15 minutes.
  2. Compute raw multiplier: Apply a piecewise linear function over the supply ratio:
    • ratio >= 1.5 → multiplier = 1.0 (no surge)
    • ratio 1.0 to 1.5 → multiplier = 1.0 to 1.5 (linear interpolation)
    • ratio 0.5 to 1.0 → multiplier = 1.5 to 2.5 (steeper linear ramp)
    • ratio < 0.5 → multiplier = 2.5 to 4.0 (capped at platform maximum)
  3. Apply forecast adjustment: If the 15-minute demand forecast predicts worsening conditions, nudge the multiplier up by up to 20% preemptively.
  4. Smooth transitions: Apply a dampening factor so the multiplier cannot change by more than 0.5x per 60-second interval, preventing jarring price swings.
  5. Write and publish: Update Redis and the active_surge table. Publish a surge_changed event to Kafka for consumption by fare estimation, the rider app, and analytics.

Rider-Facing Transparency

Before confirming a trip, the rider app fetches the zone multiplier and displays the estimated total fare with a clear surge notice. A fare lock is issued for 2 minutes: if the rider confirms within that window, the quoted fare is honored even if the multiplier increases during checkout.

Failure Handling

  • Surge engine crash: Redis TTL on surge keys ensures stale multipliers expire within 5 minutes. Downstream services fall back to 1.0x on a cache miss, preventing indefinite incorrect pricing.
  • Supply-demand service unavailable: The surge engine uses the last known supply ratio with a staleness flag. If data is more than 3 minutes old, multipliers are frozen at their current value until fresh data arrives.
  • Multiplier runaway: A hard cap (e.g., 4.0x) is enforced at both the calculation layer and the fare display layer. Any attempt to write a multiplier above the cap triggers an alert and is rejected.
  • Double-write inconsistency: Redis and the database are written in a two-phase pattern. If the database write fails, the Redis key is deleted to ensure the system returns a safe default rather than serving a committed-but-unlogged multiplier.

Scalability Considerations

  • Read fan-out: Surge multipliers are read by fare estimation on every ride request. With millions of requests per hour, Redis cluster mode with read replicas handles the fan-out without hitting the database.
  • Zone count scaling: With tens of thousands of H3 zones globally, the surge engine runs as a distributed job partitioned by city. Each city cluster computes its zones independently on a 60-second schedule.
  • Event-driven consumers: The surge_changed Kafka event allows the rider app, driver app, and analytics pipeline to react to multiplier changes without polling, reducing load on the surge service itself.
  • Audit and compliance: Every multiplier change is appended to surge_events with a reason code. This supports regulatory reporting and fare dispute resolution without scanning the operational table.

Summary

The surge pricing service translates supply-demand imbalances into fare adjustments using a piecewise linear multiplier function with smoothing and hard caps. The key engineering challenges are low-latency multiplier reads at high fan-out, safe failure modes that default to no-surge, and a transparent rider experience with fare locking. Decoupling the computation (60-second batch) from the reads (Redis cache) keeps the system both consistent and fast under load.

See also: Uber Interview Guide 2026: Dispatch Systems, Geospatial Algorithms, and Marketplace Engineering

See also: Lyft Interview Guide 2026: Rideshare Engineering, Real-Time Dispatch, and Safety Systems

See also: Airbnb Interview Guide 2026: Search Systems, Trust and Safety, and Full-Stack Engineering

Scroll to Top