Understanding the problem
Tinder (think a swipe-first dating app) is a consistency + geo-query interview. Pair with Contention, Proximity search, Cassandra, and Redis.
Geo + prefs feed.
Left / right.
Atomic + notify.
Never re-show.
Functional requirements
Non-functional requirements
Core entities
- User — profile, preferences, location.
- Swipe — from → to, direction (left/right).
- Match — unordered pair after mutual right.
- Stack — ordered candidate IDs for a session (often cached).
API
GET /stack?limit= -> Profile[]
// geo + prefs applied server-side
POST /swipes
{ "toUserId": "…", "direction": "left"|"right" }
-> { matched: boolean, matchId?: string }
GET /matches -> Match[]
High-level design
Build FR by FR: profile → stack → swipe → match notify. Profile Service owns preferences; Swipe Service owns Cassandra swipes + push on match.
Deep dives next: atomic match detection, fast stacks (ES + cache), and never re-showing swiped profiles.
Deep dive — consistent matches
Without atomicity: A and B both swipe right, each sees "no inverse yet," both rows get saved, nobody gets a match notification.
Bad — poll for matches
Misses the "immediate notify" NFR and burns DB QPS.
OK — transactions… but where?
Cassandra LWTs are single-partition only. At 2B swipes/day you can't put everything in one partition — so put each user pair in one partition.
min(id):max(id) — A→B and B→A land together.def get_user_pair(a, b):
x, y = sorted([a, b])
return f"{x}:{y}" # same partition for both directions
Great — Redis Lua + Cassandra durability
Redis hash per pair; Lua HSET own swipe + HGET inverse atomically. Match if both right. Flush/expire into Cassandra for history. Ops: cluster failover, aggressive TTL on Redis (lose only very recent match detection — user can re-swipe).
Deep dive — low-latency stacks
Open app → swipe immediately. A multi-filter SQL scan won't cut it.
Good — Elasticsearch / OpenSearch
Index prefs + geo. CDC from users DB (batch if write-heavy). See Elasticsearch and Proximity search.
Better — precompute stack cache
Cron warms Stack Cache from Profile DB so getStack() is instant on app open.
Great — cache + ES hybrid
Serve Stack Cache first; refill from Elasticsearch when the deck runs low so the stack feels infinite. Stale feeds: short TTL (<1h), recompute on filter/location change, warm only active users — tunable knobs without redesign.
Deep dive — never re-show swipes
- OK: Feed builder queries swipe partition by swiping_user_id and filters — risks replica lag under AP; expensive for huge histories.
- Better: Client keeps K recent swipes; filters while a new stack loads (assume one primary device).
- Great: For huge histories, a bloom filter — no false negatives (never re-show a real swipe); rare false positives skip a few profiles (tunable).
For huge swipe histories, upgrade the swipe cache to a bloom filter — no false negatives (never re-show a real swipe); rare false positives skip a few profiles (tunable).
Final design
Cost and performance levers
What interviewers expect by level
Architecture by level
Three progressive sketches — beginner spine, mid optimizations, pro production depth. Use the matching diagram in the interview; say the tradeoff out loud.
Pros: Clear dating loop with geo filters and a re-show avoidance story. Cons: Concurrent mutual rights without atomicity lose match notifies; naive SQL stacks miss latency NFRs.
Pros: Atomic pair-key matches; cache-first stacks with ES refill; stale-cache called out. Cons: Redis ops + ES CDC lag; must still explain Cassandra/history and client dedup.
Pros: Production dials (TTL, bloom FP%, warm set) and failure modes (Redis failover, hot pairs). Cons: Easy to over-build — lead with the race and stack p99 before bloom filters.
Mid: working dating loop. Senior: atomic matches + fast stacks. Staff: races, indexes, and tunable dedup.
Wrapping up
Tinder interviews reward pair-key atomicity, geo-aware stack plumbing, and honest dedup — with tunable TTLs and bloom error rates as ops dials.
Related: Delivery framework · Contention · Proximity search · Redis · Cassandra · Elasticsearch · Design Gopuff · Design Instagram · Interview bars by level.