場景
在直播領(lǐng)域,明星用戶短期內(nèi)可能收到海量的用戶點(diǎn)贊。那么,如何將這些點(diǎn)贊數(shù)據(jù)入庫?
問題分析
點(diǎn)贊類似于秒殺。但有如下特點(diǎn):
- 與秒殺不同,它沒有庫存。
- 點(diǎn)贊數(shù)允許少量丟失
我將從如下幾個(gè)環(huán)節(jié)入口分層抵擋海量點(diǎn)贊的沖擊。
app端聚合
面對用戶調(diào)頻的點(diǎn)贊動作,用戶端可以秒為時(shí)間單位,統(tǒng)計(jì)時(shí)間段內(nèi)用戶的點(diǎn)贊總數(shù)上傳。從而大大減少后端請求量。
服務(wù)端二次聚合
多個(gè)用戶可能對同一個(gè)主播點(diǎn)贊,因此,在服務(wù)端可將秒時(shí)間單位內(nèi)對同一主播的點(diǎn)贊量聚合,再以秒為時(shí)間間隔計(jì)入redis之中。為了盡可能增加各機(jī)器內(nèi)存利用,可通過hash算法將某hash值的用戶流量打到一臺機(jī)器之上。當(dāng)某機(jī)器故障時(shí),由于沒有持久化的存儲,可臨時(shí)切換機(jī)器。但內(nèi)存的數(shù)據(jù)可能丟失。
數(shù)據(jù)入庫
如果不考慮redis中數(shù)據(jù)的可靠性,可以在直播結(jié)束之后再將點(diǎn)贊總量入庫。為防止故障導(dǎo)致的點(diǎn)贊數(shù)量丟失,可每分鐘一次,遍歷正在進(jìn)行中的直播,將新增的點(diǎn)贊數(shù)據(jù)入庫。
緩存與數(shù)據(jù)庫的一致性
在緩存之中,每個(gè)主播有兩個(gè)點(diǎn)贊計(jì)數(shù),一個(gè)是當(dāng)前總量,一個(gè)是新增總量。每分鐘持久化新增總量。新增總量清零。為防止數(shù)據(jù)庫更新失敗,采用最終一致性完成。重試直到成功為止。同時(shí)使得當(dāng)前總量緩存失效。
總結(jié)分析
在如上的設(shè)計(jì)之中,由于存在時(shí)間段聚合,因此統(tǒng)計(jì)數(shù)據(jù)會有秒級的延遲。如果app端或者服務(wù)商down機(jī),那么1秒以內(nèi)的統(tǒng)計(jì)數(shù)據(jù)將丟失。如果出現(xiàn)redis故障,那么可能丟失分鐘以內(nèi)的數(shù)據(jù)。
改進(jìn)方案
為避免服務(wù)器故障引起數(shù)據(jù)丟失,可將每次匯入的數(shù)據(jù)寫入kafka之中。每當(dāng)寫入redis成功以后,更新kafka的消費(fèi)點(diǎn)。當(dāng)故障發(fā)生時(shí),可讀取kafka中的待消費(fèi)數(shù)據(jù)即可恢復(fù)。kafka可只保存近2天的數(shù)據(jù),以減少存儲浪費(fèi)。