消息系統設計與實現「上篇」

由于文章篇幅較長,而作者精力有限,不希望這么早就精盡人亡,故分成上下篇來寫消息系統的設計與實現。上篇主要講的是一些概念,搞清楚我們要做的這個消息系統的主要內容。而下篇主要講具體的實現,會包括架構設計,數據庫設計,業務流程詳細的實現等。

整個系統的設計與實現,并非我一人之力就可以完成的。這其中是同事們大家一起討論與商討的結果,而我只是把它細化,呈現出來。

我只是一個會思考的idea搬運工。

產品分析

首先我們來看一下市場上關于消息的實現是怎么樣的。

簡書

簡書的消息系統主要分了兩種

  • 簡信
  • 提醒

簡信
簡信的性質其實跟私信是一樣的,是用戶發送給用戶的一則消息,有具體的信息內容。

簡書簡信

提醒
而提醒,則是系統發送的一則消息,其文案格式是固定的,并且對特殊對象一般擁有超鏈接。

簡書提醒

知乎

知乎跟簡書一樣,主要分了兩種:

  • 私信
  • 消息

私信
跟簡書一樣,使用戶發送給用戶的一則消息,也可以是管理員發送給用戶的消息。

知乎私信

消息
知乎的消息比簡書的提醒有過之而無不及,知乎會對多條相似的消息進行聚會,以達到減輕用戶閱讀壓力的體驗。

知乎消息

消息的三種分類

通過兩種產品的簡單分析,得出他們的消息有兩種分類,在這基礎上,我們再加上一種:公告。
公告的主要性質是系統發送一則含有具體內容的消息,站內所有用戶都能讀取到這條消息。
所以,消息有三種分類:

  1. 公告 Announce
  2. 提醒 Remind
  3. 私信 Message

提醒的語言分析

我們從簡書取一組提醒樣本:

  • 3dbe1bd90774 關注了你
  • magicdawn 喜歡了你的文章 《單點登錄的三種實現方式》
  • 無良程序 喜歡了你的文章 《基于RESTful API 怎么設計用戶權限控制?》
  • alexcc4 喜歡了你的文章 《在Nodejs中貫徹單元測試》
  • 你在《基于RESTful API 怎么設計用戶權限控制?》中收到一條 cnlinjie 的評論
  • 你的文章《Session原理》已被加入專題 《ios開發》

分析句子結構,提醒的內容無非就是

「誰對一樣屬于誰的事物做了什么操作」
「someone do something in someone's something」

someone = 提醒的觸發者,或者發送者,標記為sender
do something = 提醒的動作,評論、喜歡、關注都屬于一個動作,標記為action
something = 提醒的動作作用對象,這就具體到是哪一篇文章,標記為target
someone's = 提醒的動作作用對象的所有者,標記為targetOwner

這就清楚了,sender和targetOwner就是網站的用戶,而target是具體到哪一篇文章,如果提醒的對象不僅僅局限于文章,還有其他的話,就需要增加一項targetType,來標記目標是文章還是其他的什么。而action,則是固定的,整個網站會觸發提醒的動作可能就只有那幾樣:評論、喜歡、關注.....(或者其他業務需要提醒的動作)

消息的兩種獲取方式

  • 推 Push
  • 拉 Pull

以知乎為例
推的比較常見,需要針對某一個問題維護著一張關注者的列表,每當觸發這個問題推送的條件時(例如有人回答問題),就把這個通知發送給每個關注者。

拉的相對麻煩一點,就是推的反向,例如每個用戶都有一張關注問題的列表,每當用戶上線的時候,對每個問題進行輪詢,當問題的事件列表出現了比我原本時間戳大的信息就進行拉取。

而我們則根據消息的不同分類采用不同的獲取方式
通告和提醒,適合使用拉取的方式,消息產生之后,會存在消息表中,用戶在某一特定的時間根據自己關注問題的表進行消息的拉取,然后添加到自己的消息隊列中,

信息,適合使用推的方式,在發送者建立一條信息之后,同時指定接收者,把消息添加到接收者的消息隊列中。

訂閱

根據提醒使用拉取的方式,需要維護一個關注某一事物的列表。
這種行為,我們稱之為:**「訂閱」Subscribe **

