消息系統(tǒng)的設(shè)計(jì)

背景

在一個(gè)系統(tǒng)中,資源,數(shù)據(jù)會(huì)持續(xù)不斷的更新。而用戶如果需要知道這些數(shù)據(jù)的更新,就需要一個(gè)系統(tǒng),將系統(tǒng)中不斷更新的數(shù)據(jù)流,發(fā)送給相關(guān)的用戶。

這個(gè)系統(tǒng)應(yīng)該具備如下的幾個(gè)功能:

  1. 可以根據(jù)配置信息,在資源,數(shù)據(jù)更新時(shí),生成更新的消息。
  2. 可以將消息發(fā)送給相關(guān)的用戶。
  3. 用戶可以根據(jù)自定義的配置,配置是否接收消息推送。

針對(duì)這幾個(gè)需求,來(lái)設(shè)計(jì)一個(gè)可靈活擴(kuò)展的消息系統(tǒng)。

系統(tǒng)設(shè)計(jì)

將系統(tǒng)拆分成2個(gè)部分:

  1. 消息的產(chǎn)生
  2. 消息的發(fā)送

消息的產(chǎn)生

當(dāng)資源的更新,觸發(fā)了資源上的消息產(chǎn)生規(guī)則,就會(huì)產(chǎn)生消息。對(duì)于資源的更新,可能會(huì)觸發(fā)多條消息產(chǎn)生規(guī)則,產(chǎn)生多條通知,發(fā)給不同的用戶不同的消息。所以這里每條消息產(chǎn)生規(guī)則,對(duì)應(yīng)一個(gè)消息模版。

消息的產(chǎn)生規(guī)則,由動(dòng)作觸發(fā)規(guī)則(rule),接受者(recipient)2部分組成。

  1. 動(dòng)作觸發(fā)規(guī)則是一個(gè)主謂短語(yǔ)(executor + action),或者主謂賓短語(yǔ)(executor + action + target),記錄了誰(shuí)對(duì)資源做了什么操作。消息產(chǎn)生規(guī)則作用于某一類的資源(executor / target)。這里的資源是一個(gè)抽象的對(duì)象類型。
  2. 接收者這里指的是某一個(gè)抽象的角色,描述了接受者與被操作資源或者動(dòng)作執(zhí)行者的關(guān)系。

比如:

  • xxx@我
rule recipient
somebody_@_somebody user
  • xxx評(píng)論了我的一條微博
rule recipient
somebody_comment_weibo author
  • xxx給我發(fā)了一條私信
rule recipient
somebody_send_message user
  • 你的好友xxx登錄了
rule recipient
somebody_login friend

還有一種情況,當(dāng)執(zhí)行了某種操作,觸發(fā)了多條條消息產(chǎn)生規(guī)則

比如:
當(dāng)管理員A刪除了一條微博,觸發(fā)了2條消息產(chǎn)生規(guī)則

  • 系統(tǒng)刪除了你的微博
rule recipient
somebody_delete_weibo author
  • 系統(tǒng)刪除了你收藏的微博
rule recipient
somebody_delate_weibo follower

消息的發(fā)送

系統(tǒng)根據(jù)用戶的訂閱,將消息發(fā)送給訂閱了消息的用戶。

用戶的訂閱,是用戶對(duì)具體資源(target / executor)上消息產(chǎn)生規(guī)則的訂閱((executor + action) / executor + action + target)。這里用戶訂閱的是具體的資源對(duì)象。

比如:

  • xxx@我
特定資源 消息產(chǎn)生規(guī)則
我(target) somebody_@_someone
  • xxx評(píng)論了我的一條微博
特定資源 消息產(chǎn)生規(guī)則
我的微博(target) somebody_comment_weibo
  • xxx給我發(fā)了一條私信
特定資源 消息產(chǎn)生規(guī)則
我(target) sombody_send_message
  • 你的好友xxx登錄了
特定資源 消息產(chǎn)生規(guī)則
好友(executor) somebody_login

消息的發(fā)送方式

