如何設(shè)計(jì)微博點(diǎn)贊功能數(shù)據(jù)庫?

一、如何設(shè)計(jì)微博點(diǎn)贊功能數(shù)據(jù)庫?
明星的一條微博的點(diǎn)贊數(shù)可能有幾十萬,甚至百萬以上。那么這個(gè)「點(diǎn)贊功能」(會(huì)記錄誰點(diǎn)了贊),新浪微博的數(shù)據(jù)庫是如何設(shè)計(jì)的呢?
網(wǎng)上說用到了 Redis,那么難道是直接用 Redis 保存的(指的是持久化保存)?還是說邏輯處理在 Redis 中,之后會(huì)定時(shí)同步/持久化到 MySQL 等磁盤數(shù)據(jù)庫?
概括一下:就是想弄明白「點(diǎn)贊」這種數(shù)據(jù)量龐大的功能,數(shù)據(jù)庫是如何設(shè)計(jì)、保存的呢?
沒設(shè)計(jì)過微博,也不懂新浪是怎么搞的,純粹按照我們做流式監(jiān)測項(xiàng)目的經(jīng)驗(yàn)做一個(gè)設(shè)計(jì)思路。

首先每條微博你所看到的點(diǎn)贊總數(shù)肯定本地和后端分開,也就是你點(diǎn)贊后,本地加1,先保證你自己馬上看到變化。然后通過點(diǎn)贊事件的方式傳遞給隊(duì)列中,肯定不會(huì)直接寫關(guān)系數(shù)據(jù)庫,一條流量明星微博,千萬粉絲點(diǎn)贊,評論里再點(diǎn)贊的請求事件挺嚇人的。

先走隊(duì)列,隊(duì)列后面一路事件流是流式點(diǎn)贊統(tǒng)計(jì),那么每條微博都會(huì)有個(gè)當(dāng)日總數(shù)和非當(dāng)天統(tǒng)計(jì)總數(shù),這個(gè)流計(jì)算控制就可以了。另外保證最近一周的微博點(diǎn)贊統(tǒng)計(jì)數(shù)都在內(nèi)存里,例如用Redis,一周以上的微博點(diǎn)贊數(shù)據(jù)都在k-v庫里,例如用Hbase。內(nèi)存庫和kv庫可以做冷熱數(shù)據(jù)交換。

隊(duì)列后面另一條路事件流,直接將微博點(diǎn)贊事件數(shù)據(jù)作為原始數(shù)據(jù)寫入到大數(shù)據(jù)平臺(tái),例如hdfs,但是寫入前,做一個(gè)類似hudi,parquet列格式,方便存儲(chǔ)進(jìn)hdfs的數(shù)據(jù)查詢,也方便后續(xù)批量統(tǒng)計(jì)。

定期對大數(shù)據(jù)平臺(tái)的微博點(diǎn)贊事件做批量統(tǒng)計(jì),并定期與實(shí)時(shí)流對接的k-v庫中的非當(dāng)天點(diǎn)贊統(tǒng)計(jì)總數(shù)做比對,統(tǒng)計(jì)數(shù)字若不同,就按照大數(shù)據(jù)平臺(tái)批統(tǒng)計(jì)結(jié)果為準(zhǔn),在保證一致性的前提下,同步更新內(nèi)存庫和k-v庫。這塊可以參考lambda架構(gòu)的辦法。

這樣點(diǎn)贊總數(shù)總是來自當(dāng)日總數(shù)和非當(dāng)天統(tǒng)計(jì)總數(shù)之和,當(dāng)日總數(shù)是實(shí)時(shí)增量的,不去理會(huì)是否正確,做好批量統(tǒng)計(jì)比對就一定能保證隔天以后點(diǎn)贊總數(shù)的準(zhǔn)確性。如下圖所示:



上述僅僅是一個(gè)思路,可以同時(shí)解決微博點(diǎn)贊統(tǒng)計(jì)準(zhǔn)確性和點(diǎn)贊訪問性能兩個(gè)指標(biāo),實(shí)際業(yè)務(wù)肯定比這個(gè)思路復(fù)雜千百倍,但總之給大家一個(gè)理解參考的方向。

一定有人會(huì)想為什么在實(shí)時(shí)統(tǒng)計(jì)準(zhǔn)確度上要這么下功夫,我想說以我們做實(shí)時(shí)流計(jì)算的經(jīng)驗(yàn)的答案:是的。實(shí)時(shí)增量統(tǒng)計(jì)是不可信的,原因來自各種情況,例如計(jì)算服務(wù)重啟,那么就會(huì)導(dǎo)致增量統(tǒng)計(jì)數(shù)據(jù)不準(zhǔn),只有通過實(shí)時(shí)與隔天分離的辦法,也就是lambda的架構(gòu)思想,始終保持隔天以后的統(tǒng)計(jì)總量來自批處理的結(jié)果。

二、如何選擇實(shí)時(shí)采集數(shù)據(jù)的數(shù)據(jù)庫?
前提:數(shù)據(jù)采集24小時(shí)連續(xù)不斷,更新或插入數(shù)據(jù)庫操作的頻率大概在每秒1000+。

解決方案:

采集數(shù)據(jù)主要是看應(yīng)用場景,如果是采集數(shù)據(jù)按周期整存整取,批量讀取分析的話,用分布式文件系統(tǒng),數(shù)據(jù)量夠大,寫入非常快,直接上Hadoop hdfs

但是若數(shù)據(jù)采集到,不僅要做離線分析,還需要實(shí)時(shí)的回放查找,那么對于這種情況最好的方法就是使用時(shí)序數(shù)據(jù)庫,例如opentsdb,它是基于HBASE,因此底層還是依賴Hadoop hdfs。

influxdb也不錯(cuò),自己實(shí)現(xiàn)原生數(shù)據(jù)庫,只不過你要為集群模式付費(fèi),其實(shí)它們都是通過lsm-tree的nosql,對最近存儲(chǔ)的數(shù)據(jù),查找性能很強(qiáng),但是對于歷史數(shù)據(jù)的查找速度就差點(diǎn)。當(dāng)然你也可以考慮國產(chǎn)清華造的IoTDB,現(xiàn)在也是Apache頂級開源項(xiàng)目了,而且也是需要通過Hadoop hdfs來保證數(shù)據(jù)可靠性!

再加一條,若應(yīng)用場景不僅僅是高速寫入,還可能涉及到大量的范圍查找,那么就要從MongoDB這樣的分布式數(shù)據(jù)庫的選擇基礎(chǔ)之上進(jìn)行優(yōu)化,因其采用B-tree索引,范圍查詢的綜合效果肯定是要好于基于lsm-tree的nosql(近期數(shù)據(jù)查找快),例如時(shí)序數(shù)據(jù)庫基本上都是lsm-tree。但Mongo的寫入一定要根據(jù)實(shí)際數(shù)據(jù)結(jié)構(gòu)優(yōu)化,因?yàn)槟愕臉I(yè)務(wù)基本上是1毫秒級的寫入,這對于Mongo是一個(gè)不小的挑戰(zhàn),所以MongoDB的批量順序?qū)?,以及加大?nèi)存資源等設(shè)置就很重要。




作者:碼農(nóng)編程進(jìn)階筆記

歡迎關(guān)注微信公眾號 :碼農(nóng)編程進(jìn)階筆記