从 0 开始设计 Twitter 系统架构
Twitter 是全球最大的社交网络之一,如果让我们从 0 开始设计 twitter 的系统架构,该怎么做呢?有哪些服务是必须的?有哪些点需要提前考虑?这篇文章简单介绍了设计类 twitter 系统的思路并在最后给出了参考设计。原文:Twitter System Architecture
Twitter 是全球领先的在线社交网络服务,用户可以在这里发布和阅读被称为“推文(tweets)”的短消息。在系统架构设计面试过程中,当被问及如何设计 Twitter 时,大多数候选人都会将其设计为单体服务。然而,将 Twitter 这样的大型服务设计为单体,表明候选人缺乏设计分布式系统的经验。从微服务甚至 lambda(或函数)的角度来设计分布式系统在今天是很正常的选择。目前的趋势是,没有人会将新服务设计为单体,公司正逐渐将其庞大的单体服务转换为一组微服务。因此,候选人应该以微服务的方式设计 Twitter。
功能需求
用户可以发布或分享新的推文(tweet)
每条推文最多不超过 140 个字符
用户可以删除推文,但不能更新/编辑发布的推文(写操作)
户可以标记喜欢的推文(写操作)
用户可以关注或取消关注另一个用户(写操作),关注一个用户意味着用户可以看到其他用户在他的时间线上的推文
可以生成两种类型的时间线(读操作),用户时间线由他最后 N 个推文组成,主页时间线由他正在关注的用户的热门推文按照时间降序生成
用户可以根据关键字搜索推文(读操作)
用户需要有一个帐户来发布或读取推文(暂时使用外部身份服务)
用户可以注册和删除帐户
Twitter 支持包含文字和图片/视频的推文,但在我们当前的设计中,将只支持文本
分析/监视服务,以确定其负载、运行状况和功能
分析还可为用户提供关于关注谁、推文通知、热门话题、推送通知和分享推文的意见或建议
非功能需求
服务的高可用是最重要的需求,这意味着用户可以在自己的主页时间线上阅读推文,而感受不到任何停顿
生成时间线的时间最长不得超过半秒
不需要强一致性,只需要最终一致性,可以使用关键词数据库用于搜索基于关键词的推文
随着用户和推文的增加,系统负载也在增加,因此系统应该具有可伸缩性
持久化用户数据
现在我们来做一些计算。
日活跃用户平均请求/天 = 150M*60/86400 = 100k /秒
峰值用户 = 平均并发用户* 3 = 300k
三月内最大峰值用户数 = 峰值用户数*2 = 600k
读 QPS = 300k
写 QPS = 5k
twitter 服务的概要设计
由于系统的复杂性,可以将其划分为若干个服务,其中包括若干个微服务。
推文服务(Tweet service)
用户时间线服务(User timeline service)
扇出服务(Fanout Service)
主页时间线服务(Home timeline service)
社交网络服务(Social graph service)
搜索服务(Search service)
下面是 twitter 服务中不同逻辑组件或微服务架构。
twitter 服务的详细设计
所有微服务都可以被称为模块。
1. 推文服务(Tweet service)
接收用户推文,转发用户推文到关注者时间线和搜索服务
存储用户信息,推文信息,包括用户的推文数量以及用户喜欢的状态
包括应用服务器、分布式的内存缓存以及后端的分布式数据库,或者使用直接由数据库(例如 Redis)支持的内存缓存
然后我们看一下 tweet 服务的数据库表结构。
用户(Users)表包含用户的所有信息,推文(Tweet)表存储所有推文,Favorite_tweet 表存储了喜欢的推文记录,也就是说,每当用户喜欢一条推文时,就会在 Favorite_tweet 表中插入一条记录。
2. 生成唯一的推文 Id
当用户调用 postTweet()时,调用会发送给应用服务器。应用服务器为该推文生成一个唯一的 id,同样的机制也可以用来为推文生成短 URL。另一个方式是基于应用服务器的 UUID(Universally unique identifier)。推文 ID 生成后,应用服务器将该推文插入分布式缓存和数据库的 tweet 表中。由于需要在执行推文的创建/更新/删除操作的同时更新缓存和数据库,所以我们使用缓存透写机制。
3. 可扩展性设计
我们可以将分布式缓存和数据库划分为多个分区和副本。基于用户 ID 分片基于推文 ID 分片基于用户 ID 和推文 ID 进行两层/级别分片
4. 社交网络服务(Social graph service)
实现 Following API,跟踪用户之间的关注关系
包括应用服务器、分布式缓存和数据库
用于存储用户关系的数据库表结构
Following API
将被关注用户的时间线异步合并到关注者的信息事件流中
取消关注一个用户后,从关注者的事件流中异步删除他的推文
异步的从信息事件流中挑选推文
之所以需要异步操作,是因为这个过程比较慢,而用户在关注和取消关注其他用户时,希望很快得到反馈
异步的缺点是用户在取消关注后,如果刷新信息事件流,会发现这些信息仍然存在,但最终它们会被删除
用户时间线服务(User timeline service)
返回用户的时间线,以降序排列的方式包含用户所有推文。此服务可用于主页时间线或其他用户的时间线。
该服务包括应用服务器和分布式内存缓存,但没有涉及该服务的数据库。
用户时间线是使用包含用户推文链接列表的数据结构设计的
当用户发布一条推文时,tweet 服务调用用户时间线服务,将该推文插入到用户时间线的推文列表顶部,运算复杂度为 O(1)。
此外,分析仪表板可以配置参数 K,表示可以保留的推文个数,K 默认为 1000,表示保留用户时间线轴中的最后 K 条推文。
在用户时间线列表中,推文按 creationTime(创建时间)降序存储。当用户时间线列表达到最大 K 条推文时,最老的条目将被删除。
6. 扇出服务(Fanout Service)
将新推文转发到搜索和主页时间线服务,以及其他组件/微服务,比如趋势服务或通知服务
由多个分布式队列组成
当用户发送一条推文消息时,该服务把消息放入推文队列,社交网络服务必须获得用户的关注者列表,并在第二组队列中插入尽可能多的消息。对于名人用户来说,他们拥有非常多的粉丝,其粉丝数甚至超过了每次推送的阈值。那么,如何处理这个问题呢?
该服务是一个先进先出的任务队列列表,处理共享相同列表的任务,并在完成后反馈给队列服务器。队列服务器是异步任务的重要组成部分,其执行的任务可能不会立即收到响应,但却能够保证最终一致性。
7. 主页时间线服务(Home timeline service)
显示用户的主页时间线
包括来自其他关注的用户的推文,按照推文的 creationTime(创建时间)降序显示。
其设计类似于用户时间线服务。
但是比用户时间线服务稍微复杂一点,因为用户将插入最新的推文,并且当推文数量超过 K 值时需要删除最老的推文,如果用户关注了很多其他用户,服务还需要一些机制来给不同关注用户的推文赋予不同的权重。
8. 搜索服务(Search service)
为用户提供搜索查询服务
扇出服务将推文传递给搜索服务
Ingester(或 ingestion engine):给推文标记上许多标签、术语或关键字。例如这条推文:“我想成为像亚马逊的杰夫·贝索斯一样非常富有的人”,它会过滤掉那些在搜索中没有用的词。除了杰夫·贝索斯(Jeff Bezos)和亚马逊(Amazon),所有其他词都将被丢弃。Ingester 可以通过配置或数据库获得词汇表。
一个叫做“词根提取(stemming)”的过程对剩下的单词进行分析,以确定它们的词根。Stemming 是处理词干、词根或词根的词形变化(或派生)的过程。因此,会在数据库中保存一个查找表。这种方法的优点是可以简单、快速、轻松的处理异常。缺点是新的或不熟悉的单词即使是完全符合规则的,也不会被处理。
传递到搜索索引
搜索索引微服务将创建反向索引,并存储从内容(如单词)到其所在文档或一组文档中的位置的术语映射索引,在我们的例子中,这是一个或一组推文。
Blender 服务:在 twitter 平台上为用户提供搜索查询。当请求搜索查询时,首先确定搜索条件,然后进行词干分析,最后使用词根在术语的倒排索引上运行搜索查询。
9. 照片和视频
使用 NoSQL 数据库
媒体文件(使用文件系统)
数据表格式
twitter 的网络
twitter 的最终详细设计
系统设计
数据架构
参考文档
你好,我是俞凡,在 Motorola 做过研发,现在在 Mavenir 做技术工作,对通信、网络、后端架构、云原生、DevOps、CICD、区块链、AI 等技术始终保持着浓厚的兴趣,平时喜欢阅读、思考,相信持续学习、终身成长,欢迎一起交流学习。微信公众号:DeepNoMind
版权声明: 本文为 InfoQ 作者【俞凡】的原创文章。
原文链接:【http://xie.infoq.cn/article/d37201e5268276777cf8970de】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论