我們先不考慮用戶規模、并發量、性能、可靠性… 這些東西
我們就單單從功能層面實現統計視頻播放量,其實很簡單, 就是給視頻表加一個字段,用來表示播放量
這樣實現,最大的好處就是簡單,但是我們馬上就能發現一個非常嚴重的問題,
每當有用戶觀看一次的時候,這個數字就加一
這里又引申出一個風控的問題,就是如果不加以控制的話,同一個用戶就可以瘋狂的刷新點擊,
那么這個播放量就會被惡意刷高了,所以肯定要做風控的
考慮并發量、性能的解決方案:
拋開上面說的風控模型,單純從技術上這個播放量如何實現?
1、首先性能必須要好
2、盡量去保證一個高可用,你這個計數服務理論上是可以掛掉的,都是要有一個兜底值、默認值
3、不要求這個數字的絕對準確性,這個很重要,直接關系到我們后面整個系統的實現復雜度
4、對于這個數字的實時性要求不高,可能達到分鐘級它能達到一個最終一致性,就夠了
這個計數服務是非常通用的,所以我們可以單獨抽象出來一個計數服務,
按照大廠的規模,高并發的場景,這個計數服務肯定是要集群部署的
這樣就可以讓這個服務能夠單獨去熔斷、限流、降級,服務治理,擴容縮容彈性都會好很多
先在本地內存使用 map concurrenthashmap 把大量的寫請求緩存起來,
key 是 視頻 id,value 是 增量的播放數
使用定時任務周期性的將本地內存中的數據刷新到 Redis 中去,
這本身是一個異步化的實際,
然后刷新到 Redis 之后,再通過一個定時任務將 Redis 中的數據持久化到 MySQL 中
這么做了之后呢,db 的壓力可以做的非常低
再具體一點說,讀壓力,讀取視頻的播放量,可以直接從 Redis 緩存中讀取,甚至可以考慮給 kv 不設置過期時間,這樣這不會有緩存擊穿、穿透的問題了
寫壓力,更新視頻的播放量,使用異步 + 批量合并的思想,先將大量的更新寫請求在本地內存中合并起來,然后在周期性的去寫庫,大大降低了數據庫的壓力
再來講一下極端的場景
1、我寫了本地內存,這個機器宕機了,怎么辦?
2、數據寫入 Redis,Redis 掛了,怎么辦?
3、xxx
我們假設一下這些極端場景發生了,那么結果也無非有一些計數沒有計算上去,丟失了。
這對業務影響很大嗎?并沒有對吧。
關于數據的實時性,就看定時任務的周期、產品提的需求、視頻的熱度、節點的可靠性
所以我認為這么實現,是一個成本比較低、又能滿足業務需求的一個解決方案