1. Requirements
Functional Requirements
| Feature |
Description |
Priority |
| Search Listings |
Search by location, dates, price, amenities, guest count |
P0 |
| View Listing Details |
Photos, description, amenities, location, reviews, calendar |
P0 |
| Book Property |
Reserve dates, payment processing, instant/request booking |
P0 |
| Calendar Management |
Hosts manage availability, pricing, blocked dates, minimum stay |
P0 |
| Reviews System |
Two-sided reviews (guest + host), 14-day window after checkout |
P0 |
| Messaging |
Host-guest communication, pre-booking inquiries, booking-related |
P0 |
| Payment Processing |
Guest pays upfront, host receives payout after check-in |
P0 |
| Dynamic Pricing |
Price suggestions based on demand, seasonality, events |
P1 |
| Cancellation Policy |
Flexible, moderate, strict policies with refund rules |
P1 |
Non-Functional Requirements
| Requirement |
Target |
Notes |
| Scale |
150M users, 7M listings, 300M nights booked/year |
~10K bookings/min peak |
| Search Latency |
<200ms p99 |
Geo + filter search |
| Booking Availability |
99.95% (no double-booking) |
Strong consistency required |
| Read:Write Ratio |
100:1 |
Search-heavy, booking rare |
| Image Storage |
~70M images (10 per listing) |
CDN delivery required |
| Data Consistency |
Strong for bookings, eventual for search |
Prevent overbooking |
Back-of-Envelope Estimates
| Metric |
Calculation |
Result |
| Daily Active Users |
150M total Γ 10% DAU |
15M DAU |
| Search QPS |
15M Γ 5 searches/day / 86400s |
~900 QPS avg, 5K peak |
| Booking QPS |
300M bookings/year / 31.5M sec/year |
~10 QPS avg, 100 peak |
| Storage (Listings) |
7M listings Γ 50KB metadata |
~350GB |
| Storage (Images) |
70M images Γ 500KB |
~35TB |
| Storage (Bookings) |
300M bookings Γ 2KB |
~600GB/year |
Interview Callout: Clarify booking semantics early: instant booking vs. request-to-book (host approval required). Instant booking needs stronger availability guarantees. Also confirm whether to support hourly rentals (adds complexity to calendar model).
2. High-Level Design
graph TB
subgraph "Client Layer"
Web[Web App]
Mobile[Mobile Apps]
end
subgraph "API Gateway / Load Balancer"
LB[Load Balancer + API Gateway]
end
subgraph "Application Services"
SearchAPI[Search Service]
ListingAPI[Listing Service]
BookingAPI[Booking Service]
UserAPI[User Service]
ReviewAPI[Review Service]
MessageAPI[Messaging Service]
PaymentAPI[Payment Service]
PricingAPI[Pricing Service]
end
subgraph "Data Layer"
ListingDB[(Listings DB
Postgres)]
BookingDB[(Bookings DB
Postgres)]
UserDB[(User DB
Postgres)]
CalendarDB[(Calendar DB
Postgres)]
ReviewDB[(Review DB
Postgres)]
end
subgraph "Search Infrastructure"
ES[Elasticsearch
Cluster]
GeoIndex[Geospatial Index]
end
subgraph "Caching Layer"
Redis[Redis Cache
Listings, Availability]
end
subgraph "Storage & CDN"
S3[Object Storage
Images, Docs]
CDN[CDN
Image Delivery]
end
subgraph "Message Queue"
Kafka[Kafka
Events, Analytics]
end
subgraph "Background Jobs"
PricingWorker[Pricing ML Model]
SearchIndexer[Search Indexer]
NotificationWorker[Notification Worker]
end
Web --> LB
Mobile --> LB
LB --> SearchAPI
LB --> ListingAPI
LB --> BookingAPI
LB --> UserAPI
LB --> ReviewAPI
LB --> MessageAPI
LB --> PaymentAPI
SearchAPI --> ES
SearchAPI --> GeoIndex
SearchAPI --> Redis
ListingAPI --> ListingDB
ListingAPI --> Redis
ListingAPI --> S3
BookingAPI --> BookingDB
BookingAPI --> CalendarDB
BookingAPI --> PaymentAPI
BookingAPI --> Redis
UserAPI --> UserDB
ReviewAPI --> ReviewDB
ReviewAPI --> Kafka
MessageAPI --> UserDB
MessageAPI --> Kafka
ListingDB --> Kafka
BookingDB --> Kafka
Kafka --> SearchIndexer
Kafka --> PricingWorker
Kafka --> NotificationWorker
SearchIndexer --> ES
PricingWorker --> PricingAPI
PricingAPI --> ListingDB
S3 --> CDN
Core Components
| Component |
Responsibility |
Technology |
| Search Service |
Geospatial search, filters, ranking |
Elasticsearch, Redis |
| Listing Service |
CRUD for listings, photos, amenities |
Postgres, S3, CDN |
| Booking Service |
Availability check, reservation, payment coordination |
Postgres + locks |
| Calendar Service |
Availability management, date range queries |
Postgres (optimized schema) |
| Payment Service |
Charge guest, hold funds, pay host |
Stripe, ledger DB |
| Review Service |
Two-sided reviews, fraud detection |
Postgres, ML fraud model |
| Messaging Service |
Host-guest chat, notifications |
WebSocket, Kafka, Postgres |
| Pricing Service |
Dynamic pricing suggestions |
ML model, batch jobs |
Interview Callout: The architecture separates read-heavy (search) from write-heavy (booking) paths. Search uses eventual consistency (Elasticsearch), while booking requires strong consistency (Postgres with locks). Explain this trade-off.
3. Search System
Search Requirements
| Search Type |
Parameters |
Index Strategy |
| Geospatial |
Lat/lng + radius (or bounding box) |
Geo-point field, geo-distance query |
| Date Range |
Check-in, check-out dates |
Inverted index on blocked_dates |
| Filters |
Price range, guest count, amenities (pool, wifi, etc.) |
Keyword fields, range queries |
| Full-Text |
Search listing title/description |
Analyzed text fields |
Elasticsearch Document Schema
| Field |
Type |
Purpose |
| listing_id |
keyword |
Primary identifier |
| location |
geo_point |
Lat/lng for geospatial queries |
| blocked_dates |
date_range[] |
Unavailable date ranges (bookings + host blocks) |
| price_per_night |
integer |
Base price for sorting/filtering |
| max_guests |
integer |
Guest capacity |
| amenities |
keyword[] |
wifi, pool, parking, etc. |
| rating_avg |
float |
Average star rating (1-5) |
| review_count |
integer |
Total reviews |
| title |
text |
Full-text search |
| property_type |
keyword |
Apartment, house, etc. |
Ranking Algorithm
| Factor |
Weight |
Calculation |
| Relevance Score |
40% |
Elasticsearch BM25 (location distance, text match) |
| Quality Score |
30% |
rating_avg Γ log(review_count + 1) |
| Price Competitiveness |
20% |
Normalized price vs. area median |
| Booking Velocity |
10% |
Bookings in last 30 days (popularity signal) |
Search Query Example
POST /listings/_search
{
"query": {
"bool": {
"must": [
{ "geo_distance": {
"distance": "10km",
"location": { "lat": 37.7749, "lon": -122.4194 }
}
}
],
"must_not": [
{ "terms": { "blocked_dates": ["2026-06-01", "2026-06-02", ...] } }
],
"filter": [
{ "range": { "price_per_night": { "lte": 200 } } },
{ "range": { "max_guests": { "gte": 4 } } },
{ "terms": { "amenities": ["wifi", "pool"] } }
]
}
},
"sort": [
{ "_score": "desc" },
{ "rating_avg": "desc" }
],
"size": 20
}
Search Optimizations
| Optimization |
Technique |
Impact |
| Cache Hot Queries |
Redis cache for popular locations (SF, NYC, etc.) |
50% cache hit rate |
| Shard by Region |
ES index sharded geographically (US-West, US-East, EU, etc.) |
Reduce search space |
| Result Pagination |
Search-after cursor (avoid deep pagination) |
Constant latency |
| Incremental Updates |
Kafka pipeline: BookingDB β Kafka β ES indexer |
Near real-time availability |
Interview Callout: Discuss trade-offs of eventual consistency in search. A listing might show as available in ES but be booked by the time the user tries to reserve. Handle this by re-checking availability in the Booking Service (source of truth = CalendarDB).
4. Booking Flow
Booking State Machine
| State |
Description |
Timeout |
| PENDING |
User initiated booking, dates reserved (pessimistic lock) |
15 minutes |
| PAYMENT_PROCESSING |
Payment gateway called, awaiting response |
5 minutes |
| CONFIRMED |
Payment succeeded, booking finalized |
- |
| CANCELLED |
User or host cancelled, refund issued per policy |
- |
| EXPIRED |
Payment timeout, dates released |
- |
Booking Flow Sequence Diagram
sequenceDiagram
participant Guest
participant BookingAPI
participant CalendarDB
participant PaymentAPI
participant HostNotification
participant Kafka
Guest->>BookingAPI: POST /bookings (listing_id, dates, guests)
BookingAPI->>CalendarDB: BEGIN TRANSACTION
BookingAPI->>CalendarDB: SELECT * FROM calendar WHERE listing_id=X AND dates IN (range) FOR UPDATE
alt Dates Available
CalendarDB-->>BookingAPI: 0 conflicts
BookingAPI->>CalendarDB: INSERT INTO bookings (status=PENDING, expires_at=NOW()+15min)
BookingAPI->>CalendarDB: UPDATE calendar SET blocked=TRUE WHERE dates IN (range)
BookingAPI->>CalendarDB: COMMIT
BookingAPI-->>Guest: 200 OK {booking_id, status=PENDING, expires_at}
Guest->>PaymentAPI: POST /payments (booking_id, payment_method)
PaymentAPI->>PaymentAPI: Charge card via Stripe
alt Payment Success
PaymentAPI-->>BookingAPI: Payment succeeded
BookingAPI->>CalendarDB: UPDATE bookings SET status=CONFIRMED
BookingAPI->>Kafka: Publish BookingConfirmed event
Kafka->>HostNotification: Send notification to host
Kafka->>SearchIndexer: Update ES (block dates)
BookingAPI-->>Guest: 200 OK {status=CONFIRMED}
else Payment Failed
PaymentAPI-->>BookingAPI: Payment failed
BookingAPI->>CalendarDB: DELETE FROM bookings WHERE booking_id=X
BookingAPI->>CalendarDB: UPDATE calendar SET blocked=FALSE WHERE dates IN (range)
BookingAPI-->>Guest: 400 Payment Failed
end
else Dates Unavailable
CalendarDB-->>BookingAPI: Conflict detected
BookingAPI->>CalendarDB: ROLLBACK
BookingAPI-->>Guest: 409 Conflict (dates unavailable)
end
Note over BookingAPI,CalendarDB: Background Job: Expire PENDING bookings after 15min
Double-Booking Prevention
| Strategy |
Mechanism |
Trade-off |
| Pessimistic Locking |
SELECT FOR UPDATE on calendar rows during booking |
Serializes concurrent bookings (safe but slower) |
| Unique Constraint |
UNIQUE(listing_id, date) in calendar table |
DB-level guarantee against double-booking |
| Idempotency Key |
Client sends idempotency_key, server dedupes retries |
Prevents duplicate bookings from retries |
| Timeout + Cleanup |
PENDING bookings expire after 15min, cron releases dates |
Prevents indefinite holds |
Booking API Endpoints
| Endpoint |
Method |
Description |
| /bookings |
POST |
Create booking (check availability + reserve dates) |
| /bookings/{id}/confirm |
POST |
Finalize booking after payment |
| /bookings/{id}/cancel |
POST |
Cancel booking (refund per policy) |
| /bookings/{id} |
GET |
Get booking details |
| /users/{id}/bookings |
GET |
List user's bookings (guest or host view) |
Interview Callout: The 15-minute reservation window is critical. Without it, users could hold dates indefinitely without paying. Implement a background job (cron or TTL index) to auto-expire PENDING bookings and release dates.
5. Calendar & Availability
Calendar Schema
| Column |
Type |
Description |
| listing_id |
UUID |
Foreign key to listings table |
| date |
DATE |
Single calendar date |
| status |
ENUM |
AVAILABLE, BOOKED, BLOCKED |
| price |
DECIMAL |
Price for this night (dynamic pricing) |
| booking_id |
UUID (nullable) |
Reference to booking if status=BOOKED |
| min_stay |
INTEGER |
Minimum nights required (host-defined) |
| updated_at |
TIMESTAMP |
Last update timestamp |
Index Strategy
| Index |
Columns |
Purpose |
| PRIMARY KEY |
(listing_id, date) |
Enforce unique date per listing, fast lookups |
| BTREE |
(listing_id, date, status) |
Range queries: "check availability for dates X-Y" |
| BTREE |
(booking_id) |
Reverse lookup: find all dates for a booking |
Efficient Date Range Queries
| Query Type |
SQL Example |
Notes |
| Check Availability |
SELECT COUNT(*) FROM calendar WHERE listing_id=? AND date BETWEEN ? AND ? AND status='AVAILABLE' |
Returns 0 if any date unavailable |
| Block Dates |
UPDATE calendar SET status='BLOCKED' WHERE listing_id=? AND date BETWEEN ? AND ? |
Host manually blocks dates |
| Book Dates |
UPDATE calendar SET status='BOOKED', booking_id=? WHERE listing_id=? AND date IN (?,...) |
Atomic update during booking |
| Get Pricing |
SELECT date, price FROM calendar WHERE listing_id=? AND date BETWEEN ? AND ? |
Calculate total cost |
Minimum Stay Logic
| Scenario |
Host Rule |
Validation |
| Weekend Bookings |
min_stay=2 on Fri-Sat |
Reject 1-night Friday bookings |
| Peak Season |
min_stay=7 in July/August |
Enforce weekly rentals during summer |
| Gap Prevention |
Don't allow 1-day gaps between bookings |
Check prev/next bookings, suggest extended stay |
Calendar Initialization
| Approach |
Description |
Trade-off |
| Pre-populate 2 years |
Insert 730 rows per listing on creation |
Simple queries, but 7M listings Γ 730 = 5B rows |
| On-demand insertion |
Only insert dates when booked/blocked |
Sparse table, but complex "available by default" logic |
| Hybrid (6-month window) |
Pre-populate next 6 months, extend on query |
Balance storage vs. complexity |
Interview Callout: The (listing_id, date) primary key enforces uniqueness at the DB level, preventing double-booking even under race conditions. Discuss sharding strategy: shard by listing_id to co-locate all dates for a listing on one shard.
6. Dynamic Pricing
Pricing Factors
| Factor |
Signal |
Weight |
| Supply & Demand |
Available listings vs. search volume in area |
40% |
| Seasonality |
Peak season (summer, holidays) vs. off-season |
25% |
| Local Events |
Concerts, conferences, sports (API: Eventbrite, SeatGeek) |
20% |
| Day of Week |
Weekends more expensive than weekdays |
10% |
| Booking Velocity |
Recent bookings in area (trending demand) |
5% |
Pricing Model Architecture
| Component |
Description |
Technology |
| Feature Pipeline |
Aggregate search/booking data by region + date |
Spark batch jobs (daily) |
| ML Model |
Predict optimal price given features (regression) |
XGBoost, deployed to SageMaker |
| Pricing Service |
Serve price suggestions to hosts via API |
Python Flask + Redis cache |
| Override Mechanism |
Host can accept/reject suggestions, set manual prices |
Calendar table (host has final say) |
Price Suggestion Workflow
| Step |
Action |
Output |
| 1. Feature Extraction |
Lookup listing location, nearby bookings, events |
Feature vector: [lat, lng, date, supply, demand, events, ...] |
| 2. Model Inference |
Call ML model API with features |
Suggested price: $120/night |
| 3. Host Notification |
Show suggestion in host dashboard |
"We recommend $120/night (15% above your base price)" |
| 4. Host Decision |
Host accepts or sets custom price |
Update calendar table with final price |
Event-Based Pricing Example
| Event |
Location |
Date |
Price Multiplier |
| Super Bowl |
Phoenix, AZ |
Feb 2027 |
3-5x |
| Coachella |
Indio, CA |
April 2027 |
2-4x |
| Tech Conference |
SF, CA |
Various |
1.5-2x |
| New Year's Eve |
NYC |
Dec 31 |
2-3x |
Pricing Constraints
| Constraint |
Rule |
Reason |
| Max Increase |
No more than 2x host's base price |
Prevent sticker shock, maintain trust |
| Min Price |
Never below host's floor price |
Host profitability |
| Smoothing |
Gradual price changes (avoid spikes) |
User experience |
| Last-Minute Discount |
Reduce price if unbooked 3 days before |
Fill empty dates |
Interview Callout: Dynamic pricing is a recommendation system, not enforcement. Hosts must opt-in and can override. This balances algorithmic optimization with host autonomy (critical for marketplace trust).
7. Reviews & Trust
Two-Sided Review System
| Aspect |
Guest Reviews Host |
Host Reviews Guest |
| Timing |
After checkout (14-day window) |
After checkout (14-day window) |
| Visibility |
Public on listing page |
Public on guest profile (visible to hosts only) |
| Ratings |
Cleanliness, accuracy, communication, location, value |
Cleanliness, communication, house rules |
| Text Review |
Optional, 500 char max |
Optional, 500 char max |
| Blind Period |
Reviews hidden until both submit (or 14 days expire) |
Reviews hidden until both submit (or 14 days expire) |
Review Schema
| Column |
Type |
Description |
| review_id |
UUID |
Primary key |
| booking_id |
UUID |
Foreign key (one review per booking per side) |
| reviewer_id |
UUID |
User who wrote review |
| reviewee_id |
UUID |
User being reviewed |
| review_type |
ENUM |
GUEST_TO_HOST, HOST_TO_GUEST |
| rating_overall |
INTEGER (1-5) |
Overall star rating |
| rating_cleanliness |
INTEGER (1-5) |
Cleanliness score |
| rating_communication |
INTEGER (1-5) |
Communication score |
| comment |
TEXT |
Written feedback |
| submitted_at |
TIMESTAMP |
When review was submitted |
| published_at |
TIMESTAMP |
When review became public (after blind period) |
| fraud_score |
FLOAT |
ML-based fraud detection score (0-1) |
Fraud Detection
| Signal |
Red Flag |
Action |
| Velocity |
User submits 10+ reviews in 1 hour |
Flag for manual review |
| Text Similarity |
Review text 90%+ similar to others from same user |
Likely bot/template |
| Rating Distribution |
Listing has 50 reviews, all 5-star |
Suspiciously uniform |
| Account Age |
New account (< 7 days old) leaving reviews |
Possible fake account |
| No Booking |
Review submitted without completed booking |
Block submission |
Review Aggregation
| Metric |
Calculation |
Usage |
| Average Rating |
SUM(rating_overall) / COUNT(*) |
Displayed on listing page, used in search ranking |
| Review Count |
COUNT(*) WHERE published_at IS NOT NULL |
Trust signal (more reviews = more reliable) |
| Category Breakdown |
AVG(rating_cleanliness), AVG(rating_communication), etc. |
Shown in listing details |
| Recency Weighting |
Weight recent reviews 2x older reviews |
Reflect current listing quality |
Interview Callout: The 14-day blind period prevents retaliation. Both parties submit reviews without seeing the other's feedback. Once both submit (or 14 days expire), reviews become public simultaneously. This encourages honest feedback.
8. Messaging System
Messaging Requirements
| Feature |
Description |
Priority |
| Pre-Booking Inquiries |
Guest asks questions before booking |
P0 |
| Booking Coordination |
Check-in details, keys, parking, etc. |
P0 |
| Real-Time Delivery |
WebSocket for instant messages |
P0 |
| Push Notifications |
Mobile push when offline |
P0 |
| Message History |
Persist conversation, searchable |
P0 |
| Automated Responses |
Host can set auto-replies (FAQ) |
P1 |
| Translation |
Auto-translate messages (60+ languages) |
P1 |
Messaging Architecture
| Component |
Technology |
Purpose |
| WebSocket Server |
Node.js + Socket.io |
Real-time bidirectional messaging |
| Message Queue |
Kafka |
Decouple message delivery, enable push notifications |
| Message Store |
Postgres (sharded by conversation_id) |
Persist message history |
| Push Service |
Firebase Cloud Messaging (FCM) |
Deliver notifications to offline users |
| Translation Service |
Google Translate API |
Auto-translate messages |
Message Schema
| Column |
Type |
Description |
| message_id |
UUID |
Primary key |
| conversation_id |
UUID |
Thread ID (booking-specific or inquiry-based) |
| sender_id |
UUID |
User who sent message |
| recipient_id |
UUID |
User who receives message |
| message_text |
TEXT |
Original message content |
| translated_text |
TEXT (nullable) |
Auto-translated version |
| sent_at |
TIMESTAMP |
Message send time |
| read_at |
TIMESTAMP (nullable) |
When recipient read message |
| is_automated |
BOOLEAN |
True if auto-generated (e.g., booking confirmation) |
Message Delivery Flow
| Step |
Action |
Component |
| 1. Send |
Guest sends message via WebSocket |
Client β WebSocket Server |
| 2. Persist |
Store message in database |
WebSocket Server β Postgres |
| 3. Publish |
Publish message to Kafka topic |
WebSocket Server β Kafka |
| 4. Deliver (Online) |
If recipient online, push via WebSocket |
WebSocket Server β Recipient Client |
| 5. Deliver (Offline) |
If recipient offline, send push notification |
Kafka β Push Service β FCM |
| 6. Translate (Optional) |
If recipient language differs, auto-translate |
Translation Worker β Google Translate API |
Automated Responses
| Trigger |
Auto-Message |
Example |
| Booking Confirmed |
Send check-in details to guest |
"Your booking is confirmed! Check-in at 3pm. WiFi password: xyz123" |
| Inquiry Received |
Host's FAQ auto-reply |
"Thanks for your interest! We allow pets and have free parking." |
| Checkout Reminder |
Day before checkout |
"Reminder: checkout is 11am tomorrow. Thanks for staying!" |
Interview Callout: Messaging is tied to bookings (conversation_id = booking_id) to provide context. This allows Airbnb to show booking details alongside messages and enforce policies (e.g., no off-platform payment requests).
9. Database Design
Core Tables
| Table |
Key Columns |
Sharding Strategy |
| users |
user_id (PK), email, name, role (guest/host), created_at |
Shard by user_id (hash) |
| listings |
listing_id (PK), host_id (FK), title, description, lat, lng, price_base, max_guests |
Shard by listing_id (hash) |
| calendar |
listing_id (FK), date (PK), status, price, booking_id (FK) |
Shard by listing_id (co-locate with listings) |
| bookings |
booking_id (PK), listing_id (FK), guest_id (FK), check_in, check_out, status, total_price |
Shard by listing_id (join with calendar) |
| reviews |
review_id (PK), booking_id (FK), reviewer_id (FK), reviewee_id (FK), rating_overall, comment |
Shard by listing_id (aggregation) |
| messages |
message_id (PK), conversation_id (FK), sender_id (FK), recipient_id (FK), message_text |
Shard by conversation_id (hash) |
| payments |
payment_id (PK), booking_id (FK), amount, status, stripe_charge_id |
Shard by booking_id |
Geospatial Indexing
| Approach |
Description |
Use Case |
| PostGIS Extension |
Postgres with geospatial functions (ST_Distance, ST_DWithin) |
Backup for admin queries, analytics |
| Elasticsearch Geo-Point |
geo_point field + geo_distance query |
Primary search index (sub-200ms latency) |
| Geohash Bucketing |
Encode lat/lng to geohash (e.g., "9q8yy"), index as keyword |
Coarse filtering before precise distance calc |
Sharding Strategy
| Table |
Shard Key |
Rationale |
| listings, calendar |
listing_id |
Co-locate listing metadata + availability on same shard for fast booking queries |
| bookings |
listing_id |
Join with calendar during booking flow (same shard) |
| reviews |
listing_id |
Aggregate reviews per listing efficiently |
| users |
user_id |
Separate shard (user queries don't join with listings) |
| messages |
conversation_id |
Keep entire conversation on one shard |
Replication & Consistency
| Table |
Replication |
Consistency Model |
| bookings, calendar |
Synchronous replication (2 replicas) |
Strong consistency (no double-booking) |
| listings |
Asynchronous replication (3 replicas) |
Eventual consistency (read from replicas OK) |
| reviews |
Asynchronous replication |
Eventual consistency |
| messages |
Asynchronous replication |
Eventual consistency (Kafka ensures delivery) |
Data Retention
| Data Type |
Retention Policy |
Archive Strategy |
| Bookings |
Forever (legal, accounting) |
Move >3 year old bookings to cold storage (S3) |
| Messages |
7 years (compliance) |
Archive to S3 after 2 years |
| Search Logs |
90 days (analytics) |
Delete after 90 days |
| Reviews |
Forever (public record) |
No archiving |
Interview Callout: Sharding by listing_id (not user_id) is key. Booking flow requires joining listings, calendar, and bookings tablesβco-locating them on the same shard avoids expensive cross-shard queries. Discuss trade-offs: user queries (e.g., "show all my bookings") become scatter-gather.
10. Scalability & Performance
Search Service Scalability
| Challenge |
Solution |
Impact |
| High Query Volume |
Elasticsearch cluster (50+ nodes), horizontal scaling |
Handle 5K QPS peak |
| Geo Query Latency |
Shard ES index by region (US-West, EU, Asia, etc.) |
Reduce search space, sub-100ms queries |
| Cache Hot Queries |
Redis cache for popular searches (SF, NYC, etc.) |
50% cache hit rate, offload ES |
| Stale Availability |
Accept eventual consistency, re-check in booking flow |
Trade latency for accuracy |
Booking Service Scalability
| Challenge |
Solution |
Impact |
| Concurrent Bookings |
Pessimistic locks (SELECT FOR UPDATE) + idempotency keys |
Prevent double-booking, serializes writes |
| Hotspot Listings |
Queue booking requests per listing (FIFO) |
Avoid lock contention |
| Payment Latency |
Async payment processing, return 202 Accepted |
Improve user experience (don't block) |
| Expired Reservations |
TTL index in Postgres or cron job (every 1 min) |
Auto-release dates after 15 min |
Image Delivery
| Component |
Technology |
Optimization |
| Object Storage |
S3 (or equivalent) |
Store original images, multi-region replication |
| CDN |
CloudFront / Cloudflare |
Cache images at edge (low latency globally) |
| Image Resizing |
Lambda@Edge or Imgix |
Generate thumbnails on-the-fly (200x200, 800x600, etc.) |
| Compression |
WebP format for browsers that support it |
50% smaller than JPEG |
Database Scaling
| Technique |
Description |
Use Case |
| Read Replicas |
3-5 read replicas per shard |
Offload read-heavy queries (search, listing details) |
| Connection Pooling |
PgBouncer in transaction mode |
Reduce connection overhead |
| Vertical Scaling |
Upgrade to larger instances (more RAM, CPU) |
Hot shards (popular cities) |
| Archiving |
Move old bookings (>3 years) to cold storage |
Keep DB size manageable |
Caching Strategy
| Cache Layer |
Data Cached |
TTL |
| Redis (Application) |
Listing metadata, user sessions |
1 hour |
| Redis (Search) |
Popular search results (SF, NYC, etc.) |
5 minutes |
| CDN |
Images, static assets |
1 day |
| Browser Cache |
Listing images, CSS, JS |
1 week |
Monitoring & Alerting
| Metric |
Threshold |
Alert Action |
| Search Latency |
p99 > 500ms |
Scale ES cluster, investigate slow queries |
| Booking Error Rate |
> 1% |
Check DB locks, payment gateway |
| DB Connection Pool |
> 80% utilization |
Scale connection pool or replicas |
| Kafka Lag |
> 10K messages |
Scale consumer workers |
| CDN Cache Hit Rate |
< 90% |
Investigate cache misses, adjust TTLs |
Disaster Recovery
| Scenario |
Mitigation |
RTO / RPO |
| DB Shard Failure |
Promote read replica to master (automatic failover) |
RTO: 30s, RPO: 0 (sync replication) |
| Region Outage |
Multi-region active-active (route traffic to healthy region) |
RTO: 1 min, RPO: 5 min |
| ES Cluster Down |
Fallback to cached results or degraded mode (no search) |
Graceful degradation |
| Payment Gateway Down |
Queue booking requests, retry when recovered |
Manual intervention |
Interview Callout: Airbnb's read:write ratio is 100:1 (search >> booking). The architecture reflects this: search uses eventual consistency + caching for speed, while booking requires strong consistency + locks for correctness. Discuss how to scale each path independently.