Design Facebook Likes with Live Updates — System Design Interview Practice
Design a like and unlike feature with reliable per-user state, scalable counts, and live updates for viewers of the same post. Work through the requirements, architecture trade-offs, and an interactive design review.
Concepts and architecture decisions to consider
- social mediaConcept to explore
- real timeConcept to explore
- event drivenConcept to explore
- scalabilityConcept to explore
- consistencyConcept to explore
Interview prompt
Design Facebook's Like feature so a user can like or unlike a post, see an accurate-enough count, and receive live updates when other people interact with the same post.
- Separate the user's membership state from the denormalized count and define which result must be strongly consistent.
- Make like and unlike idempotent, authorize the actor, and prevent duplicate state transitions under retries.
- Use an ordered event stream and coalesced fan-out for live count updates without turning every viewer into a database reader.
- Handle hot posts, celebrity traffic, reconnects, moderation deletes, and delayed or duplicated events explicitly.
Requirements and scale assumptions
- Allow an authenticated user to like or unlike a post and see whether they have liked it.
- Display a count and optionally a preview of representative users who liked the post.
- Push count and membership changes to viewers who are currently looking at the post.
- Keep moderation, privacy, blocked-user, and deleted-post rules reflected in reads and events.
- The actor's own like state is read-after-write consistent; the aggregate count may be briefly eventually consistent.
- Target p95 under 150 ms for a like write acknowledgement and under 2 seconds for a live count update.
- Do not lose an accepted like or unlike; retries and duplicate deliveries must not create duplicate state.
- A fan-out or analytics outage must not block the write path or expose private interactions.
- 1 billion registered users, 300 million daily active users, and 100 million posts receiving interactions each day.
- Assume 20 million like/unlike operations per day on average, with 10x bursts during live events.
- Most posts have fewer than 1,000 active viewers, but the hottest 1,000 posts can each have 100,000 viewers.
- Retain the durable interaction ledger for product and moderation needs; aggregate counts are rebuilt from it when required.
- Peak write rate: ~2.3K/s — 20M daily mutations with a 10x burst; provision partitions and queues for more than the average.
- Write acknowledgement: p95 <=150ms — The user sees their own state after the conditional interaction write commits.
- Live freshness: <=2 seconds — Coalesce count changes while exposing the last sequence and an offline/stale state.
- Hot-post fan-out: 100K viewers — Shard the subscriber set and send snapshots or deltas with backpressure.
Key entities
- LikeStatepostId, userId, liked, version, updatedAt, tombstone
One idempotent user/post like state.
- LikeEventeventId, postId, userId, operation, version, occurredAt
Durable interaction transition used for projection and replay.
- PostCounterpostId, count, appliedVersion, watermark, updatedAt
Rebuildable approximate/accurate-enough aggregate with freshness.
- RoomSubscriptionpostId, sessionId, lastVersion, expiresAt, status
Ephemeral subscription state for live updates.
Data flow
- 1. Commit the user's like stateThe like service conditionally writes post_id/user_id state and an idempotency result before acknowledging the user.
- 2. Publish the durable transitionAn outbox emits the like or unlike event after the ledger commit; duplicate deliveries are deduplicated by event ID.
- 3. Update the aggregate projectionPartition owners consume events, update the post counter with a monotonic version, and expose a freshness watermark.
- 4. Broadcast asynchronouslyThe room service coalesces rapid count changes, fans out scoped deltas to subscribers, and drops only updates clients can resync.
- 5. Repair hot posts and driftCounter rebuilds replay the ledger, compare versions, and correct the projection without blocking new like writes.
Deep dives and trade-offs
- Idempotent like stateFor Facebook's like and live-count feature, one user/post state is authoritative while counts and live updates are derived and repairable. Design for the failure case where celebrity-post fanout or duplicate retries must not inflate counts or block the write path; keep retries, versions, and repair state explicit. Expose freshness, version, lineage, or audit metadata so operators and clients can distinguish current, pending, and degraded state.
- Hot-post counter aggregationFor Facebook's like and live-count feature, one user/post state is authoritative while counts and live updates are derived and repairable. Keep this concern off unrelated request paths and partition it by Facebook's like and live-count feature access key. Expose freshness, version, lineage, or audit metadata so operators and clients can distinguish current, pending, and degraded state.
- Coalesced live delivery and resyncFor Facebook's like and live-count feature, one user/post state is authoritative while counts and live updates are derived and repairable. Keep this concern off unrelated request paths and partition it by Facebook's like and live-count feature access key. Expose freshness, version, lineage, or audit metadata so operators and clients can distinguish current, pending, and degraded state.
- Exact counter versus approximate countUse an exact ledger and asynchronously projected counter; allow approximate display semantics only when product tolerates it. Updating one exact counter synchronously for every hot post creates a write hot spot.
- Fanout-on-write versus fanout-on-readUse a partitioned counter projector and room fanout for subscribed viewers, with coalescing for bursts. Fanout to every follower on every like multiplies hot-post work.
- Push-only versus cursor resyncPush low-latency deltas but include versions and a pull/resync endpoint. Push-only clients drift whenever a mobile connection sleeps or a packet is lost.