System Design LabSystem Design QuestionsDesign Online Presence Service

Design Online Presence Service

EasyReal-time Systemsreal-timewebsocketspresencemessaging🟣 Meta

Question Overview

Design the online indicator and last-seen timestamp for a chat app with 100M concurrent connections. The interesting parts are detecting liveness cheaply with heartbeats and TTLs, avoiding flicker on flaky mobile networks, and fanning out status changes without flooding every contact.…

Sign up to see the full question and AI interviewer

Requirements

  • Show each contact as online or offline, with a last seen time for offline contacts
  • A user is online if any device is connected; changes reach watching contacts within 5 seconds
  • Disconnects shorter than 20 seconds do not cause online/offline flicker
  • A user who disconnects or crashes stops appearing online within about 60 seconds
  • Honor privacy settings that hide last seen from everyone or from non-contacts
  • Chat-list presence reads return in under 100 ms; eventual consistency is acceptable

Back-of-the-envelope numbers

  • Connections: 100M concurrent ÷ ~100K connections per gateway ≈ 1,000 gateway servers, plus headroom for failover
  • Heartbeats: 100M ÷ 30 s ≈ 3.3M heartbeats/s, absorbed in gateway memory rather than written to any database
  • Transitions: 500M DAU × 20 changes/day = 10B/day ÷ 86,400 s ≈ 116K/s average, ~350K/s at 3× peak
  • Naive fan-out: 116K changes/s × ~40 online contacts (20% of 200) ≈ 4.6M pushes/s, so push only to contacts actively viewing
  • Presence store: 500M users × ~50 bytes (status, device set, gateway ID, last seen) ≈ 25 GB in a sharded in-memory store
  • Chat-list reads: 500M × 20 opens/day = 10B batched lookups/day ≈ 116K requests/s, each fetching ~50 contacts in one MGET

Key components

  • Connection gateways: hold WebSocket or MQTT connections, track heartbeats in memory, and declare a device gone after ~2 missed beats
  • Presence store in sharded Redis: per-user device set, status, gateway ID, and last seen, with a TTL as a safety net
  • Grace-period debouncer: delay publishing offline for ~20 seconds so a quick reconnect cancels it and nobody sees flicker
  • Pub/sub fan-out: clients subscribe to contacts currently on screen, and gateways subscribe to per-user channels on their behalf
  • Gateway liveness leases: when a gateway stops renewing, the presence service marks all of its connections offline in bulk
  • Durable last-seen store (e.g. Cassandra) written on disconnect, with privacy rules applied on every read and push

Common mistakes

  • Writing every heartbeat to a database, producing ~3.3M writes/s for data that only matters when status changes
  • Pushing every status change to all 200 contacts, even those offline or not looking at the user
  • Marking users offline the instant a socket closes, which causes constant flicker on flaky mobile networks
  • Relying only on explicit disconnect events, so a crashed app or dead gateway leaves users online forever
  • Keeping one status per user instead of per device, so closing the web tab marks a user offline while their phone is connected
  • Using strongly consistent storage or consensus for presence, paying latency for data that is inherently approximate

Likely follow-ups

  • What happens to presence when a gateway holding 100K connections crashes?
  • How would you build typing indicators, and how do they differ from presence?
  • How would you show presence in a group chat with 5,000 members?
  • How would you reduce the battery and data cost of heartbeats on mobile devices?
  • How would presence work across regions when two friends are connected to different data centers?
  • How would you enforce a rule that users who hide their last seen cannot see others' last seen?

No community solutions yet

Be the first to publish your solution

Practice ‘Design Online Presence Service’ with an AI Interviewer

Get scored feedback on your diagram, scalability approach, and trade-offs. Free while we grow — up to 3 full interviews a day.