sns系統,微博系統都應用到了feed(每條微博或者sns裏的新鮮事等咱們稱做feed)系統,不論是twitter.com或者國內的新浪微博,人人網等,在各類技術社區,技術大會上都在分享本身的feed架構,也就是推拉模式(timyang上次也分享了新浪微薄的模式)。下面咱們就微博的feed推拉(push,pull)模式作一下探討,並提出新的時間分區拉模式。 數據庫
衆所周知,在微博中,當你發表一篇微博,那麼全部關注你的followers(粉絲)都會在必定的時間內收到你的微薄,這有點像羣發一封郵件,全部的抄送者都會在必定的時間內收到。到這裏,你可能以爲沒有什麼難度。咱們看下下面的截圖: 緩存
圖1 新浪微博姚晨 數據結構
圖2 twitter上馮大輝 架構
新浪微博的姚晨粉絲有2594751,她發表任何一篇微博,都須要2594751個粉絲在必定的時間內收到,twitter的馮大輝發表一篇的話,須要19868個followers收到。 memcached
相反,姚晨須要收到他關注的545我的的全部更新,馮大輝須要收到他關注的2525我的的全部更新。到這裏,你是否是感受到有那麼一點點小挑戰呢? 性能
下面咱們看下微博通常的總體結構圖: 優化
圖3 微博總體結構 ui
圖中展現了微博的總體數據流程,先了解下總體的數據結構,沒有涉及到followers等的推拉模式處理。下面咱們再看下推模式(push): it
圖4 推模式結構 微博
推模式須要把一篇微博推送給全部關注他的人(推給全部的粉絲),好比姚晨,咱們就須要推送給2594751個用戶的feeds表中。固然,feeds表能夠很好的進行sharding,存儲也都是一些數字型的字段,存儲空間可能不是很大,用戶在查詢本身關注的全部人的feed時,速度快,性能很是高,可是推送量會很是大,姚晨發表一篇,就會產生200多萬條數據。試想,一個大量用戶的微薄系統經過使用推模式,是否是會產生很是驚人的數據呢?
下面看下拉模式(pull)
圖5 拉模式
拉模式只須要用戶發表微博時,存儲一條微博數據到feeds表中(feeds表能夠是一個臨時表,只保存近期可接受範圍的數據).用戶每次查詢feed時都會去查詢feeds表。好比姚晨打開本身的微薄首頁,就產生:SELECTidFROMfeedswhereuidin(followinguidlist)ORDERBYidDESCLIMITn(查詢最新的n條),緩存到memcached
uidlist=>{data:idlist,timeline:上次查詢出來的最新的一條數據的時間}
再次刷新:SELECTidFROMfeedswhereuidin(followinguidlist)ANDtimeline>(memcached存儲的上次的timeline)ORDERBYidDESCLIMITn
這種模式實現起來也是比較簡單和容易的,只是在查詢的時候須要多考慮下緩存的結構。可是feeds表會產生很大的壓力,怎麼說feeds表也要保存最近十天半個月的數據吧,對於一個大點的系統,這會產生比較大的數據,若是following的人數比較多,數據庫的壓力就會很是大。並且通常在線的用戶,客戶端都會按期掃描,又會增長很大的壓力,這在查詢性能上沒有推模式的效率高。
下面咱們在對拉模式作一下改進優化
圖6 拉模式(pull)-改進(時間分區拉模式)
拉模式的改進主要是在feeds的存儲上,使用按照時間進行分區存儲。分爲最近時間段(好比最近一個小時),近期的,比較長時期等等。咱們再來看下查詢的流程,好比姚晨登錄微博首頁,假設緩存中沒有任何數據,那麼咱們能夠查詢比較長時期的feeds表,而後進入緩存。下一次查詢,經過查詢緩存中的數據的timeline,若是timeline還在最近一個小時內,那麼只須要查詢最近一個小時的數據的feed表,最近一個小時的feeds表比圖四的feeds表可要小不少,查詢起來速度確定快幾個數量級了。
改進模式的重點在於feeds的時間分區存儲,根據上次查詢的timeline來決定查詢應該落在那個表。通常狀況下,常常在線的用戶,頻繁使用的客戶端掃描操做,常常登陸的用戶,都會落在最近的feeds表區間,查詢都是比較高效的。只有那些十天,半個月才登陸一次的用戶須要去查詢比較長時間的feeds大表,一旦查詢過了,就又會落在最近時間區域,因此效率也是很是高的。
關於時間的分區,須要根據數據量,用戶訪問特色進行一個合理的切分。若是數據發表量很是大,能夠進行更多的分區。
上面介紹的推模式和拉模式都有各自的特色,我的以爲時間分區拉模式彌補了圖四的拉模式的很大的不足,是一個成本比較低廉的解決方案。固然,時間分區拉模式也能夠結合推模式,根據某些特色來增長系統的性能。
後記:本文的目的是介紹時間分區拉模式,本人對新浪微博和twitter等的推拉模式的細節並不清楚。