消息的發(fā)送方式分為系統(tǒng)推送,和用戶拉取

  1. 推 push:推是當(dāng)消息產(chǎn)生時(shí),系統(tǒng)自動(dòng)將消息推送給訂閱用戶。
  2. 拉 pull:拉是當(dāng)消息產(chǎn)生時(shí),系統(tǒng)不自動(dòng)將消息推送給用戶,而是當(dāng)用戶主動(dòng)觸發(fā)拉取的動(dòng)作時(shí),獲得新的消息。

系統(tǒng)運(yùn)行發(fā)方式

當(dāng)某個(gè)具體資源的更新,觸發(fā)了這個(gè)資源上的消息產(chǎn)生規(guī)則,產(chǎn)生消息。系統(tǒng)再根據(jù)用戶在這個(gè)資源上的訂閱,將消息發(fā)送給訂閱了這個(gè)資源的消息的用戶。產(chǎn)生的消息和用戶通過(guò)用戶訂閱關(guān)聯(lián)起來(lái)。用戶可以根據(jù)訂閱的設(shè)置,來(lái)設(shè)置是否接收主動(dòng)推送的消息。

  1. 用戶設(shè)置好消息接收規(guī)則,確定哪些消息接收推送,哪些消息主動(dòng)拉取
  2. 系統(tǒng)自動(dòng)設(shè)置好各類資源的消息產(chǎn)生規(guī)則
  3. 資源在系統(tǒng)中創(chuàng)建時(shí),系統(tǒng)根據(jù)用戶的訂閱規(guī)則,位用戶訂閱新資源的各類消息創(chuàng)建規(guī)則,生成用戶訂閱
  4. 當(dāng)資源更新,觸發(fā)了資源的消息產(chǎn)生規(guī)則,產(chǎn)生消息
  5. 系統(tǒng)根據(jù)用戶的訂閱,確定把哪些消息發(fā)送給用戶,保存到用戶消息列表中
  6. 系統(tǒng)根據(jù)用戶設(shè)置的消息接收規(guī)則,決定是推送消息給用戶,還是讓用戶拉取消息

系統(tǒng)建模

根據(jù)以上的分析,可以知道,系統(tǒng)中有以下幾個(gè)實(shí)體類:

  1. 資源(target/executor)
資源可以是是系統(tǒng)中的各類對(duì)象模型

這里的資源可能是被操作的對(duì)象,也可能是動(dòng)作的執(zhí)行者。例如:

  • 好友登錄:target 是 好友
  • 有人評(píng)論了文章:target 是 文章
  • 微博被刪除:target 是 微博
  1. 消息產(chǎn)生規(guī)則(rule)/消息訂閱規(guī)則
// 消息產(chǎn)生規(guī)則
[
  {
    'rule': 'user_update_weibo', // 觸發(fā)規(guī)則
    'targetType': 'weibo', // 觸發(fā)規(guī)則作用的對(duì)象類型
    'relationship': 'follow', // 觸發(fā)對(duì)象與訂閱對(duì)象的關(guān)系
    'role': 'user', // 訂閱對(duì)象在系統(tǒng)中的角色
    'obtainType': 0 // 消息的發(fā)送方式:0.推,1.拉
  },
  {
    'rule': 'user_update_weibo',
    'targetType': 'weibo',
    'relationship': 'author',
    'role': 'user',
    'obtainType': 0
  },
  {
    'rule': 'user_comment_weibo',
    'targetType': 'weibo',
    'relationship': 'author',
    'role': 'user',
    'obtainType': 0
  },
  {
    'rule': 'user_delete_weibo',
    'targetType': 'weibo',
    'relationship': 'author',
    'role': 'user',
    'obtainType': 0
  }
  {
    'rule': 'user_delete_weibo',
    'targetType': 'weibo',
    'relationship': 'follow',
    'role': 'user',
    'obtainType': 0
  },
  {
    'rule': 'user_delete_weibo',
    'targetType': 'weibo',
    'relationship': 'admin',
    'role': 'admin',
    'obtainType': 1
  },
  {
    'rule': 'user_follow_someone',
    'targetType': 'user',
    'relationship': 'self',
    'role': 'user',
    'obtainType': 0
  },
  {
    'rule': 'user_publish_weibo',
    'targetType': 'user',
    'relationship': 'follow',
    'role': 'user',
    'obtainType': 0
  },
  {
    'rule': 'user_login',
    'targetType': 'user',
    'relationship': 'friend',
    'role': 'user',
    'obtainType': 0
  }
]