一則訂閱有以下三個核心屬性

  • 訂閱的目標 target
  • 訂閱的目標類型 targetType
  • 訂閱的動作 action

比如我發布了一篇文章,那么我會訂閱文章《XXX》的評論動作,所以文章《XXX》每被人評論了,就需要發送一則提醒告知我。

訂閱的規則還可以擴展
我喜歡了一篇文章,和我發布了一篇文章,訂閱的動作可能不一樣。
喜歡了一篇文章,我希望我訂閱這篇文章更新、評論的動作。
而發布了一篇文章,我希望我只是訂閱這篇文章的評論動作。

這時候就需要多一個參數:subscribReason
不同的subscribReason,對應著一個動作數組,
subscribReason = 喜歡,對應著 actions = [更新,評論]
subscribReason = 發布,對應著 actions = [評論]

訂閱的規則還還可以擴展
用戶可能會有一個自己的訂閱設置,比如對于所有的喜歡的動作,我都不希望接收。
比如Knewone的提醒設置

Knewone提醒設置

所以我們需要再維護一個表:SubscriptionConfig,來存放用戶的提醒設置。
并且,當用戶沒有提醒設置的時候,可以使用系統提供的一套默認設置:defaultSubscriptionConfig

聚合

如果我發布了一篇文章《XXX》,在我不在線的時候,被評論了10遍,當我一上線的時候,應該是收到十條信息類似于:「誰誰誰評論了你的文章《XXX》」?
還是應該收到一條信息:「甲、乙、丙、丁...評論了你的文章《XXX》」?

知乎在聚合上做的很優秀,要知道他們要實現這個還是挺有技術的:
知乎的消息機制,在技術上如何設計與規劃?
網站的消息(通知)系統一般是如何實現的?

關于這部分功能,我們還沒有具體的實現方法,暫時也無法講得更加詳細。⊙﹏⊙

五個實體

通過上面的分析,大概知道做這個消息系統,需要哪些實體類:

  1. 用戶消息隊列 UserNotify
  2. 用戶 User
  3. 訂閱 Subscription
  4. 訂閱設置 SubscriptionConfig
  5. 消息 Notify
    • 通告 Announce
    • 提醒 Remind
    • 信息 Message

行為分解

說了這么多,整理一下整個消息流程的一些行為:

  • 系統或者管理員,創建消息
    • createNotify (make announce | remind | message)
  • 用戶,訂閱消息,取消訂閱
    • subscribe, cancelSubscription
  • 用戶管理訂閱設置
    • getSubscriptionConfig, updateSubscriptionConfig
  • 用戶,拉取消息
    • pullNotify (pull announce | remind | message | all)
  • 用戶,查詢消息隊列
    • getUserNotify(get announce | remind | message | all)
  • 用戶閱讀消息
    • read

在本文的「下篇」我們來探討一下:模型怎么做、數據庫怎么設計、代碼結構怎么來、一些邏輯上的時序圖應該是怎么樣的。

-------- 更新于 2015/11/15 ----------

關聯文章:消息系統設計與實現「下篇」


如果本文對您有用
請不要吝嗇你們的Follow與Start
這會大大支持我們繼續創作

「Github」
MZMonster :@MZMonster
JC_Huang :@JerryC8080

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 關聯文章:消息系統設計與實現「上篇」 模型設計 Notify Save Remind消息表,我們需要target、...
    JC_Huang閱讀 26,289評論 52 196
  • 背景 在一個系統中,資源,數據會持續不斷的更新。而用戶如果需要知道這些數據的更新,就需要一個系統,將系統中不斷更新...
    goaheadhj閱讀 4,757評論 1 14
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,923評論 18 139
  • 點擊查看原文 Web SDK 開發手冊 SDK 概述 網易云信 SDK 為 Web 應用提供一個完善的 IM 系統...
    layjoy閱讀 13,928評論 0 15
  • 看過很多產品設計的文章,很少有對消息系統這個模塊的設計講得比較清晰的,最近搜集了一些資料,結合實際例子梳理了消息系...
    jason_peng閱讀 2,823評論 3 46