1-介绍

经常被要求写技术方案, 通过 twitter 来说明如何做一个系统设计的方案.

1)-如果是面试, 一般会用如下的评分标准:

  1. 可行解: Work Solution 25%
  2. 特定问题: Special Case 20%
  3. 分析能力: Analysis 25%
  4. 权衡: TradeOff 15%
  5. 知识储备: Knowledge Base 15%

2)-4s 分析

  • Scenario: 场景, 最好用 领域语言-业务通用语言描述清楚 需要设计哪些功能, 要设计 多牛的系统

    • Ask / Features / QPS / DAU / Interfaces
  • Services: 服务

    • 把大的服务拆分为小服务
    • Split / Application / Module
  • Storage: 存储

    • 存储
    • Schema/Data/SQL/NoSQL/File System
  • Scale: 处理可能遇到的问题.

    • Sharding / Optimize / Special Case

2-Twitter Design Post tweet

2-1 Scenario

先问或者自己想, 2个问题.

  • 设计哪些功能
  • 多大的访问量: DAUMAU ,一般用月活而不是注册用户来代表一个网站的用户数

1)-Step1 列出所有 Features

  • Register/Login
  • User Profile Display/Edit
  • Upload Image/Video/Audio *
  • Search *
  • Post / Share a tweet
  • Timeline / News Feed
  • Follow / Unfollow a user

2)-Step2: Sort , 列出核心功能, 尤其是面试,不可能这么短的时间什么都设计, 不过也可以尝试一下.

下面是一个例子:

  • Post a Tweet
  • Timeline
  • News Feed
  • Follow / Unfollow a user
  • Register / Login

3)-并发

并发能力: - Avg User = 日活跃 x 每个用户的平均请求次数 / 一天多少秒 = 150M x 60 / 86400 = 100k - 峰值 Peak = Avg x 3 = 300K - 如果考虑到快速增长, 最好再 x 2 = 600k

  • 读的 Qps = 600k
  • 写的 Qps = 10k

当今的硬件考虑数据库, 这个取决于具体选型,有一些实力特别强劲的:

  • 一台 Web Server : 1000Qps
  • 一台 Db: 1k - 10k Qps , 设计的是否好非常关键.
  • 一台 NoSql: 10k - 100k Qps , 设计的好也非常关键.
  • 一台 Memcached : 大概是 1M

2-2 Service

将大系统拆分为小服务.

  1. Replay 重放需求: 过一下需求, 为每个需求都要增加一个服务
  2. Merge 归并需求: 归并相同的服务

1)-什么是服务?

  • 逻辑处理的集合

  • 同一类的问题的逻辑 处理归并到同一个 Servivce

  • 整个 System 细分为若干个小的 Service

  • Tweet Service

    • Post a tweet
    • News Feed Timeline
  • User Service

    • Register / Login
  • Relation Service

    • follow / unfollow
  • Media Service

    • Upload Image / Upload Video

2-3 Storage

1)-Step1 为一个 service 选择一个合适的 Storage

  • 数据库系统 Database

    • 关系型数据库: SQL Database
      • 用户信息 User Table
    • 非关系型数据库: NoSQL Database
      • 推文: Tweets
      • 社交图谱: Social Graph (followers)
  • 文件系统 File System:

    • 图片,视频 Media Files
  • 缓存系统

一个观点:

  • 程序 = 算法 + 数据结构
  • 系统 = 服务 + 数据存储

2)-Step2 设计 Schema

  • UserRoot

    • UserId
    • UserCore: username& password & birth & gender
    • UserDetail: …
  • FriendFollowRoot

    • from_user_id
    • to_user_id
  • TweetRoot:

    • user_id
    • content
    • created_at

2-4-New Feed 系统

所有朋友,关注的对象 发的信息的集合.

Pull And Push

  • Pull : 用户查看 News Feed 的时候, 获取每个好友的前 K 条, 然后进行多路归并.

    • 归并排序, 基于内存, 时间一般可以忽略
    • 时间成本在于 查询 NTable , 核心是在于 关注的用户个数. 这次查询.
      • 可以用 searchAfter : 不要用传统的 sort 优化单次查询
      • 可以用 多线程优化多次
  • Push:

    • 为每个用户创建一个 List 去存储他的 NewFeed 信息 ;
    • 也就是写扩散: 写的时候去写 他所有的 followee ;
    • 但是读的时候丛之前 N 次读减少为 一次读 ;
  • Push + Pull : 从 N 次读变为 少数次读 ;

目前热门的 Social App 的模型:

  • Facebook - Pull
  • Instagram - Push + Pull
  • Twitter - Pull
  • 朋友圈 - ?

2-5-前3个的总结

上面搞完之后就是 一个基本可行的方案.

  • Scenario 场景:

    • 和面试官讨论 ;
    • 搞清楚需要设计哪些功能 ;
    • 分析出所设计的系统大概所需要支持的 Concurrent Users / QPS / Memory / Storage ;
  • Service 服务:

    • 合并需要设计功能, 相似的功能整合为一个 Service
  • Storage 存储:

    • 对每个 Service 选择合适的存储结构
    • 细化数据表单
    • 画图 展示数据存储和读取的流程

上面3个得到 是一个 Workable Solution 而不是一个 Perfect Solution

2-6 Scale

Step1 - Optimize

  • 解决设计缺陷: Solve Problems
    • Pull vs Push
  • 更多的功能设计: More Features
    • Like | Follow & UnFollow | Ads
  • 特殊情况:
    • 明星搞挂微博, 僵尸粉

Step2 - Maintenance

  • 鲁棒性 Robust
    • 一台服务器挂了怎么办
  • 扩展性 Scalability :
    • 如果有流量暴增, 如何扩展

1)-Pull 的问题

  • 使用 Cache:
    • Cache 的就要考虑 How much, 所有的, 最近 1000 天
    • 过期策略

2)-Push 的问题

  • 磁盘问题基本可以忽略: Disk is cheap

  • 不活跃用户, InActive Users

    • 粉丝排序 Rank followers by weight (for example, last active time)
    • 没有登录用户不推送, 然后登录的时候 异步的去同步
  • 粉丝数目 follower >> 关注数目 following

    • Lady gaga 问题 ?
    • 无解 ? 完全切回 Pull ?
    • Push + Pull 可解

3)-明星用户

  • 明星用户离线计算, is_super , 明星用户发布的东西配的上缓存.

2-7 选择

既然 Push 的问题也要用 Pull 的思路去解, 那么为什么要用 Push .

什么时候用 Push ?

  • 实时性要求不高, 简单,想要偷懒
  • 双向好友关系,特殊,比如说朋友圈, 一般就用 push
  • 非常省钱

什么时候用 Pull ?

  • 有明星问题
  • 资源充足, 考虑用 redis

2-8 What’s more

1)-Follow && UnFollow 的实现

人和人的关系:

  • Rdb 做的话
  • graphDb 做的话

异步的构建优化:

  • 批处理 + 合并
  • Mq

2)-如何存储 Likes

  • 同上
  • Rdb 做的话
  • graphDb 做的话

上面2个 一个 人人 , 人物, 从更全局的角度来看, 都不是 核心域,真正决定留存,北极星指标的还是搜推.

  • 所以直接考虑全部 通用化中台, 底层 索引外置到 graphDb 是非常好的选择.