恰好最近想寫一個Feed機制的文章,就來回答一下吧。
樓上各位其實把大致的狀況都已經說的很明白了,我來分享一下咱們目前線上一個feed實現機制,已經在生產環境運行了大半年。理論來講,百萬級別用戶沒有什麼問題。
爲了節省你們流量,全程無圖(實際上是我懶得畫 - - ),但願你們能把省下的流量錢來給我發紅包,鼓掌 。
首先,拋去數據庫這一塊,數據庫我想你們確定知道怎麼設計,可是查詢確定是個麻煩事, 因此我使用了redis進行一個冗餘設計,開始介紹以前,須要瞭解什麼是推拉模式,樓上說的兩篇文章
新浪微博架構和FEED架構分析--人人架構_paper0023_新浪博客 ,還有推拉模式以及時間分區拉模式的分析
微博feed系統的推(push)模式和拉(pull)模式和時間分區拉模式架構探討 其實已經足夠了解了,請各位看官若是未對推拉模式瞭解,那麼請先看文章,再來看個人回答,個人回答只是闡述具體實現,謝謝。
那麼我如今說一下redis這塊怎麼來完成推拉模式,以及內存儘量節省,速度儘量提升吧(固然,只是我理解的節省內存跟速度提升,若是看官們有其餘的意見,我就兩點要求,1、輕噴,2、說完再噴)。
一、實現
首先,先解決發佈跟接收的問題,目前有大致如下幾種方式:
一、推模式
什麼是推模式?推模式就是,用戶A關注了用戶B,用戶B每發送一個動態,後臺遍歷用戶B的粉絲,往他們粉絲的feed裏面推送一條動態。
二、拉模式
與推模式相反,拉模式則是,用戶每次刷新feed第一頁,都去遍歷關注的人,把最新的動態拉取回來。
可是,無論推模式仍是拉模式都存在若關注數量或者粉絲數量過多,致使遍歷時間太長的問題,怎麼去解決 ?這裏就出現了第三種模式,推拉模式。
三、推拉模式
這是一種折中的解決方案,就是在線推,離線拉。粉絲幾百上千萬, 跟你發佈動態同時在線的確定也就只有那麼頂天幾百幾千幾萬,況且這類大V不多,只推給在線的粉絲,離線的粉絲上線後,再去拉取動態便可!可是,無論是什麼模式,每一個用戶都會維護一個相似發件箱跟收件箱的東西,保存本身發過的動態以及Feed動態(具體實現看下面),來完成推與拉。
而這裏講的,確定就是推拉模式,用戶A關注了用戶B , 用戶B發佈動態則將動態推動用戶A的feed,這裏使用redis的zset實現,sort爲time(記得以毫秒爲時間戳,秒級在數據量達到必定程度後,會有讀取不到的問題,好比以時間戳爲分頁頁碼),value爲具體的動態 ID(爲何是動態ID, 其實很簡單, 就是由於動態的內容能夠進行緩存,在redis裏面所有走ID,修改動態內容也須要修改一處,動態內容能夠保存在hash結構裏), 每一個用戶維護一個zset保存我發佈的動態,一個zset保存個人feed動態,過時時間3~7天看狀況而定。爲何要設計過時時間後面會細說。
OK,全局維護一個在線用戶列表,怎麼設計這個就本身琢磨了,爲了防止用戶掛後臺致使與服務端爲離線狀態,因此最好是1~3小時未操做或者離線時間不大於3小時的,都當作在線處理,反正這個看狀況定。
那麼,當用戶發了一條動態後,後臺會有如下這些操做:
在線推: 異步遍歷在線的粉絲,將動態ID,添加到粉絲的Feed中。
離線拉: 離線用戶打開APP後,咱們是會請求一個公共的入口接口,主作統計以及其餘初始化操做,在這裏,咱們也開了一個異步線程,對用戶進行Feed更新操做,防止用戶進入APP後等待拉取時間過長,畢竟關注成千上萬的人確定有(其實萬單位如下遍歷都很快)。拉取過程其實就是把本身最後一條Feed的時間戳取出,去遍歷關注的人的feed,將大於該時間的ID所有拉取回來。用戶進入APP後,刷新便可看到最新操做。
另:若是有Feed新消息數提示的需求,能夠在推拉的同時進行增長, 刷新feed時清空便可。
其實到這裏,發佈接收的問題已經解決了,那麼有一個問題,用戶feed裏面過長,佔用內存怎麼辦?
我是這麼處理的,一個用戶的feed第一次拉取的時候,feed長度爲500條,在咱們APP裏,至關於50頁,然後的數據,都走數據庫。大頁碼翻頁其實就是個僞需求並且耗性能的東西,用戶除了第一次用這個APP,纔會翻到底,第一次使用, 能有幾個動態 ?而對於二次使用以上的用戶,通常來說, 翻了幾頁就已經到達上一次看過的地方了,因此500條數據,在關注量通常的狀況下,內容已經足夠消費,甚至達到疲勞,可能有關注量很大的用戶他的Feed天天可能有不少不少動態,可是,不用說,確定是作廣告的,關注一堆人等着回粉,這種人更不會去消費內容,50頁的內容,翻起來都累。固然,並非說放棄了這些人,feed找不到走數據庫嘛~~~~愛走不走,想走就給我翻50頁再說~
還有一個問題,每一個用戶都維護本身的動態跟Feed隊列,當用戶上百萬時,內存的佔有量確定不小,要怎麼釋放內存才合適 ?
這裏就回到上面那個問題了,爲何要給feed的key設計過時時間?爲何是設計3~7天過時時間?
緣由有如下:
1、一個用戶3~7天不打開APP,可能已經對APP失去興趣了,打開概率很小,或者已經被卸載了,沒有存在的意義了。
2、3~7天未登錄APP,關注的人發的動態也很多了,Feed未拉取回來的數據確定也很多,那麼這時候去遍歷其實拉取量很大,那麼還不如直接所有從新拉一邊或者拉取用戶最後登錄時間後產出的數據。
到這裏,其實已經差很少了,大部分業務邏輯已經足夠知足,而且速度也理想,目前咱們線上這種模式走了半年,feed通常都是10~80ms響應完畢。
好了,大概就是這樣了。
最後說一句:
<?php
echo 'php 是世界上最好的語言!!!';
?>