postgresql , pipelinedb , facebook , 微網誌 , 流式統計
高可用架構的一個pcc大賽,看了一下比賽規則,發現postgresql很适合做這個場景,原樣複刻,使用pg實作以及性能表現到底如何?
比賽内容介紹如下
<a href="https://github.com/archnotes/pcc">https://github.com/archnotes/pcc</a>
可以對一個對象(一條feed、文章、或者url)進行 like 操作,禁止 like 兩次,第二次 like 傳回錯誤碼
有 islike 接口,傳回參數指定的對象有沒有被目前使用者 like 過
需要看到一個對象的 like 計數
可以看到一個對象的 like 使用者清單(類似 qq 空間);
上述清單加分項:like優先顯示我的好友清單(social list)。
資料量:每天新增的 like 對象數為 1 千萬,每秒 like 計數器查詢量為 30 萬次 / 秒。
使用者數量級1億,好友數量級1~1萬,單個對象的like數量1-100萬
提供比賽資料集(純文字格式),需要參賽人員自行導入到自己資料庫
uid為uint64,1億條
uid, friend_id為uint64,隻存在雙向好友關系,1億個使用者*1000,好友關系通常是一個長尾分布,90% 100個以下,8%長尾分布300-1000,2% 1000-10000
oid,uid為uint64,2億個objects, 每個1-100w
人與人的關系為關注,或者互相關注的關系。
人與對象為喜歡或者不喜歡的關系。

在設計時,分明細資料和統計資料,統計資料為了更快速的查詢關系,被關注數。
明細可以記錄在日志,也可以記錄在資料庫中。統計資料(關系,計數,被like等),以流處理的方式寫入資料庫。
1. 人關注了哪些人,
2. 人被哪些人關注,本場景未涉及(如果需要的話,建立反向關系表)。
3. 人like了哪些對象,本場景未涉及(如果需要的話,建立反向關系表)。
4. 對象被哪些人like,
5. 對象被like了多少次
6. like某對象的使用者中,哪些是我的好友?
建立流,關注的行為将寫入流,同時寫入明細(可選)。
建立持續視圖,根據關注行為實時統計。
激活流計算
關注(like)操作函數,判斷是否已關注,如果已關注,傳回異常,否則關注。(這個也可以寫在程式中,但是需要與資料庫互動多次,差評)
函數可以根據實際需求進行調整,比如需要傳回被like後的數組,查詢一下continue view即可。
測試
1. 使用者id範圍
1-1億
2. 文章id範圍
1-2億
3. 熱點文章id範圍
總共2億文章,使用高斯分布進行like,分布在以鐘鼎為中心的2.0/xx這個區間内的文章id,覆寫了95%的出現機率。分布在1.0/xx這個區間的文章id覆寫了67%的出現機率。
橫坐标越靠近鈡的頂端的值(即文章id=1億),産生的機率越高。
xx越小,鈡越尖,也就是說熱點文章越少。
原理參考
<a href="https://github.com/digoal/blog/blob/master/201705/.../201506/20150618_01.md">《生成泊松、高斯、指數、随機分布資料 - postgresql pg_bench 》</a>
4. 随機使用者喜歡随機文章
5. 随機使用者喜歡熱點文章
壓測腳本,like文章,使用高斯分布産生文章id,經過長時間的壓測,文章被like的次數呈現高斯分布,鐘鼎的文章被like的次數最多。
xx設定為10.0,表示以鐘鼎為中心的20%這個區間内的文章id,覆寫了95%的出現機率。分布在10%這個區間的文章id覆寫了67%的出現機率。
xx越大,鐘鼎的文章id機率越高。
256個連接配接進行壓測,測試結果,每秒産生17.7萬次like請求。
階段性壓測後文章數
符合預期,繼續壓測。(或者我們也可以選擇指數分布進行測試)
暫時沒有進行優化的情況下,cpu使用情況如下
持續壓測like,産生2億文章的like資料,然後進入測試2。
2. 使用者好友分布
90% 100個以下,8%長尾分布300-1000, 2% 1000-10000
産生90%的使用者關系
産生8%的使用者關系
産生2%的使用者關系
最終生成1億使用者,占用123gb空間,2.7gb索引。
1. 查詢文章被誰like?
2. 查詢文章被like了多少次?
3. 查詢like某文章的使用者中,哪些是我的好友?
壓測腳本1, 查詢文章被誰like?
壓測腳本2, 查詢文章被like了多少次?
壓測腳本3, 查詢like某文章的使用者中,哪些是我的好友?
壓測結果1,查詢文章被誰like? 達到 101萬/s 并不意外。
壓測結果2,查詢文章被like了多少次? 104萬/s。
壓測結果3,查詢like某文的使用者中,哪些是我的好友? 64.8萬/s。
1. 數組越長,一條記錄占用的空間會越大,使用toast切片存儲,可以有效的提高查詢非數組字段的效率。
2. profiling,針對性的優化。
微網誌、facebook最常用的操作:
1. 關注人或者喜歡某條消息、微網誌等。
這個屬于寫操作,要求寫入快,并且要求寫入(like或關注)後立即反映出來。
2. 查詢好友清單
為了查詢快速,最快的方法是pk查詢,但是一個人可能關注很多人,如果是查詢多條記錄,很顯然會比較慢。
是以考慮使用數組存儲好友清單。
但是,使用數組存儲清單,又需要考慮寫入速度的問題。
是以使用流計算聚合是最好的,因為pg有流計算插件,可以在資料庫中完成流計算。
3. 查詢被關注的好友清單
反向好友關系,同樣要求查詢快速,使用正向關系一樣的方法。
4. 查詢文章(微網誌)被關注的次數,被關注人,被關注的人裡有哪些是我的好友。
首先被關注的次數,實際上就是個計數器。為了提高查詢速度,它必須是一個value而不是查詢時使用count(*)進行聚合。
查詢文章(微網誌)被關注的人,為了提高查詢速度,同樣考慮使用數組存儲。使用pg内置的流計算進行聚合。
被關注的人裡面有哪些是我的好友,這個問題就很簡單了,好友關系與文章(微網誌)被關注人的兩個數組求交集即可。
使用pg的流計算解決了實時寫入,實時聚合的問題。
同時由于資料實時被聚合,是以幾個查詢需求就顯得非常輕松。
測試得到的性能名額(未優化):
1. 關注微網誌(文章)
17.7萬/s,預計可以優化到30萬。
2. 查詢文章被誰like?
101.6萬/s
3. 查詢文章被like了多少次?
104.1萬/s
4. 查詢like某文章的使用者中,哪些是我的好友?
64.8萬/s
5. 機器:
(10w左右價位的x86,12*8tb sata盤,1塊ssd作為bcache)
資料庫内置流計算功能,是一件不錯的事情。
<a href="https://github.com/digoal/blog/blob/master/201609/20160911_01.md">《facebook linkbench 測試postgresql社交關系圖譜場景性能》</a>
<a href="https://github.com/digoal/blog/blob/master/201612/20161220_01.md">《流計算風雲再起 - postgresql攜pipelinedb力挺iot》</a>
<a href="https://github.com/digoal/blog/blob/master/201611/20161121_01.md">《postgresql on linux 最佳部署手冊》</a>