Parking Service at Scale
📋 Jump to TakeawaysA parking service manages parking lots, tracking spot availability in real-time, allowing reservations, handling entry/exit, and processing payments. The challenges are real-time occupancy tracking across thousands of lots, handling concurrent spot claims, and dynamic pricing based on demand.
Step 1: Parking Service Requirements
Parking Service Functional Requirements
- Search for available parking near a location
- View real-time spot availability per lot
- Reserve a spot in advance (optional, time-limited hold)
- Entry/exit detection (license plate or ticket)
- Automatic billing based on duration and rate
- Support multiple spot types (regular, handicap, EV charging, compact)
Parking Service Non-Functional Requirements
| Metric | Target |
|---|---|
| Lots managed | 50,000 parking lots |
| Total spots | 10 million spots (avg 200 per lot, mix of small street lots and large garages) |
| Peak concurrent users | 100K searching simultaneously |
| Availability updates | Real-time (within 2 seconds of car entering/exiting) |
| Reservation consistency | No double-booking of a specific spot |
| Uptime | 99.9% |
Step 2: Parking Service Estimation
Notification Traffic
- Entry/exit events: 10M spots × avg 3 turnovers/day = 30M events/day = ~350 events/sec
- Search queries: 100K peak concurrent × 1 query/30sec = ~3,300 queries/sec
- Reservations: ~50K/day = negligible QPS
Parking Service Storage
- Lot metadata: 50K lots × 5 KB = 250 MB
- Spot records: 10M spots × 200 bytes = 2 GB
- Active sessions: 10M × 100 bytes = 1 GB
- Transaction history: 30M/day × 500 bytes × 365 days = 5.5 TB/year
Bandwidth
- Search responses (nearby lots + availability): 3,300/sec × 2 KB = 6.6 MB/sec
- Entry/exit events: 350/sec × 200 bytes = 70 KB/sec (trivial)
Step 3: Parking Service High-Level Design
┌─────────────────────────────────────────────────────────────────────┐
│ PARKING SERVICE │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ Mobile │────►│ API Gateway │────►│ Search Service │ │
│ │ App │ │ │ │ (find nearby │ │
│ └──────────┘ └──────┬───────┘ │ lots + avail.) │ │
│ │ └────────┬─────────┘ │
│ │ │ │
│ │ ▼ │
│ │ ┌──────────────────┐ │
│ │ │ Geospatial DB │ │
│ │ │ (PostGIS/Redis) │ │
│ │ └──────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ Reservation │ │
│ │ Service │ │
│ └──────┬───────┘ │
│ │ │
│ ┌──────────────┐ ▼ │
│ │ IoT Sensors │ ┌──────────────┐ ┌──────────────────┐ │
│ │ / Cameras │─►│ Occupancy │────►│ Availability │ │
│ │ (entry/exit)│ │ Service │ │ Cache (Redis) │ │
│ └──────────────┘ └──────┬───────┘ │ lot→free_count │ │
│ │ └──────────────────┘ │
│ ▼ │
│ ┌──────────────┐ ┌──────────────────┐ │
│ │ Billing │────►│ Payment │ │
│ │ Service │ │ Gateway │ │
│ │ (duration │ │ (Stripe) │ │
│ │ × rate) │ └──────────────────┘ │
│ └──────────────┘ │
└─────────────────────────────────────────────────────────────────────┘Entry/exit flow:
Car enters → sensor/camera detects → Occupancy Service:
1. Decrement available count in Redis
2. Create active session (lot, spot, plate, entry_time)
3. Update Availability Cache
Car exits → sensor detects → Occupancy Service:
1. Increment available count in Redis
2. Close session (set exit_time)
3. Billing Service: calculate charge (duration × rate)
4. Payment Gateway: charge card on fileStep 4: Parking Service Deep Dive
Occupancy Tracking
Each lot has a real-time counter in Redis:
lot:{lot_id}:available:regular → 45
lot:{lot_id}:available:handicap → 3
lot:{lot_id}:available:ev → 8
lot:{lot_id}:available:compact → 12Entry event:
DECR lot:{lot_id}:available:{type}If result < 0 → lot is full for that type, INCR back and reject (or direct to another type).
Exit event:
INCR lot:{lot_id}:available:{type}Why Redis counters? Atomic, sub-millisecond, handles concurrent entry/exit without locks. The counter is the real-time view; PostgreSQL stores the session history.
Spot-Level vs Lot-Level Tracking
Lot-level (simpler): Just track total available per type. Car gets any open spot. Works for most garages.
Spot-level (complex): Track each individual spot. Required when:
- Users reserve a specific spot
- Spots have different rates (premium location)
- Guidance systems direct cars to specific spots
For spot-level, use a bitmap in Redis:
lot:{lot_id}:spots → 1110010011... (1=occupied, 0=free)Search Service (Find Nearby Parking)
User opens app → "Find parking near me":
- Geospatial query: Find lots within radius using PostGIS or Redis GEO
GEOSEARCH lots FROMLONLAT -73.98 40.75 BYRADIUS 1 km ASC - Filter: Only lots with available spots of the needed type
- Rank: By distance, price, rating, availability percentage
- Return: List with real-time availability counts
Caching: Availability counts cached with 2-second TTL. Acceptable staleness, since the exact check happens at entry.
Reservation System
Optional pre-booking (e.g., airport parking):
Reserve → Reservation Service:
1. Check availability (Redis counter > 0)
2. DECR counter (hold the spot)
3. Store reservation (lot, type, user, start_time, end_time)
4. Set TTL: if user doesn't arrive within 30 min of start_time, release
User arrives → match reservation by plate/QR → confirm entry
User no-show → TTL expires → INCR counter back → charge no-show feeOverbooking strategy: For large lots (500+ spots), allow 5-10% overbooking on reservations. Statistically, not all reservations convert to arrivals.
Dynamic Pricing
Adjust rates based on demand:
Pricing factors:
- Current occupancy percentage (>80% → surge)
- Time of day (peak hours cost more)
- Day of week (weekday vs weekend)
- Nearby events (concert at venue → 2× rate)
- Historical demand patterns
Price tiers:
0-50% full: base rate ($3/hr)
50-80% full: 1.5× ($4.50/hr)
80-95% full: 2× ($6/hr)
95-100% full: 3× ($9/hr)Prices update every 5 minutes based on current occupancy. Displayed in search results so users can compare.
Billing Service
Calculate charges on exit:
Session:
entry_time: 2026-05-26 09:15
exit_time: 2026-05-26 14:45
duration: 5.5 hours
Rate schedule for this lot:
first_hour: $5
additional_hours: $3/hr
daily_max: $25
Charge: $5 + (4.5 × $3) = $18.50 (under daily max)Pre-authorized payment: Charge card on file at exit. If no card → license plate flagged, invoice mailed.
Fault Tolerance
- Sensor failure: If entry sensor fails, fall back to camera + license plate recognition. If both fail, manual attendant mode.
- Redis failure: Counters reconstructed from active sessions in PostgreSQL. Brief inconsistency (seconds) is acceptable.
- Network partition between sensor and service: Buffer events locally at the lot controller, replay when connection restores.
Key Takeaways
Redis atomic counters are the core primitive for availability
INCR/DECR on lot-level counters handles concurrent entry/exit without locks. Sub-millisecond latency means real-time availability updates. PostgreSQL stores durable session history.
Lot-level tracking is sufficient for most use cases
Individual spot tracking adds complexity (bitmaps, guidance systems) and is only needed for reserved-spot or premium-location scenarios. Start with lot-level counters.
Geospatial indexing enables "parking near me"
PostGIS or Redis GEO finds lots within radius efficiently. Combine with real-time availability filtering and price/distance ranking for useful search results.
Reservations need TTL-based release for no-shows
A reserved spot that nobody claims wastes inventory. Auto-release after a grace period (30 min past start time) keeps availability accurate. Charge a no-show fee to discourage abuse.
Dynamic pricing balances supply and demand
Surge pricing when lots are >80% full incentivizes users to park elsewhere or use transit. Update prices every few minutes based on current occupancy, not faster (confusing UX).
Sensor redundancy prevents revenue loss
A broken entry sensor means cars enter without being tracked (lost revenue). Layer camera + LPR + manual fallback. Buffer events locally during network outages and replay on reconnection.