Command Palette

Search for a command to run...

Hectal
PHASE 16Advanced ~9 min· topic 4 of 8

Topic 16.4

Social Media: Follows, Posts, Likes and Feeds

In one line

Social schemas store users, a follow graph, posts, likes and comments, with feeds built by fan-out on write (precompute each follower's timeline), fan-out on read (merge followees' posts at request time), or a hybrid that treats celebrities differently. Counters are denormalised and eventually consistent; media lives in object storage.

0/8 · 0%

Think of it like this

A newspaper delivery service. It can print a personalised paper for every subscriber when news arrives (fan-out on write), or have each reader visit every news stand they follow each morning (fan-out on read). For a celebrity columnist with 50M readers, pushing 50M copies instantly is impractical.

Key ideas

  1. 01

    Follow graph: follow(follower_id, followee_id, created_at) with PK (follower_id, followee_id) and an index on (followee_id, follower_id) for follower lists; counts denormalised on the user.

  2. 02

    Posts: post(id Snowflake, author_id, body, media_keys, created_at) indexed on (author_id, id DESC). Likes: post_like(post_id, user_id) PK (the uniqueness prevents double likes); like counts via counters (Topic 3.4).

  3. 03

    Fan-out on write: on post, insert (follower, post_id) into each follower's timeline (Redis sorted set or a Cassandra timeline table). Reads are fast; writes are expensive for accounts with huge followings.

  4. 04

    Fan-out on read: at read time, fetch recent posts from each followee and merge. Writes are cheap; reads are expensive for users following thousands.

  5. 05

    Hybrid: fan-out on write for normal authors; for celebrities (> ~100K followers), merge their recent posts at read time. Ranking adds a scoring step over candidates.

Code & diagrams

feed.sqlsql
CREATE TABLE follow (
  follower_id bigint NOT NULL, followee_id bigint NOT NULL, created_at timestamptz NOT NULL DEFAULT now(),
  PRIMARY KEY (follower_id, followee_id), CHECK (follower_id <> followee_id)
);
CREATE INDEX ON follow (followee_id, follower_id);

CREATE TABLE post (id bigint PRIMARY KEY, author_id bigint NOT NULL, body text,
                   created_at timestamptz NOT NULL);
CREATE INDEX ON post (author_id, id DESC);

-- fan-out on read (fine for small graphs): latest 30 posts from people I follow
SELECT p.* FROM follow f
JOIN LATERAL (SELECT * FROM post WHERE author_id = f.followee_id ORDER BY id DESC LIMIT 30) p ON true
WHERE f.follower_id = 42
ORDER BY p.id DESC LIMIT 30;
timeline.redisbash
# fan-out on write: push post 7300 (score = post id / time) to each follower's timeline
ZADD timeline:user:42 7300 post:7300
ZREMRANGEBYRANK timeline:user:42 0 -801        # keep newest 800 entries
# read a page (keyset by score)
ZREVRANGEBYSCORE timeline:user:42 +inf -inf LIMIT 0 30
ZREVRANGEBYSCORE timeline:user:42 (7250 -inf LIMIT 0 30   # next page after id 7250

Interview problem

The problem

Design the Instagram home feed storage

500M DAU, average 200 followees, some accounts with 300M followers; users open the feed 10 times/day. Design storage for posts, the follow graph and feeds, and explain the hybrid strategy.

When it breaks

Synchronous fan-out on write for a celebrity

What you see

One post triggers 300M timeline inserts; queues back up for hours, and other users' posts are delayed.

Fix & prevent

Hybrid: exclude high-follower accounts from fan-out and merge them at read time; process fan-out asynchronously with priority lanes.

Explain it without notes

01

Compare fan-out on write and fan-out on read.

Practice

01

Estimate fan-out writes per second for 100M posts/day with 200 average followers.

Trade-offs

  • ↔

    Precomputation buys read speed with write amplification and storage; the hybrid balances them around follower count.

Done when you can

  • I can design follow graphs, posts, likes and a hybrid feed with storage estimates.