Contents

一个 Twitter 的负载例子

两个 Twitter 的典型操作:

  • 发布 tweet:用户可以快速推送新消息到所有关注者,平均 4.6k request/sec,峰值约 12k request/sec
  • 主页时间线(Home timeline)浏览:平均 300k request/sec 查看关注对象的最新消息;

普通思路

将新发的 tweet 插入到全局 tweets 集合中。当用户查看时间线,先查找所有该用户关注的所有关注对象,根据时间排序,合并所有关注对象的消息。SQL 如下:

SELECT tweets.*, users.* FROM tweets
JOIN users ON tweets.sender_id = users.id
JOIN follows ON follows.followee_id = users.id
WHERE follows.follower_id = current_user_id

难点:每个用户会关注很多人,也会被很多人关注。采用传统的多表 join 查询在后续中的读取中必然的会造成对 tweets 表的巨大压力:维护 sender_id 列的索引也是一个巨大的成本,且区分度可预见性的不会太高,这就导致以上查询会扫描表的大部分行。

增加一个缓存

对每个用户维护一个时间线缓存,如下图所示,

/images/twitter-cache.png

用户新发 tweet 消息,查询关注者,将 tweet 插入到关注者的时间线缓存中。

给每一个用户维护一个队列,因为已经预先给每个用户将结果取出,访问的时候性能将会得到一定的保障;

一些结论

方法 1 进行全表的查询,读的压力会很大;

通过方法 2,在发布的时候多做一些工作,来减少读的压力;

说一下 Twitter 最后的做法,方法 2 被稳定实现,但是 Twitter 倾向于结合两种方法。

  1. 大多数普通用户(关注者不是超级数量级的)新发 tweet 消息采用第 2 种方法,

  2. 针对超多关注者的用户,使用方法 1,其推文被单独提取,根据用户的关注列表,在读取时与用户的时间线进行合并。

还有手段可以完成,进行优化:

  • 根据用户的关注对象数量采取不同的推送策略;
  • 针对关注对象特别多的用户的时间线,采用延时消息进行推送;
  • 优先保证超多关注者的用户推送准确性;

一个细微的小观察,会发现,无论是 Twitter,还是微博,查看时间线的推文都并非严格按照时间线进行排序的,可见为了维护推文的最终可达性(最终一致性),里面也是可能采用了类似方法 2 的优化。