导航菜单

系统设计案例

通过实际案例学习系统设计是最有效的方法。本章将深入分析几个经典的系统设计案例,帮助你理解如何将理论知识应用到实际设计中。

案例 1:设计 Twitter

需求分析

功能需求

  • 用户可以发布推文
  • 用户可以关注其他用户
  • 用户可以查看时间线(自己的推文和关注的人的推文)

非功能需求

  • 高可用性(99.99%)
  • 低延迟(时间线加载 < 200ms)
  • 高吞吐量(支持数亿用户)

容量估算

  • 用户数:10 亿用户
  • 日活用户:2 亿(20%)
  • 平均每个用户:每天发布 2 条推文,关注 200 人
  • 推文读取/写入比:100:1
  • 峰值 QPS
    • 写:2 亿 × 2 / 86400 ≈ 4,630 QPS
    • 读:4,630 × 100 ≈ 463,000 QPS

高层设计

用户 → 负载均衡 → API 服务器 → 推文服务
                              → 用户服务
                              → 时间线服务
                              → 关注服务

详细设计

1. 数据模型

用户表

  • user_id (主键)
  • username
  • email
  • created_at

推文表

  • tweet_id (主键)
  • user_id
  • content
  • created_at

关注关系表

  • user_id (主键)
  • follower_id (主键)
  • created_at

2. 时间线生成

方案 1:推模式(Fan-out on Write)

用户发布推文时,推送到所有关注者的时间线。

优点

  • 读取时间线快(O(1))

缺点

  • 写入慢(需要写入所有关注者的时间线)
  • 大 V 用户发布推文时压力大

方案 2:拉模式(Fan-out on Read)

读取时间线时,实时聚合关注的人的推文。

优点

  • 写入快(O(1))

缺点

  • 读取慢(需要查询多个用户)

方案 3:混合模式(推荐)

  • 普通用户:推模式
  • 大 V 用户(关注者 > 1000):拉模式

3. 数据库设计

  • 用户数据:SQL 数据库(MySQL)
  • 推文数据:NoSQL 数据库(Cassandra)
  • 时间线数据:Redis(缓存)+ Cassandra(持久化)
  • 关注关系:图数据库(Neo4j)或 SQL 数据库

4. 缓存策略

  • 用户信息缓存:Redis,TTL 1 小时
  • 时间线缓存:Redis,TTL 5 分钟
  • 热门推文缓存:Redis,TTL 1 小时

扩展性设计

  • 水平扩展:无状态 API 服务器,可以轻松扩展
  • 数据库分片:按 user_id 分片
  • CDN:静态资源(图片、视频)

案例 2:设计 URL 短链服务

需求分析

功能需求

  • 将长 URL 转换为短 URL
  • 短 URL 重定向到长 URL
  • 统计短 URL 的访问次数

非功能需求

  • 高可用性
  • 低延迟(重定向 < 100ms)
  • 高吞吐量

容量估算

  • 短 URL 生成:100M/天
  • 短 URL 读取:100M × 100 = 10B/天
  • 峰值 QPS
    • 写:100M / 86400 ≈ 1,157 QPS
    • 读:1,157 × 100 ≈ 115,700 QPS

高层设计

用户 → 负载均衡 → API 服务器 → 短链生成服务
                              → 重定向服务
                              → 统计服务

详细设计

1. 短 URL 生成算法

方案 1:哈希 + Base62 编码

import hashlib
import base64

def generate_short_url(long_url):
    hash_value = hashlib.md5(long_url.encode()).hexdigest()
    # 取前 6 个字符
    short_code = base64.b64encode(hash_value[:6].encode()).decode()[:6]
    return short_code

方案 2:自增 ID + Base62 编码

def base62_encode(num):
    chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
    result = []
    while num > 0:
        result.append(chars[num % 62])
        num //= 62
    return ''.join(reversed(result))

2. 数据库设计

URL 映射表

  • short_code (主键)
  • long_url
  • created_at
  • expiration_date

统计表

  • short_code (主键)
  • click_count
  • last_accessed_at

3. 缓存策略

  • URL 映射缓存:Redis,TTL 1 年
  • 热门 URL:Redis,TTL 1 小时

扩展性设计

  • 数据库分片:按 short_code 的第一个字符分片
  • 缓存层:Redis 集群
  • CDN:静态重定向页面

案例 3:设计分布式缓存

需求分析

功能需求

  • 存储键值对
  • 支持 TTL(过期时间)
  • 高可用性

非功能需求

  • 低延迟(< 1ms)
  • 高吞吐量
  • 可扩展性

高层设计

客户端 → 一致性哈希 → 缓存节点

详细设计

1. 一致性哈希

  • 将节点和键映射到哈希环
  • 键存储在顺时针方向的第一个节点

优点

  • 节点增减时,只需要迁移少量数据
  • 负载均衡

2. 数据复制

  • 主从复制:每个节点有多个副本
  • 故障转移:主节点故障时,从节点接管

3. 缓存策略

  • LRU:最近最少使用
  • LFU:最不经常使用
  • TTL:基于过期时间

案例 4:设计聊天系统

需求分析

功能需求

  • 一对一聊天
  • 群聊
  • 消息推送
  • 在线状态

非功能需求

  • 低延迟(消息传递 < 100ms)
  • 高可用性
  • 消息持久化

高层设计

客户端 → WebSocket 服务器 → 消息队列 → 消息存储
                          → 推送服务

详细设计

1. 消息传递

  • WebSocket:实时双向通信
  • 消息队列:解耦和削峰
  • 消息存储:Cassandra(按时间分区)

2. 在线状态

  • Redis:存储在线用户
  • 心跳机制:定期更新在线状态

3. 消息推送

  • APNs(iOS)
  • FCM(Android)
  • Web Push(Web)

总结

系统设计案例展示了:

  1. 需求分析:明确功能和非功能需求
  2. 容量估算:估算用户量、QPS、存储量
  3. 架构设计:高层设计和详细设计
  4. 技术选型:选择合适的数据库、缓存、消息队列
  5. 扩展性设计:考虑系统的扩展性

通过学习和实践这些案例,你将能够设计出优秀的系统。


系统设计部分的学习就到这里了!接下来,让我们学习行为面试,这是面试中的重要环节。

搜索