消息生成規(guī)則由如下幾部分組成:

  • rule: 觸發(fā)規(guī)則

觸發(fā)規(guī)則用一個(gè)字符串表示,作為規(guī)則的唯一標(biāo)識(shí),也可以從字面上直接看出消息的規(guī)則,便于理解。每條規(guī)則是一個(gè)主謂短語(yǔ)(executor_action),或者主謂賓短語(yǔ)(executor_action_target)。
消息產(chǎn)生規(guī)則作用于某一類資源。但是對(duì)于不同的用戶,和資源的關(guān)系不同,收到的消息不同,所以生成消息的規(guī)則也不同。所以通過(guò)用戶和資源的關(guān)系,分組資源的消息產(chǎn)生規(guī)則。

  • targetType: 觸發(fā)規(guī)則作用的對(duì)象類型

記錄觸發(fā)規(guī)則作用的對(duì)象類型,可以通過(guò)對(duì)象類型,查出這個(gè)對(duì)象上所有的觸發(fā)規(guī)則。

  • relationship: 觸發(fā)對(duì)象與訂閱對(duì)象的關(guān)系

規(guī)則作用資源和訂閱者之間的關(guān)聯(lián)關(guān)系類別。當(dāng)資源被創(chuàng)建時(shí),或者用戶和資源發(fā)生關(guān)聯(lián)時(shí),根據(jù)用戶和資源的關(guān)系類型,訂閱不同的消息規(guī)則。

  • role: 訂閱對(duì)象在系統(tǒng)中的角色

對(duì)于不同角色的用戶,對(duì)于同一種資源,需要配置的規(guī)則也不一樣,比如不需要把管理員的訂閱規(guī)則,保存到普通用戶設(shè)置里。這里的role,可以和系統(tǒng)里的角色系統(tǒng)相關(guān)聯(lián),為不同的角色,配置不同的訂閱規(guī)則。

  • obtainType: 消息的發(fā)送方式:0.推,1.拉

消息產(chǎn)生規(guī)則相對(duì)固定,并且每次增加,需要實(shí)現(xiàn)相應(yīng)的消息模版,無(wú)法通過(guò)增加配置自動(dòng)生效。所以這里直接使用配置文件或者配置類保存信息,比較簡(jiǎn)單方便,不需要對(duì)外提供管理編輯的接口。

  1. 消息(notify)
create table notify (
  id int,
  rule varchar comment '消息產(chǎn)生規(guī)則',
  obtain_type int comment '消息的獲取方式:0.推,1.拉',
  target_id int comment '消息產(chǎn)生規(guī)則作用的對(duì)象',
  target_type int comment '消息產(chǎn)生規(guī)則作用的對(duì)象類型',
  content varchar comment '消息內(nèi)容',
  sender_id int comment '消息發(fā)送者id',
  sender_type int comment '消息發(fā)送者類型:0.系統(tǒng),1.用戶,...',
  notify_type int comment '消息類型:0.公告,1.新聞,2.活動(dòng),3.feed,...',
  create_time timestamp comment '消息創(chuàng)建時(shí)間'
) comment = '消息'

