得物社區計數系統設計與實現
1、前言
1.1 社區數字場景
社區業務有非常多的數字統計場景,基礎的場景主要有以下這些:
- 用戶維度:發布內容數、被點贊數、被收藏數、關注數、粉絲數、點贊內容數、收藏內容數等。
- 內容維度:內容點贊數、內容閱讀數、內容分享數、內容收藏數、內容評論數等。
- 標簽維度:話題內容數、特效內容數、商品內容數、品牌內容數等。
其中部分場景還會有很多細分情況,例如內容相關的統計還會有以下場景:
- 根據內容類型統計:圖文數、視頻數、專欄數等。
這樣排列組合出來的最終結果就有很多了,比如需要查詢用戶發布的圖文內容數、用戶點贊的視頻內容數等等,且這些數字一般都需要能夠支持高度精確性、高性能查詢和批量查詢等能力。
1.2 具體案例
具體案例可參考下列圖示:
- 圖1. 個人主頁展示獲贊與收藏總數、粉絲數、關注數、發布動態數(視頻數、穿搭精選數、專欄數)。

(圖1)
- 圖2. 他人主頁展示獲贊與收藏總數、粉絲數、關注數、點贊動態數(視頻數、專欄數)。

(圖2)
- 圖3. 話題主頁展示話題內容數。?

(圖3)
2、逐漸浮現的系統風險
2.1 歷史方案
2.2 系統風險
- 性能瓶頸和穩定性風險:
- 一方面業務明細表的體量越來越大,需要通過分庫分表來解決問題,分庫分表后再用Count聚合的方式性能就會變差。
- 另一方面業務統計規則越來越復雜,使用數據庫Count的方式會使數據查詢語句越來越復雜,容易引發慢SQL從而導致數據庫不穩定。
- 計數業務數據層和緩存都和核心業務部分放在一起,若出現統計導致的不穩定會影響核心業務場景的使用,從而將小問題變成大問題。
- 緩存策略問題:
- 熱點穿透問題:部分計數場景下是有新數據就刪除緩存的策略,但若出現熱點內容、熱點用戶時,對應的統計數據(如點贊數、粉絲數)會頻繁刪除緩存導致穿透的問題,且一般熱點內容和用戶產生的數據量比較大、查詢量也比較大,會更容易加劇問題從而引發雪崩。
- 數據一致性問題:部分計數場景下是定時更新緩存的策略,緩存操作和MySQL操作無法在一個事務中完成,會產生不一致的問題,且在越頻繁變更的場景下差異值就會越大。
3、計數系統設計與實現
結合當前社區的業務現狀、體量以及考慮中長期體量增長的規劃,我們也調研了業內比較常見的一些實現方案,最終敲定通過維護一套計數中心的服務,由計數中心服務統一管理社區的數字統計的方式,整體情況大致如下:

3.1 寫場景
該場景下計數中心內部主要干三件事,主要包括數據獲取、數據處理、數據持久化。
3.1.1 數據獲取
數據的獲取一般有兩種方式,通過接口或通過MQ的方式,既然是平臺服務更希望對業務沒什么侵入性,因此我們目前采用的主要是MQ的方式。
使用MQ的情況下也有兩種方案可取,一種是業務服務根據事件觸發MQ消息,需要業務服務先保證業務數據已經持久化且需要生產端保證消息投遞無丟失,另一種則是直接通過訂閱業務數據表binlog的方式,這種方式可以保證業務數據已經持久化,目前得物已有DTS(數據訂閱平臺),使用起來也比較方便且可保證消息投遞不丟失,因此我們目前更多的是采用第二種方案。
數據獲取到后我們做一些格基礎校驗,驗證是否存在我們必要的一些字段是否完整,同時需要驗證數據處理的冪等性防止數據重復消費等,通過消息ID和業務唯一ID做冪等,然后把每行業務數據的各字段格式化成變更前和變更后倆個值且可以區分出是新增還是更新(binlog消息體就是這樣因此更加方便),之后就可以進入數據處理階段。
3.1.2 數據處理
拿到通過校驗和格式化后的數據,根據對應的事件和規則來判斷當前變更數據具體要做什么操作,我們通過具體的案例來看會更直觀,如:
場景1. 用戶A關注用戶B
- 第一步,判斷出該場景下需要變更的統計數,用戶A的關注數要+1,用戶B的粉絲數要+1。
- 第二步,提取需要變更的統計數的對象值,如用戶A的ID和用戶B的ID。
- 第三步,格式化成統計的格式,對象ID+統計類型+統計數變化值。
- 第四步,調用數據持久化的方法。
場景2. 用戶A發布的圖文內容狀態由正常變為刪除
- 第一步,判斷出該場景下需要變更的統計數,用戶A發布的圖文內容數要-1。
- 第二步,提取需要變更的統計數的對象值,如用戶A的ID。
- 第三步,格式化成統計的格式,對象ID+統計類型+統計數變化值。
- 第四步,調用數據持久化的方法。
3.1.3 數據持久化
持久化部分主要分為兩塊,一是DB持久化,二是對于緩存的更新。社區的數字統計場景主要有以下兩種情況:
- 只增不減:如內容分享事件,每次事件觸發只需要給內容的分享數+1即可。
- 既有增又有減:如用戶A(關注/取消關注)用戶B事件,需要給用戶A關注數(+1/-1),也需要給用戶B的粉絲數(+1/-1)。
又因為我們通過MQ消費數據是無序的,極端情況下可能會出現先減再加的情況從而導致負數的出現,因此存儲層的字段需要支持有符號的數據,保證最終計算的結果是正確的即可。DB層持久完成后再直接操作緩存變更數字并延長有效期,若緩存不存在則不處理等待讀場景有需要時再處理。
3.2 讀場景
讀場景整體邏輯比較簡潔,就是先查緩存,緩存不存在就查詢DB再寫入緩存即可,可批量跨場景查詢,需要注意對負數情況的處理。
4、總結及規劃
4.1 總結
計數中心是業內比較常見的做法,相對于老方案能夠降低各個業務對于復雜計數場景的維護成本,提升迭代效率和系統穩定性,獨立出來后在出現異常時業務也可做短時間降級,從而降低對核心業務的影響面。
4.2 規劃
目前社區已有多個場景接入計數中心,結合當前的現狀及未來的可能性,考慮后續主要優化方向主要有:
降低新增場景的接入成本和效率 | 計數中心服務的Owner更多的是維護系統層面的流程及穩定性,對于上游的業務邏輯并不都是很了解,如果需要擴大業務場景,可以考慮將統計規則部分做到可配置,將業務的部分交給業務處理,其他流程編排部分通用化。 |





































