twitter系統架構分析
(一)twitter的核心業務
twitter的核心業務,在于following和be followed:
(1)following-關注
進入個人首頁,會看到你follow的人發表的留言(不超過140個字),這是following的過程;
(2)followed-被關注
你釋出一條留言,follow你的人将看到這條資訊,這是be followed的過程;
(二)twitter的業務邏輯
twitter的業務邏輯也不複雜
following業務,查follow了哪些人,以及這些人發表的留言;
followed業務,前端js輪詢後端,看follow了的人有沒有新留言,有則更新(更新及時性取決于輪詢時間);
(三)三層架構(three-tier architecture)
網站的架構設計,傳統的做法是三層架構,所謂“傳統”不意味着“過時”,新潮的技術不成熟,傳統的路子更穩健。
(1)表示層(presentation tier):apache web server,主要任務是解析http協定,将請求分發給邏輯層;
(2)邏輯層(logic tier):mongrel rails server,利用rails現成的子產品,降低工作量;
(3)資料層(data tier):mysql;
資料層先來吧:
twitter的核心是(1)使用者;(2)消息;(3)使用者關系;
圍繞這幾個核心,其核心資料的schema設計:
(1)使用者表user
id, name, pass, status, …
(2)消息表msg
msgid, author_id, msg, time, …
(3)使用者關系表relation
id, following_ids, followed_ids
邏輯層:
當使用者釋出消息時,依次執行:
(1)存消息至msg表;
(2)查使用者relation表,找出其followed_ids;
(3)擷取followed_ids中使用者的狀态;
(4)線上的ids,将消息push進一個隊列queue;
(5)queue中的msg,更新ids的首頁;
這裡面要用到隊列,其實作方式有很多種,例如apache mina,twitter團隊自己實作了一個kestrel。
表示層:
表示層的主要職能有2個:
(1)http協定處理(http processor);
(2)分發器(dispatcher);
當然,通路twitter的不僅僅是浏覽器,可能還有手機,由于可能存在其他協定,故可能存在其他processor。
無論如何,架構架構清晰如下:
圖1:架構版本1
(四)cache=cash即緩存等于收入
cache的使用對大型網站架構至關重要,網站響應速度是影響使用者體驗最明顯的因素,而影響響應速度最大的敵人又是磁盤io。
twitter工程師認為,良好體驗的網站平均響應時間應該在500ms左右,理想的時間是200-300ms。
關于cache的使用,是twitter架構的一大看點,帶cache的架構清晰如下:
圖2:帶cache架構版本2
哪裡需要cache?IO越頻繁的地方,越需要cache。
資料庫是IO通路最頻繁處,三大核心表是否有必要放入記憶體中?
twitter的做法是,将表拆分,将其中通路最頻繁的字段裝入cache。
(1)vector cache and row cache即數組cache與行cache
vector cache:新發表消息的msgids,相關作者的ids,這些id的通路頻率很高,存放它們的cache稱為vector cache;
row cache:消息正文的行cache;
記憶體有限的情況下,優先vector cache,實際結果vector cache的命中率是99%,row cache為95%;
(2)fragment cache and page cache
通路twitter的使用者除了網頁(web通道),還有手機(API通道),而後者的比例占總流量的80%-90%。
mysql cache之外,cache的重心會在API通道上。
手機螢幕的主體,是一屏一屏的消息,不妨把整個頁面分割成若幹局部,每個局部對應一些/一條消息,這些就是fragment。
人氣高的作者,緩存其頁面的fragment,可以提高讀取其釋出消息效率,這就是fragment cache的使命。
人氣旺的作者,人們也會通路其首頁,這就是page cache的使命。
實際結果,fragment cache的命中率為95%,page cache為40%。
雖然page cache的命中率低,但由于是通路首頁,其占用的空間是很大的,為了防止兩種cache互相影響,這兩種cache需要部署在不同的實體機器上。
twitter的fragment cache和page cache都是使用的memcached。
(3)http accelerator
web通道的緩存問題也需要解決,分析之後,web通道的壓力主要來自搜尋。
面臨突發事件時,讀者們會搜尋相關資訊,而不會理會這些資訊的作者是不是自己follow的那些人。
為了降低搜尋壓力,可以将搜尋關鍵詞與搜尋内容cache起來,這裡,twitter的工程師使用了varnish。
有趣的是,varnish通常部署在web server外層,先通路varnish,其中沒有先關的内容,才通路web server;
twitter的工程師卻将varnish放在apache web server的内層,原因是他們認為varnish操作複雜,擔心varnish崩潰造成系統的癱瘓,故采用了這種保守型部署方式。
twitter沒有公開varnish的命中率,他們聲稱,使用了varnish之後,整站的負載下降了50%。
(五)抗洪需要隔離
twitter架構的另一大看點是其消息隊列:隔離使用者的操作,将流量高峰攤平。
餐廳客滿時,對于新來的顧客,雖然不能服務,但不是拒之門外,而是讓他們現在休息廳等待。
使用者通路twitter時,接待他的是apache web server,而apache不能接待無限多的使用者。
2009年1月20日,奧巴馬發表就職演說,twitter流量猛增,此時如何是好。
面對洪峰,如何保證網站不奔潰?迅速接納,但推遲服務。
apache收到請求,轉發給Mongrel,由Mongrel負責實際處理,apache則騰出手來,迎接下一位使用者。
但apache能夠接待的使用者數總是有限的,它的并發數受apache能夠容納的工作程序數量,這裡不細究apache内部原理,圖如下:
圖3:apache内部架構
(六)資料流與控制流
快速接納,推遲服務,隻是緩兵之計,目的是讓使用者不至于收到503(service unavailable)。
真正的抗洪能力,展現在蓄洪與洩洪兩個方面:
(1)twitter有龐大的memcached叢集,能大容量蓄洪;
(2)twitter自己的kestrel消息隊列,作為引流洩洪手段,傳遞控制指令(引流和管道);
洪峰到達時,twitter控制資料流,将資料及時疏散到多個機器,避免壓力集中,造成系統癱瘓。
下面舉例說明twitter内部流程,假設有兩個作者,通過浏覽器發消息,一個讀者也通過浏覽器閱讀他們的消息。
圖4:twitter流
(1)登陸apache web server,apache配置設定一個工作程序為其服務,登陸,查id,寫cookie等;
(2)上傳新寫的消息,把作者id,消息等轉發給Mongrel,apache等待Mongrel回複,以便更新作者首頁,将新寫的消息更新上去;
(3)Mongrel收到消息後,配置設定一個msgid,将其與捉着id等緩存到vector memcached上去;
同時,Mongrel讓vector memcached查找作者被哪些人follow,緩存如果沒有命中會去後端mysql查找,并入cache;
讀者ids會傳回給Mongrel,Mongrel把msgid與短信正文緩存至row memcached;
(4)Mongrel通知kestrel消息隊列伺服器,每個作者及讀者都有一個隊列(沒有則建立);
Mongrel将msgid放入讀者的隊列,以及作者本人的隊列;
(5)某一台Mongrel,它可能正在處理某一個id的隊列,就會往傳回該id使用者的首頁上添加上此條資訊;
(6)Mongrel将更新後作者的首頁給前端等待着的apache,apache則傳回浏覽器。
(七)洪峰與雲計算
不細說了,洪峰扛不住時,隻能加機器。
機器哪裡來?租雲計算平台公司的裝置。
當然,裝置隻需要在洪峰時租用,省錢呀(@58沈劍 疑問:twitter怎麼知道什麼時候是洪峰?)。
(八)push與pull的折衷
可以看到,Mongrel的工作流程:
(1)将相關ids放入vector memcached和row memecached就算消息釋出成功,而不負責mysql資料庫的存入;
(2)将相關msgid放入kestrel消息隊列就算消息推送成功;
Mongrel沒有使用任何方式去通知作者、讀者,讓他們重新拉取消息。
上述工作方式,反映了twitter架構設計“分拆”的理念:
(1)将一個完整的流程分拆成獨立工作的子流程,一個工作可以由各個服務負責(三層架構本身是一種分拆);
(2)多機器之間協作,細化資料流與控制流,并強調其分離;
twitter業務流程的分隔,是一種事件驅動式的設計,主要展現在兩個方面:
(1)Mongrel與mysql的分離,前者不直接插手mysql的操作,而委托memcached全權負責;
(2)上傳、下載下傳邏輯分離:隻通過kestrel隊列來傳遞指令;