Twitter如何缓存时间线信息?
尝试理解Twitter的内部结构
前方入口
在类似Twitter的微博服务中,用户的发帖数量很大,特别是在时间轴周围,仅仅使用关系型数据库来读写数据已经不能满足大规模需求。
因为在互联网上我发现了一些Twitter员工对于架构进行解释的文章和视频,所以我想总结一下Twitter是如何缓存时间线的(包括猜测)。
推特的表结构
単純なTwitterのテーブル定義をRDBで定義すると以下のようになると思います。
推文
-
- id
-
- user_id
-
- contents
- tweet_at
追随者
-
- source_user_id
- destination_user_id
用户
-
- id
- user_name
时间轴
-
- user_id
-
- tweet_id
- seq
时间线不仅仅是简单的SQL聚合
在Twitter上,每個用戶都可以發布推文,並可以關注其他用戶。
用户可以在自己的主页时间线上浏览他们关注的人的推文,并且如果进入相关用户的个人资料页面,他们可以浏览用户过去发表的推文列表和用户的时间线。
如果是简单的社交网络服务,你可以使用SQL查询来获取正在关注的用户的ID,并获取指定用户ID在过去某个时间段内发表的推文,这样就可以完成时间线。然而,事情并不那么简单。
如果一个拥有数千名用户关注的人进行汇总统计,会变得很重,并且现实情况下需要进行必要的筛选。另外,还需要满足在主页时间线中插入推荐的推文和广告推文等要求。因此,时间线需要一个单独的表格。
Twitter采用的是PUSH基础架构,当关注的用户发推时,直接写入各个时间线,而不是使用PULL基础架构在获取时进行聚合。
尽管有点偏离这次的主题,但除此之外,貌似还有一些人故意重叠地在关注已关注之人的名单上,并关注着某些人。
在应用程序层上来回切换时间轴是非常昂贵的。
使用Twitter的时候,我认为有时可能会滚到时间线的底部。虽然看起来像是无限滚动,但时间线似乎有一个长度限制。主页时间线可能只能显示300条推文之类的吧。
对于一般用户来说,很少有想要重新呈现一周前的主页时间线的场景。如果想要查看关注的人过去发布的内容,可以通过搜索或查看相关用户的用户时间线来确认。
おすすめや広告などの差込をタイムラインに行うにあたって、差込や入れ替えを愚直にWebアプリのレイヤーでやると
-
- 从时间线表中提取user_id的数据
-
- 插入和替换tweet_id并删除
- 使用事务完全替换timelines表中的user_id数据
我认为会变成。
然而,在像Twitter这样用户数量众多、实时性要求高的服务中,这种操作相对较昂贵。它不是以类似于RDB的高通用性的表结构进行存储,而是利用定制化的Redis上的特殊用途数据结构来表示。
哈普洛(Haplo):在Redis中实现混合列表(Hybrid List)和B-Tree(B树)。
据公开信息,Twitter正在努力将其在内存缓存存储中使用的Memcached+Redis迁移到Pelikan。
除了时间线,Memcached被广泛使用,而时间线则使用Redis。我们自行开发了整合了Memcached和Redis的Pelikan,使得除了时间线外,其他部分都可以相对容易地迁移到Pelikan上。在计划将时间线加入时,负责缓存方面的人似乎已经被解雇了。。。
Pelikan是一个开源项目,最初在GitHub的Twitter下维护,但由于维护者失去权限,所以已经迁移到了pelikan-io。最近有一次在RustConf上发布了关于从C++部分迁移到基于Rust的代码的消息。
时间轴使用的是自定义的Redis,而不是原生Redis,看起来是使用了Haplo。作为数据结构,增加了Hybrid List和BTree。BTree也被用作RDB的索引。
我认为原因可能是,它们将古老版本的Redis进行了分叉,并且可能是因为Redis方面不想设计支持自定义数据结构(尤其是B树)的常规Redis,所以它不支持这些数据结构。
创建混合列表的动机是压缩效率和性能。
时间轴主要使用混合列表进行操作。
Redis是内置的。
-
- ziplist
- 連結リスト
目前支持的有ziplist和连接列表,因此将它们合并称为混合列表,即Hybrid List。
Twitter的时间线基本上是由一系列tweet_id组成的集合。然而,在链表中,它可能有一些不利的结构。如果内容部分相比指针来说足够大的话,我认为可以忽略指针部分,因为tweet_id是一个ID,与指针的差异很小,可能存在优化的空间。
根据我了解,有很多名人在使用自己的简单ziplist时,如果他们的关注者很多,他们的推文会被发布在很多人的时间线上,这可能导致内存不足等问题。
其他表演方面的策略和费用方面的创新。
由于Redis是内存数据存储,因此准备所有注册用户的时间线会增加成本负担。实际上,他们似乎根据最近登录情况来改变缓存策略。
据说在发布推文时,时间线上有个队列,当名人发推文时,时间线更新会出现问题。但是,似乎还有其他缓解此问题的措施。
这片区域的想像成分较多,但是我找到了一个称为”Celebrity Cluster”的视频,如果我当初创建了Twitter的话,可能会给拥有一定数量粉丝的人添加标记,并改变他们进入队列的速度或进行特殊操作。事实上,Twitter每天对关注人数有限制,可能是为了防止突然出现大量的机器人关注名人。
最终、最后、最后的
这个Redis的文档可能有一篇关于如何建立Twitter克隆的文章,尽管有点旧了,但读一读可能也挺有趣的。
我努力阅读了文章和观看了视频,但可能会有一些遗漏,如果有错误,请指正。
请参考以下资源。
Scaling Redis at Twitter, 2014
“Cache à la carte: a framework for in-memory caching” by Yao Yue, 2015
Using Redis at Scale at Twitter – by Rashmi Ramesh of Twitter – RedisConf17 -, 2017
RustConf 2021 – Whoops! I Rewrote It in Rust by Brian Martin
Pelikan
Timelines at Scale
Real-Time Delivery Architecture at Twitter