原文地址:http://blog.163.com/xychenbaihu@yeah/blog/static/1322296552013430114959121/
之前在網上看到關於Twitter、Sina以及騰訊微薄的一些實現技術,這個簡單做個摘要。
1、讀擴散還是寫擴散?
inbox: 收件箱,你收到的消息,即你所關注的人發布的消息。
outbox: 發件箱,你發布的消息。
寫擴散(Push)
該方式為每個用戶維護一個訂閱列表,記錄該用戶訂閱的消息索引(一般為消息ID、類型、發表時間等一些元數據)。每當用戶發布消息時,都會去更新其follower的訂閱列表。
優點:讀很輕。初始化時僅需要讀取自己的inbox即可。
缺點:寫很重。每發布一個消息,會導致大量的寫操作。
注:一般來說,用戶發布消息,並不會更新所有followers的訂閱列表,僅更新在線followers即可。
讀擴散(Pull)
該方式為每個用戶維護一個發送列表,記錄該用戶所有發表過的消息索引。
優點:寫很輕,節省空間。用戶每發布一條消息,僅需更新自己的outbox。
缺點:讀操作很重,計算量大。假設你收聽了1k用戶,則初始化時,需要從1k個用戶的outbox拉取消息,然后計算獲得最新的n條消息。
混合模式(Push+Pull)
該方式既為讀寫擴散的結合,根據用戶followers的數量來決定是讀擴散還是寫擴散。例如followers大於1k的,則使用讀擴散,否則使用寫擴散。
從目前現在網上的一些資料來看,Twitter是寫擴散,騰訊微薄是讀擴散,新浪微薄則是二者結合。
2、關於Cache
對於一個千萬級甚至億級用戶的大型網站來說,合理使用Cache至關重要。
一個用戶的核心數據由如下幾個部分組成:inbox,outbox,關系鏈,消息內容。
- inbox:主要緩存消息索引,僅為在線用戶緩存,從Timyang的PPT來看,新浪微薄估計是使用redis的list或set實現。
- outbox:緩存一定數量(例如200)條最近發表的消息。
- 關系鏈:following相對於followers來說,緩存容易些,follower加載開銷比較大,例如劉翔在騰訊微薄的聽眾超過1600萬。
- 消息內容:按內容年齡緩存;一般需要多份支持容災;需要緩存xml,json,rss,atom等多種格式的緩存以供API使用。
以Twitter為例,其將Cache分為四類:Vector Cache,Row Cache,Page Cache,Fragment Cache,均使用memcached實現。其中:
- Vector Cache主要緩存用戶的inbox以及outbox索引,其命中率高達99%;
- Row Cache主要緩存用戶關系鏈數據,以及Tweets內容,命中率為95%;
- Fragment Cache緩存Tweet的xml,json,rss,atom四種格式數據,以供API使用,命中率為95%;
- Page Cache主要原來緩存那些高人氣用戶的個人主頁,命中率僅為40%。
下圖為TwitterCache架構圖:
Twitter為啥要為API通道設置Fragment Cache和Page Cahce呢?其原因是Twitter的80%流量來自API。
下面以新浪微薄介紹一下Cache流程:
消息發布流程:
- 更新自己的outbox
- 加載followers列表
- 更新followers inbox
獲取首頁流程:
- 檢查inbox cache是否可用
- 獲取關注列表
- 聚合內容,獲得消息索引
- 根據索引,返回最終聚合的消息內容
3、關於存儲
目前Twitter和新浪的落地存儲,都是使用MySQL。而騰訊微薄則使用采用SSD+大文件存儲(每次寫操作都是append操作,寫操作可以先用內存緩存,達到適當大小合並,盡量減少隨機寫)。其他細節因不清楚或不方便透露,不做細述。
4、關於洪峰處理。
一般用異步隊列處理方式。消息隊列產品有:Kestrel(twitter使用Scala實現),RabbitMQ(使用Erlang實現),MemcacheQ。
Twitter 09年時,用戶的平均followers數量為126個。按照每秒400消息發布數算,那每秒就需要推送126*400=50400條消息出去。為了削 峰,Twitter自己用Scala實現了一個分布式消息隊列Kestrel,其代碼僅為1200行,運行在3台機器上,其使用memcached協議, 其Server之間無共享狀態,且全內存。新浪使用的是MemcacheQ。
參考文獻: