|
4 years ago | |
---|---|---|
.. | ||
README-zh-Hans.md | 5 years ago | |
README.md | 4 years ago | |
twitter.graffle | 8 years ago | |
twitter.png | 8 years ago | |
twitter_basic.graffle | 8 years ago | |
twitter_basic.png | 8 years ago |
注意:这个文档中的链接会直接指向系统设计主题索引中的有关部分,以避免重复的内容。你可以参考链接的相关内容,来了解其总的要点、方案的权衡取舍以及可选的替代方案。
设计 Facebook 的 feed 与设计 Facebook 搜索与此为同一类型问题。
搜集需求与问题的范围。 提出问题来明确用例与约束条件。 讨论假设。
我们将在没有面试官明确说明问题的情况下,自己定义一些用例以及限制条件。
普遍情况
时间轴功能
搜索功能
如果你需要进行粗略的用量计算,请向你的面试官说明。
tweet_id
- 8 字节user_id
- 32 字节text
- 140 字节media
- 平均 10 KB便利换算指南:
列出所有重要组件以规划概要设计。
深入每个核心组件的细节。
我们可以将用户自己发表的推特存储在关系数据库中。我们也可以讨论一下究竟是用 SQL 还是用 NoSQL。
构建用户主页时间轴(查看关注用户的活动)以及推送推特是件麻烦事。将特推传播给所有关注者(每秒约递送 6 万条推特)这一操作有可能会使传统的关系数据库超负载。因此,我们可以使用 NoSQL 数据库或内存数据库之类的更快的数据存储方式。从内存读取 1 MB 连续数据大约要花 250 微秒,而从 SSD 读取同样大小的数据要花费 4 倍的时间,从机械硬盘读取需要花费 80 倍以上的时间。1
我们可以将照片、视频之类的媒体存储于对象存储中。
向你的面试官告知你准备写多少代码。
如果我们用 Redis 作为内存缓存,那可以用 Redis 原生的 list 作为其数据结构。结构如下:
tweet n+2 tweet n+1 tweet n
| 8 bytes 8 bytes 1 byte | 8 bytes 8 bytes 1 byte | 8 bytes 8 bytes 1 byte |
| tweet_id user_id meta | tweet_id user_id meta | tweet_id user_id meta |
新发布的推特将被存储在对应用户(关注且活跃的用户)的主页时间轴的内存缓存中。
我们可以调用一个公共的 REST API:
$ curl -X POST --data '{ "user_id": "123", "auth_token": "ABC123", \
"status": "hello world!", "media_ids": "ABC987" }' \
https://twitter.com/api/v1/tweet
返回:
{
"created_at": "Wed Sep 05 00:37:15 +0000 2012",
"status": "hello world!",
"tweet_id": "987",
"user_id": "123",
...
}
而对于服务器内部的通信,我们可以使用 RPC。
REST API:
$ curl https://twitter.com/api/v1/home_timeline?user_id=123
返回:
{
"user_id": "456",
"tweet_id": "123",
"status": "foo"
},
{
"user_id": "789",
"tweet_id": "456",
"status": "bar"
},
{
"user_id": "789",
"tweet_id": "579",
"status": "baz"
},
REST API 与前面的主页时间轴类似,区别只在于取出的推特是由用户自己发送而不是关注人发送。
REST API:
$ curl https://twitter.com/api/v1/search?query=hello+world
返回结果与前面的主页时间轴类似,只不过返回的是符合查询条件的推特。
根据限制条件,找到并解决瓶颈。
重要提示:不要从最初设计直接跳到最终设计中!
现在你要 1) 基准测试、负载测试。2) 分析、描述性能瓶颈。3) 在解决瓶颈问题的同时,评估替代方案、权衡利弊。4) 重复以上步骤。请阅读「设计一个系统,并将其扩大到为数以百万计的 AWS 用户服务」 来了解如何逐步扩大初始设计。
讨论初始设计可能遇到的瓶颈及相关解决方案是很重要的。例如加上一个配置多台 Web 服务器的负载均衡器是否能够解决问题?CDN呢?主从复制呢?它们各自的替代方案和需要权衡的利弊又有什么呢?
我们将会介绍一些组件来完成设计,并解决架构扩张问题。内置的负载均衡器将不做讨论以节省篇幅。
为了避免重复讨论,请参考系统设计主题索引相关部分来了解其要点、方案的权衡取舍以及可选的替代方案。
消息输出服务有可能成为性能瓶颈。那些有着百万数量关注着的用户可能发一条推特就需要好几分钟才能完成消息输出进程。这有可能使 @回复 这种推特时出现竞争条件,因此需要根据服务时间对此推特进行重排序来降低影响。
我们还可以避免从高关注量的用户输出推特。相反,我们可以通过搜索来找到高关注量用户的推特,并将搜索结果与用户的主页时间轴合并,再根据时间对其进行排序。
此外,还可以通过以下内容进行优化:
我们还可以考虑优化 SQL 数据库 来解决一些瓶颈问题。
内存缓存能减小一些数据库的负载,靠 SQL Read 副本已经足够处理缓存未命中情况。我们还可以考虑使用一些额外的 SQL 性能拓展技术。
高容量的写入将淹没单个的 SQL 写主从模式,因此需要更多的拓展技术。
我们也可以考虑将一些数据移至 NoSQL 数据库。
是否深入这些额外的主题,取决于你的问题范围和剩下的时间。
请参阅「安全」一章。
请参阅「每个程序员都应该知道的延迟数」。