2010-02-06 29 views
16

我正在使用的應用程序有一個活動供稿,其中每個用戶都可以看到他們的朋友的活動(很像Facebook)。我正在尋找一種適度擴展的方式來即時顯示給定用戶的活動流。我說'適度',因爲我只想用數據庫(Postgresql)和或者 memcached來完成此操作。例如,我希望這個解決方案可以擴展到每個有100個朋友的20萬用戶。以適度可擴展的方式提供活動供稿項目

當前,有一個主活動表存儲給定活動的呈現html(Jim添加了一個朋友,George安裝了一個應用程序等)。這個主活動表保留了源用戶,html和一個時間戳。

然後,有一個單獨的('join')表,它只保留一個指向應該在其好友供稿中看到此活動的人員的指針,以及一個指向主活動表中的對象的指針。所以,如果我有100個朋友,並且我做了3個活動,那麼連接表將增長到300個項目。

很明顯,這個表格將增長得非常快。不過,它具有很好的屬性,即向用戶顯示提取活動需要一個(相對)便宜的查詢。

另一種選擇是隻保留主要活動表,並說類似查詢它:

select * from activity where source_user in (1, 2, 44, 2423, ... my friend list) 

這有你查詢的用戶誰可能永遠不會被激活的缺點,併爲您的朋友列表增長,這個查詢可以變得越來越慢。

我看到雙方的優點和缺點,但我想知道如果一些SO人可能會幫助我衡量選項,並建議一種方式或他人。我也開放給其他解決方案,但我想保持簡單,不要安裝類似CouchDB等。

非常感謝!

回答

12

我傾向於擁有主活動表。如果你這樣做,這是我會考慮實現的:

  1. 當從數據庫中獲取數據時,您可以創建多個活動表並執行UNION ALL。例如,每月滾動它們 - activity_2010_02等等。以您的示例爲例 - 200K用戶x 100個朋友x 3個活動= 6000萬行。對於PostgreSQL來說,這不是一個值得關注的性能問題,但您現在可能僅僅爲了方便而考慮這一點,並最終爲了毫不費力的未來擴展而進行。

  2. 這樣做的缺點是您查詢的用戶可能永遠不會處於活動狀態,隨着您的好友列表增長,此查詢可能會變得越來越慢。

你要顯示整個活性飼料,回去的時候開始?您在原始問題中沒有提供太多細節,但我猜測您會顯示按時間戳排序的最後10/20/100項。一些索引和LIMIT子句應該足以提供即時響應(因爲我剛剛在一個大約2000萬行的表上測試過)。在繁忙的服務器上它可能會比較慢,但這應該通過硬件和緩存解決方案來解決,Postgres不會成爲那裏的瓶頸。

即使您確實提供活動飼料回到曙光時間,分頁的輸出! LIMIT子句將把你保存在那裏。如果帶有LIMIT的基本查詢不夠用,或者用戶有不再活動的朋友的長尾巴,則可以考慮將查找限制爲最後一天/每週/月第一個然後提供朋友的ID列表:

select * from activity 
    where ts <= 123456789 
    and source_user in (1, 2, 44, 2423, ... my friend list) 

如果你有一臺跨越幾個月或幾年回來,對於朋友的ID搜索將只由第一WHERE子句選擇的行內執行。

這就是如果我選擇你現在考慮的兩種解決方案。我也看看像這樣的東西:

  1. 重新考慮你的非規範化的表。存儲預生成的HTML輸出真的是最好的方法嗎?通過查找活動查詢表並在運行中生成模板化輸出,您會更好地改善性能嗎?預先生成的HTML在一開始看起來似乎更好,但考慮諸如磁盤存儲,API,未來佈局更改以及存儲HTML之類的東西可能並不是那麼有吸引力。查找表可能包含您可能的活動 - 添加好友,更改狀態等,如果其他用戶參與活動,則活動日誌會引用該活動和朋友的ID。

  2. 在做預生成HTML,但沒有將其存儲在數據庫中。將這些東西保存在磁盤上作爲預先生成的頁面。然而,這不是一個銀彈,很大程度上取決於您網站上的讀寫比率。即一個公共論壇上的典型討論主題可能會有十幾條消息,但可以被瀏覽數百次 - 這是緩存的一個很好的選擇。而如果您的應用程序更適合立即進行狀態更新,並且您必須重新生成HTML頁面,並在每次觀看兩次後再將其保存在磁盤上,則此方法幾乎沒有任何價值。

希望這會有所幫助。