消息系統(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ī)則作用于某一類(lèi)的資源(executor / target)跋涣。這里的資源是一個(gè)抽象的對(duì)象類(lèi)型。
  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è)置好各類(lèi)資源的消息產(chǎn)生規(guī)則
  3. 資源在系統(tǒng)中創(chuàng)建時(shí)驮肉,系統(tǒng)根據(jù)用戶的訂閱規(guī)則,位用戶訂閱新資源的各類(lèi)消息創(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í)體類(lèi):

  1. 資源(target/executor)
資源可以是是系統(tǒng)中的各類(lèi)對(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ì)象類(lèi)型
    '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ī)則作用于某一類(lèi)資源。但是對(duì)于不同的用戶犹撒,和資源的關(guān)系不同折联,收到的消息不同,所以生成消息的規(guī)則也不同识颊。所以通過(guò)用戶和資源的關(guān)系诚镰,分組資源的消息產(chǎn)生規(guī)則。

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

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

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

規(guī)則作用資源和訂閱者之間的關(guān)聯(lián)關(guān)系類(lèi)別刃跛。當(dāng)資源被創(chuàng)建時(shí)抠艾,或者用戶和資源發(fā)生關(guān)聯(lián)時(shí),根據(jù)用戶和資源的關(guān)系類(lèi)型桨昙,訂閱不同的消息規(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)生效。所以這里直接使用配置文件或者配置類(lèi)保存信息颈娜,比較簡(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ì)象類(lèi)型',
  content varchar comment '消息內(nèi)容',
  sender_id int comment '消息發(fā)送者id',
  sender_type int comment '消息發(fā)送者類(lèi)型:0.系統(tǒng)蛹磺,1.用戶,...',
  notify_type int comment '消息類(lèi)型: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ì)象類(lèi)型',
  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) 獲取某類(lèi)對(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)系作者
  • 序言:七十年代末拗慨,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子奉芦,更是在濱河造成了極大的恐慌赵抢,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件声功,死亡現(xiàn)場(chǎng)離奇詭異烦却,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)先巴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)其爵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人筹裕,你說(shuō)我怎么就攤上這事醋闭。” “怎么了朝卒?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵证逻,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我抗斤,道長(zhǎng)囚企,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任瑞眼,我火速辦了婚禮龙宏,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘伤疙。我一直安慰自己银酗,他們只是感情好辆影,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著黍特,像睡著了一般蛙讥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上灭衷,一...
    開(kāi)封第一講書(shū)人閱讀 51,146評(píng)論 1 297
  • 那天次慢,我揣著相機(jī)與錄音,去河邊找鬼翔曲。 笑死迫像,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的瞳遍。 我是一名探鬼主播闻妓,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼傅蹂!你這毒婦竟也來(lái)了纷闺?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤份蝴,失蹤者是張志新(化名)和其女友劉穎犁功,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體婚夫,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡浸卦,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了案糙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片限嫌。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖时捌,靈堂內(nèi)的尸體忽然破棺而出怒医,到底是詐尸還是另有隱情,我是刑警寧澤奢讨,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布稚叹,位于F島的核電站,受9級(jí)特大地震影響拿诸,放射性物質(zhì)發(fā)生泄漏扒袖。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一亩码、第九天 我趴在偏房一處隱蔽的房頂上張望季率。 院中可真熱鬧,春花似錦描沟、人聲如沸飒泻。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)泞遗。三九已至衰猛,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間刹孔,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工娜睛, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留髓霞,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓畦戒,卻偏偏與公主長(zhǎng)得像方库,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子障斋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

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