解剖Twitter 【2】三段论
作者 邓侃 | 2010-03-08 07:28 | 类型 云计算, 互联网, 行业动感 | 9条用户评论 »
系列目录 Twitter系统结构分析【2】三段论 网站的架构设计,传统的做法是三段论。所谓“传统的”,并不等同于“过时的”。大型网站的架构设计,强调实用。新潮的设计,固然吸引人,但是技术可能不成熟,风险高。所以,很多大型网站,走的是稳妥的传统的路子。 2006年5月Twitter刚上线的时候,为了简化网站的开发,他们使用了Ruby-On-Rails工具,而Ruby-On-Rails的设计思想,就是三段论。 1. 前段,即表述层(Presentation Tier) 用的工具是Apache Web Server,主要任务是解析HTTP协议,把来自不同用户的,不同类型的请求,分发给逻辑层。 2. 中段,即逻辑层 (Logic Tier)用的工具是Mongrel Rails Server,利用Rails现成的模块,降低开发的工作量。 3. 后段,即数据层 (Data Tier) 用的工具是MySQL 数据库。 先说后段,数据层。 Twitter 的服务,可以概括为两个核心,1. 用户,2. 短信。用户与用户之间的关系,是追与被追的关系,也就是Following和Be followed。对于一个用户来说,他只读自己“追”的那些人写的短信。而他自己写的短信,只有那些“追”自己的人才会读。抓住这两个核心,就不难理解 Twitter的其它功能是如何实现的[7]。 围绕这两个核心,就可以着手设计Data Schema,也就是存放在数据层(Data Tier)中的数据的组织方式。不妨设置三个表[8], 1. 用户表:用户ID,姓名,登录名和密码,状态(在线与否)。 2. 短信表:短信ID,作者ID,正文(定长,140字),时间戳。 3. 用户关系表,记录追与被追的关系:用户ID,他追的用户IDs (Following),追他的用户IDs (Be followed)。 再说中段,逻辑层。 当用户发表一条短信的时候,执行以下五个步骤, 1. 把该短信记录到“短信表” 中去。 2. 从“用户关系表”中取出追他的用户的IDs。 3. 有些追他的用户目前在线,另一些可能离线。在线与否的状态,可以在“用户表”中查到。过滤掉那些离线的用户的IDs。 4. 把那些追他的并且目前在线的用户的IDs,逐个推进一个队列(Queue)中去。 5. 从这个队列中,逐个取出那些追他的并且目前在线的用户的IDs,并且更新这些人的主页,也就是添加最新发表的这条短信。 以上这五个步骤,都由逻辑层(Logic Tier)负责。前三步容易解决,都是简单的数据库操作。最后两步,需要用到一个辅助工具,队列。队列的意义在于,分离了任务的产生与任务的执行。 队列的实现方式有多种,例如Apache Mina[9]就可以用来做队列。但是Twitter团队自己动手实现了一个队列,Kestrel [10,11]。Mina与Kestrel,各自有什么优缺点,似乎还没人做过详细比较。 不管是Kestrel还是Mina,看起来都很复杂。或许有人问,为什么不用简单的数据结构来实现队列,例如动态链表,甚至静态数组?如果逻辑层只在一台服务器上运行,那么对动态链表和静态数组这样的简单的数据结构,稍加改造,的确可以当作队列使用。Kestrel和Mina这些“重量级”的队列,意义在于支持联络多台机器的,分布式的队列。在本系列以后的篇幅中,将会重点介绍。 最后说说前段,表述层。 表述层的主要职能有两 个,1. HTTP协议处理器(HTTP Processor),包括拆解接收到的用户请求,以及封装需要发出的结果。2. 分发器(Dispatcher),把接收到的用户请求,分发给逻辑层的机器处理。如果逻辑层只有一台机器,那么分发器无意义。但是如果逻辑层由多台机器组成,什么样的请求,发给逻辑层里面哪一台机器,就大有讲究了。逻辑层里众多机器,可能各自专门负责特定的功能,而在同功能的机器之间,要分摊工作,使负载均衡。 访问Twitter网站的,不仅仅是浏览器,而且还有手机,还有像QQ那样的电脑桌面工具,另外还有各式各样的网站插件,以便把其它网站联系到Twitter.com上来[12]。因此,Twitter的访问者与Twitter网站之间的通讯协议,不一定是HTTP,也存在其它协议。 三段论的Twitter架构,主要是针对HTTP协议的终端。但是对于其它协议的终端,Twitter的架构没有明显地划分成三段,而是把表述层和逻辑层合二为一,在Twitter的文献中,这二合一经常被称为“API”。 综上所述,一个能够完成Twitter基本功能的,简单的架构如Figure 1 所示。或许大家会觉得疑惑,这么出名的网站,架构就这么简单?Yes and No,2006年5月Twitter刚上线的时候,Twitter架构与Figure 1差距不大,不一样的地方在于加了一些简单的缓存(Cache)。即便到了现在,Twitter的架构依然可以清晰地看到Figure 1 的轮廓。 Figure 1. The essential 3-tier of Twitter architecture Reference, [7] Tweets中常用的工具 (http://www.ccthere.com/article/2383833) | |
雁过留声
“解剖Twitter 【2】三段论”有9个回复
受益匪浅。有一个问题就是,如果离线的人上线的话,如何去更新到发送的短信?
“如何去更新到发送的短信?”
你是说,如何更新已经发出的短信?
一旦发出,估计是改不了了。如果改的话,无异于发了一条新的短信。
哦,不是这个意思,我是说如果某一个人发了一条短信(短信是否就是发布的内容?),而在发送的时候我(我follow了发布人)恰好不在线(这个在线是否是指通过帐号登录到twitter?),内部是怎样去收取之前发送的短信?
这个问题问得好,后续章节中有详细解答。呵呵
其实 解剖Twitter 【1】万事开头易 里面回答过wenlujon的问题:
当用户打开自己的个人空间时,Twitter先查阅Following表,找到所有following的作者的ID。然后去数据库读取每一位作者最近写的短信。汇总后按时间顺序显示在用户的个人主页上。
其中有个词“最近”,还需要进一步解释:
就是从我所有following的人的短信表里,查找所有创建时间>=我上次在线时,server最后一次为我更新个人主页的时间
应该还有个字段isread吧?
回复Sarlmolapple,
不一定需要isread字段。
设想一个读者,following几个作者。这个读者经常上网看twitter,而他follow的作者不经常写。
这样,假如T1时间,这个读者上网后,看到几条新帖子。T2时间,他再次上网,假如所有的帖子他都已经看过,那么是不是在他的主页上,就应该不显示任何帖子呢?显然不是。
所以设置isread,不一定有意义。
首先赞一个,文章分析的很到位,但对于”例如Apache Mina[9]就可以用来做队列”,不敢苟同。Mina只是一个基于Java Nio的异步网络框架,并非一个队列服务。Apache的开源的队列是ActiveMQ