說(shuō)明下幾個(gè)重點(diǎn)的字段:

  • target_id,可能是動(dòng)作操作對(duì)象的id,也可能是動(dòng)作執(zhí)行者的id。
  • target_type,通過(guò)target_type,區(qū)分是不同的被操作對(duì)象還有動(dòng)作執(zhí)行者。
  • sender_id,當(dāng)是系統(tǒng)發(fā)送的消息時(shí),這里可以為空,或者某個(gè)特殊id。
  • sender_type,可以區(qū)分出是系統(tǒng)發(fā)送的還是用戶發(fā)送的。
  • content,消息內(nèi)容中動(dòng)態(tài)的部分,可能需要?jiǎng)幼鲌?zhí)行者,動(dòng)作,被操作對(duì)象,或者其他各種相關(guān)資源的數(shù)據(jù)來(lái)填充。因?yàn)樾枰臄?shù)據(jù)無(wú)法確定,所以這里交給每個(gè)消息產(chǎn)生規(guī)則的實(shí)現(xiàn)者取實(shí)現(xiàn)相應(yīng)的消息模版。
  1. 消息接收者(recipient)
訂閱消息的用戶
  1. 訂閱(subscribe)
create table subscribe (
  id int,
  rule int comment '消息產(chǎn)生規(guī)則',
  target_id int comment '消息產(chǎn)生規(guī)則作用的對(duì)象',
  target_type int comment '消息產(chǎn)生規(guī)則作用的對(duì)象類型',
  create_time timestamp comment '訂閱時(shí)間',
  valid int comment '訂閱是否有效:0.無(wú)效,1有效'
) comment = '用戶訂閱'
  1. 訂閱設(shè)置(subscribeConfig)
保存具體用戶訂閱了哪些消息產(chǎn)生規(guī)則,以及針對(duì)這條規(guī)則,是否接收系統(tǒng)的主動(dòng)推送
create table subscribe_config (
  id int,
  rule int comment '消息產(chǎn)生規(guī)則',
  enable_recieve int comment '針對(duì)這條規(guī)則,是否接收系統(tǒng)的主動(dòng)推送:0.不接收,1.接收'
) comment = '用戶訂閱設(shè)置'
  1. 用戶消息列表(recipientNotify)
create table recipient_notify (
  id int,
  recipient_id int comment '消息接收者id',
  notify_id int comment '消息id',
  create_time timestamp comment '消息創(chuàng)建時(shí)間',
  read_time timestamp comment '用戶閱讀時(shí)間'
) comment = '用戶消息列表'

系統(tǒng)服務(wù)

根據(jù)系統(tǒng)的運(yùn)行方式,和系統(tǒng)建模。系統(tǒng)的服務(wù)需要以下幾個(gè)功能:

  • getAllRuleByObjectType(objectType) 獲取某類對(duì)象的所有消息產(chǎn)生規(guī)則

  • setPushConfig(user) 用戶設(shè)置獲取推送規(guī)則

設(shè)置用戶推送規(guī)則,是否接受推送

  • subscribe(user, rule, target) 用戶訂閱

設(shè)置用戶訂閱,將用戶和消息產(chǎn)生規(guī)則和規(guī)則作用的具體對(duì)象關(guān)聯(lián)

  • cancelSubscribe(user, rule, target) 取消用戶訂閱

取消用戶訂閱

  • listAllSubscribe(user) 獲取用戶的所有訂閱

獲取用戶所有具體對(duì)象上的訂閱

  • createNotify(rule, target, sender, source) 創(chuàng)建消息

根據(jù)消息產(chǎn)生規(guī)則,創(chuàng)建消息,source是消息內(nèi)容需要的所有數(shù)據(jù)

  • pushNotify(receipient, notify) 推送消息到用戶消息列表

將消息保存到用戶消息列表,同時(shí)發(fā)送推送消息

  • pullNotify(receipient, notify) 拉取消息到用戶消息列表

將消息保存到用戶消息列表

  • getUserSubscribeConfig(user) 獲取用戶訂閱規(guī)則

獲取用戶訂閱的所有消息產(chǎn)生規(guī)則

  • getUsersBySubscribe(subscribe) 查詢所有訂閱了這條訂閱的用戶

  • getNotifyBySubscribe(subscribe) 查詢所有根據(jù)這條消息產(chǎn)生規(guī)則和作用目標(biāo),生成的消息

  • readRecipientNotify(now) 讀消息列表

設(shè)置讀取的消息的讀取時(shí)間

時(shí)序圖
消息的創(chuàng)建,訂閱,推送,拉取

Paste_Image.png
Paste_Image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容