Requirements
A live comments system allows users to post comments on content (articles, videos, livestreams) and see other users’ comments in real time. Scale: YouTube live chat reaches 10,000+ messages/minute for major events. Key challenges: real-time delivery to all viewers, chronological ordering, spam/abuse filtering, and pagination of existing comments without re-fetching the entire history. Functional requirements: post a comment, receive new comments in real time, load previous comments (paginated), upvote/downvote, reply threading, and moderation (delete, mute user). Non-functional: < 500ms latency from post to display for other viewers, 99.9% availability, no message loss.
Real-Time Delivery Architecture
WebSocket connections for real-time comment delivery. Each viewer maintains a persistent WebSocket connection to a comment server. Comments are partitioned by content_id — all viewers of the same content connect to servers subscribed to the same channel. Architecture: comment submission → API server → validates + stores in database → publishes to Redis Pub/Sub channel “comments:{content_id}”. Comment server nodes are subscribed to Redis Pub/Sub for the channels of their active connections. When a new comment is published: all subscribed server nodes receive it via Pub/Sub and push it to their connected viewers. Scaling WebSocket connections: 1M concurrent viewers = 1M persistent connections. At 10,000 connections per server: 100 servers needed. Use a load balancer that supports sticky sessions (or any WebSocket-capable LB like HAProxy, Nginx) to distribute connections. Connection state (which content_id each connection is watching) is stored in the server process memory (not shared state — scale-out by adding more servers).
Comment Storage and Pagination
Schema: Comment: comment_id (UUID), content_id, user_id, parent_id (nullable — for threading), body, created_at, status (ACTIVE, DELETED, FLAGGED), upvotes, downvotes. Index: (content_id, created_at DESC) for chronological feeds. Keyset pagination for live feeds: the client sends cursor = last_seen_comment_id + last_seen_created_at. Query: SELECT * FROM comments WHERE content_id=:id AND status=’ACTIVE’ AND created_at < :cursor_time ORDER BY created_at DESC LIMIT 50. For live streams: the initial load fetches the last N comments. The WebSocket stream delivers new comments as they arrive. The client displays a "Load more" button to fetch older comments on demand — avoiding infinite scroll for fast-moving live chats. Top-level + replies: top-level comments fetched separately from replies. Replies loaded on-demand when a user expands a thread. Parent comment count caching: store reply_count on the parent comment (incremented via trigger or async counter), displayed in the collapsed thread view.
Spam and Abuse Prevention
Rate limiting per user: max 5 comments per 10 seconds per user_id. Store in Redis: INCR rate:{user_id} with TTL 10s. If count > 5: return 429. For unauthenticated users: rate limit by IP. Automated spam detection: (1) Duplicate comment detection: SHA256 hash of comment body. If the same hash appears from the same user within 60 seconds: block as duplicate. Store recent (user_id, body_hash, timestamp) in Redis. (2) Link spam: detect URLs in comments. New accounts ( threshold → auto-remove. Score in gray zone → send to moderation queue. Community reporting: users flag comments. If a comment receives 5+ flags: auto-hide pending review. Moderator dashboard: queue of flagged comments, auto-hidden comments, and comments from new accounts for human review. Moderator actions: approve (unhide), delete, mute user (30 days, 90 days, permanent).
Ordered Delivery and Message Loss
Redis Pub/Sub does not persist messages. If a comment server restarts or a viewer’s connection drops and reconnects: they may miss comments published during the gap. Solution: each comment gets a monotonic sequence number (per content_id): Redis INCR “seq:{content_id}” → seq_number. Stored on the Comment row. On WebSocket reconnect: client sends last_received_seq. Server queries: SELECT * FROM comments WHERE content_id=:id AND seq_number > :last_seq ORDER BY seq_number ASC. Delivers any missed comments. For high-volume live streams: batch the “catchup” query — return all missed in one response, not one by one. Client-side ordering: display comments in seq_number order, not arrival order. Comments can arrive slightly out of order over WebSocket (network). Buffer for 100ms before rendering to handle minor jitter.
{
“@context”: “https://schema.org”,
“@type”: “FAQPage”,
“mainEntity”: [
{
“@type”: “Question”,
“name”: “How do you handle comment ordering in a live stream where millions of messages arrive per minute?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “At extreme scale (10M+ messages/min for major live events), strict global ordering is impractical — the latency of coordinating order across all writers exceeds user expectations. Practical approaches: (1) Per-shard ordering: partition the comment stream into shards (by content_id or sub-shards). Within each shard, comments are sequenced by a monotonic counter (Redis INCR). Clients display comments in shard-sequence order. Comments across shards may display slightly out of global order, but users rarely notice. (2) Approximate ordering: assign a server-side timestamp with millisecond precision. Sort by (timestamp_ms, comment_id) for tie-breaking. Small clock skew (100 accounts created in the same 1-hour window post on the same content. High correlation = likely coordinated. (3) Content similarity: multiple accounts posting identical or near-identical negative comments (Levenshtein distance < 5 between messages). Flag for review. (4) IP correlation: multiple accounts from the same /24 IP subnet posting on the same content. Network: if the comment section is embeddable, block embedding on sites known for brigading. Auto-hide: when a target user receives 50+ negative comments in 1 minute: auto-hide the section for that user (not for other viewers). Give the target a "shelter" while moderators respond. Shadowban: reduce the visibility of flagged accounts (their comments are visible only to themselves) rather than hard-banning — harder to detect and circumvent. Real-time response: have an on-call moderator channel (Slack/PagerDuty) that fires when the comment velocity/brigade detectors trigger."
}
},
{
"@type": "Question",
"name": "How do you implement comment threading (nested replies) efficiently?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Two approaches: adjacency list and closure table. Adjacency list: store parent_id on each comment. To fetch a thread: recursive query or application-side tree reconstruction. PostgreSQL recursive CTEs handle arbitrary depth efficiently. Shallow threading (max 2-3 levels like Reddit): adjacency list with application-side reconstruction works fine. Closure table: store all ancestor-descendant relationships: (ancestor_id, descendant_id, depth). To find all descendants of comment X: SELECT descendant_id FROM comment_closure WHERE ancestor_id=X. Efficiently supports any-depth queries without recursion. More writes on insert, but faster reads for deep trees. For most comment systems: limit threading depth to 2 levels (top-level + one reply level). Deep nesting confuses users and complicates the UI. Implementation: top-level comments fetched separately, replies loaded per parent comment on-demand. Display count of replies on each top-level comment. On expand: fetch all direct children (parent_id=comment_id). Ordering within a thread: chronological (oldest first for threaded discussion), or by upvotes (most popular replies first)."
}
},
{
"@type": "Question",
"name": "How do you design comment moderation to comply with content regulations like the DSA?",
"acceptedAnswer": {
"@type": "Answer",
"text": "The EU Digital Services Act (DSA) requires large platforms to: (1) Provide transparent content moderation policies and appeals. (2) Remove illegal content within defined timeframes (CSAM: 1 hour; terrorist content: 1 hour; other illegal: within 24h after notice). (3) Maintain records of content moderation decisions with reasoning. (4) Provide meaningful appeals mechanisms for users whose content is removed. Implementation: moderation decision logging: every moderation action (hide, delete, warn, ban) is logged with: moderator_id, reason_code (standardized taxonomy: SPAM, HATE_SPEECH, HARASSMENT, ILLEGAL_CONTENT, etc.), timestamp, evidence (text snippet, screenshot), and the specific policy violated. User notification: when a comment is removed, notify the user with the reason and the relevant policy. Include a link to the appeals process. Appeals: users can submit an appeal. A different moderator reviews it. Decisions can be reversed. All appeals and outcomes are logged. Audit trail: generate compliance reports on request from regulators: "all moderation actions in country X in the past 30 days." This requires the moderation decisions table to be indexed by (country, timestamp, action_type)."
}
}
]
}
Asked at: Twitter/X Interview Guide
Asked at: Snap Interview Guide
Asked at: Netflix Interview Guide
Asked at: Meta Interview Guide