Chuyển đến nội dung chính

レッスン 26: ケーススタディ - ニュース フィード システムの設計

ニュースフィードのデザイン (Facebook/Twitter/Instagram)。ファンアウト戦略: プッシュ、プル、ハイブリッド。フィードランキングアルゴリズムの概念。フィードのキャッシュ。リアルタイムの更新。有名人(数百万人のフォロワー)を扱います。

🏗️ 建築 — レッスン 26 レッスン 26: ケーススタディ - ニュース フィードのデザイン システム

システムアーキテクチャ: ゼロからヒーローへ

パート 7: システム設計のケーススタディ

xdev.asia

はじめに

ニュース フィードは、あらゆるソーシャル プラットフォームの中核機能です。各ユーザーは、何千もの友人やフォローから集計され、関連性によってランク付けされた独自のフィードを持っています。規模が非常に大きいため、これは難しい問題です。


1. 要件と見積もり

Functional:
  - User tạo post (text, image, video)
  - News Feed hiển thị posts từ friends/followings
  - Feed ranked theo relevance (không chỉ chronological)
  - Support likes, comments, shares
  - Real-time: post mới xuất hiện trong feed bạn bè

Non-Functional:
  - Feed load < 500ms
  - 500M DAU
  - Average 500 friends per user

Estimation:
  Feed requests: 500M × 10 views/day = 5B feed requests/day
  QPS: 5B / 86400 ≈ 58K QPS (peak: 150K)
  Posts/day: 500M × 2 posts = 1B posts/day
  Post size: ~1KB text + pointers → 1TB/day

2. コアコンポーネント

┌──────────────────────────────────────────────────────┐
│                                                       │
│  ┌──────────┐    Post Service                         │
│  │ User     │───► ┌──────────────┐                    │
│  │ creates  │    │ Post Storage │                    │
│  │ post     │    │ (posts DB)   │                    │
│  └──────────┘    └──────┬───────┘                    │
│                         │                             │
│                  ┌──────▼───────┐                     │
│                  │ Fan-out      │                     │
│                  │ Service      │                     │
│                  └──────┬───────┘                     │
│                         │                             │
│               ┌─────────▼──────────┐                  │
│               │ Feed Cache         │                  │
│               │ (per-user feed)    │                  │
│               └─────────┬──────────┘                  │
│                         │                             │
│  ┌──────────┐    ┌──────▼───────┐                     │
│  │ User     │───►│ Feed Service │                     │
│  │ reads    │    │ (retrieve)   │                     │
│  │ feed     │    └──────────────┘                     │
│  └──────────┘                                         │
│                                                       │
└──────────────────────────────────────────────────────┘

3. ファンアウト戦略

3.1 書き込み時のファンアウト (プッシュ モデル)

User A posts → Write to ALL followers' feed cache

  User A has 1000 followers
  Post → Fan-out Service:
    Feed[follower_1].prepend(post)
    Feed[follower_2].prepend(post)
    ...
    Feed[follower_1000].prepend(post)

  ✅ Feed read: Instant (pre-computed)
  ❌ Write: Slow for celebrities (10M followers!)
  ❌ Wasted work: inactive users' feeds updated
  ❌ Hot key: Celebrity's post → 10M cache writes

3.2 読み取り時のファンアウト (プル モデル)

User B opens feed → Query all friends' posts, merge, rank

  User B has 500 friends
  Feed request:
    Get posts from friend_1 (last 24h)
    Get posts from friend_2 (last 24h)
    ...
    Merge + Rank + Return top 20

  ✅ Write: Instant (just store post)
  ❌ Read: Slow (500 queries per feed request!)
  ❌ High read latency

3.3 ハイブリッド (Facebook/Twitter アプローチ)

Normal users (< 10K followers): Fan-out on Write
  → Pre-compute feeds, instant reads

Celebrities (> 10K followers): Fan-out on Read
  → Don't pre-compute, merge at read time

Feed Read:
  1. Get pre-computed feed (from cache)
  2. Get celebrity posts (from post store)
  3. Merge + Re-rank
  4. Return top N

  ┌────────────────────────────────────────┐
  │ User B's Feed                          │
  │                                        │
  │ Pre-computed cache: [post5, post3, ...]│
  │ +                                      │
  │ Celebrity posts:   [celeb_post_1, ...] │
  │ =                                      │
  │ Merged + Ranked:   [final feed]        │
  └────────────────────────────────────────┘

4. フィードランキング

Không chỉ chronological, mà ranked by relevance:

Score = f(affinity, weight, time_decay)

  Affinity:    Bạn tương tác với author bao nhiêu?
               (likes, comments, messages, profile views)

  Weight:      Post type importance
               Video > Photo > Link > Text
               Comments > Likes

  Time Decay:  Post cũ hơn → score giảm
               score × (1 / time_since_posted^1.5)

Simplified Ranking:
  score = (likes × 1 + comments × 3 + shares × 5)
          × affinity_score
          × time_decay_factor

ML-based:
  Feature engineering → Train model
  Features: user engagement history, post features,
            social graph, time context
  Model: Predict P(user engages with post)

5. フィード キャッシュの設計

Per-user feed cache (Redis):

  Key: feed:{user_id}
  Value: List of post_ids (last 1000)

  feed:user_123 → [post_999, post_998, post_995, ...]

Feed retrieval:
  Page 1: LRANGE feed:user_123 0 19    (posts 1-20)
  Page 2: LRANGE feed:user_123 20 39   (posts 21-40)

Post details:
  Separately cached:
  post:999 → { author, text, image_url, likes, ... }

  Feed = post_ids from user cache
       + post details from post cache
       + author info from user cache
       → Assemble in API server

Cache Eviction:
  - Keep last 1000 posts per user
  - TTL: 7 days (re-compute if expired)
  - Active users: always fresh (fan-out keeps updating)
  - Inactive users: compute on demand

6. リアルタイム更新

Long Polling vs WebSocket vs SSE:

  Long Polling: Client polls every 30s
    Simple, but delayed, wasteful

  WebSocket: Persistent connection
    Real-time, but resource-heavy (50M connections!)

  SSE (Server-Sent Events): Server push, HTTP-based
    Simpler than WebSocket, one-directional

Approach (Facebook-style):
  - Initial load: REST API (full feed)
  - Updates: Long polling / SSE (new posts notification)
  - "3 new posts available" → Click to load
  - NOT auto-inject (breaks reading flow)

概要

決定選択理由
ファンアウトハイブリッドすべてのユーザー タイプの書き込み/読み取りのバランスをとる
ストレージCassandra (投稿) + Redis (フィード)書き込みが多い + 高速読み取り
ランキングML ベースのスコアリング関連性 > 最新性
リアルタイムSSE + 通知WebSocket が完全ではありません
キャッシュユーザーごとのフィード キャッシュ高速読み取りのために事前計算

演習

  1. 有名人の問題: ユーザーの投稿には 5,000 万人のフォロワーがいます。書き込み時のファンアウト → 50M キャッシュの更新。最大 5 秒の遅延を持つソリューションを設計します。

  2. フィードの多様性: フィードは 1 人のユーザーからのすべての投稿であってはなりません。重複排除 + 多様性アルゴリズムを設計します。

  3. 広告の統合: スポンサー付きの投稿をフィードに挿入します (5 つの投稿につき 1 つの広告)。フィードの遅延に影響を与えずに広告挿入戦略を設計します。