ホームページ  >  記事  >  バックエンド開発  >  メッセージ システムの設計と実装、メッセージ システムの設計と実装_PHP チュートリアル

メッセージ システムの設計と実装、メッセージ システムの設計と実装_PHP チュートリアル

WBOY
WBOYオリジナル
2016-07-12 08:55:511194ブラウズ

メッセージ システムの設計と実装、メッセージ システムの設計と実装

記事/JC_Huang (概要本の著者)
元のリンク: http://www.jianshu.com/p/f4d7827821f1
著作権は著者に属します。再版については著者に連絡し、「ブリーフブックの著者」を承認し、マークを付けます。

製品分析

まず、メッセージが市場でどのように実装されるかを見てみましょう。

ジアンシュ

Jianshuのメッセージシステムは主に2種類に分かれます

  • ショートメッセージ
  • リマインダー

ショートメッセージ
ショートメッセージの性質は、実際にはプライベートメッセージと同じであり、特定の情報内容を含むユーザーからユーザーに送信されるメッセージです。


シンプルな文字

リマインダー
リマインダーはシステムによって送信されるメッセージであり、そのコピー形式は固定されており、通常は特別なオブジェクトへのハイパーリンクが含まれています。


簡単なリマインダー

志胡

Zhihuは、Jianshuと同様に、主に2つのタイプに分けられます:

  • プライベートメッセージ
  • メッセージ

プライベートメッセージ
Jianshu と同様に、ユーザーからユーザーに送信されるメッセージ、または管理者からユーザーに送信されるメッセージにすることができます。


志胡のプライベートメッセージ

メッセージ
Zhihu のメッセージは、Jianshu のリマインダーよりもさらに優れており、ユーザーの読書プレッシャーを軽減するために複数の同様のメッセージを収集します。


知湖ニュース

メッセージの 3 つのカテゴリ

2 つの製品の簡単な分析を通じて、メッセージには 2 つのカテゴリがあると結論付けることができます。これに基づいて、アナウンスというカテゴリがもう 1 つ追加されます。
アナウンスの主な性質は、システムがサイト上のすべてのユーザーが読むことができる特定のコンテンツを含むメッセージを送信することです。
つまり、メッセージには 3 つのカテゴリがあります:

リマインダーの言語分析

短い本から一連のリマインダーのサンプルを取り出します:

  • 3dbe1bd90774さんがフォローしました
  • magicdawn があなたの記事「シングル サインオンを実装する 3 つの方法」を「いいね!」しました
  • 悪徳プログラム 「RESTful APIに基づいてユーザー権限制御を設計するには?」という記事が気に入りました。 》
  • alexcc4 さんが記事「Nodejs での単体テストの実装」を「いいね!」しました
  • 「RESTful API に基づいてユーザー権限制御を設計する方法」を参照しています。 》cnlinjieさんからコメントをいただきました
  • あなたの記事「セッション原則」がトピック「ios開発」に追加されました

文章の構造を分析し、リマインダーの内容を分析するだけです

リーリー

someone = リマインダーのトリガー、または送信者、送信者としてマークされます
do something = リマインダーのアクション、コメント、いいね、フォローはすべて 1 つのアクションに属し、アクションとしてマークされます
something = アクションのオブジェクトリマインダー (特定の) どの記事がターゲット
としてマークされているか、誰かの = リマインダー アクション オブジェクトの所有者、targetOwner

としてマークされている

これは明らかです。送信者と targetOwner は Web サイトのユーザーであり、ターゲットは特定の記事です。リマインダー オブジェクトが記事に限定されず、他にもある場合は、ターゲットをマークするために targetType を追加する必要があります。 . 記事とか。アクションは固定されています。Web サイト全体でリマインダーをトリガーするアクションはいくつかしかありません: コメント、いいね、フォロー... (またはビジネスがリマインダーを必要とするその他のアクション)

メッセージを受け取る 2 つの方法

  • プッシュ
  • 引く

Zhihu を例に挙げます。
プッシュは比較的一般的です。この質問をプッシュするための条件がトリガーされると (たとえば、誰かが質問に回答する)、通知が送信されます。フォロワーごとに送信されます。

プルはプッシュの逆で、少し面倒です。たとえば、ユーザーがオンラインになるたびに、各問題がポーリングされ、問題のイベント リストが表示されます。元のリストよりも大きなタイムスタンプを持つ情報が取得されます。

而我们则根据消息的不同分类采用不同的获取方式
通告和提醒,适合使用拉取的方式,消息产生之后,会存在消息表中,用户在某一特定的时间根据自己关注问题的表进行消息的拉取,然后添加到自己的消息队列中,

信息,适合使用推的方式,在发送者建立一条信息之后,同时指定接收者,把消息添加到接收者的消息队列中。

订阅

根据提醒使用拉取的方式,需要维护一个关注某一事物的列表。
这种行为,我们称之为:「订阅」Subscribe

一则订阅有以下三个核心属性

  • 订阅的目标 target
  • 订阅的目标类型 targetType
  • 订阅的动作 action

比如我发布了一篇文章,那么我会订阅文章《XXX》的评论动作,所以文章《XXX》每被人评论了,就需要发送一则提醒告知我。

订阅的规则还可以扩展
我喜欢了一篇文章,和我发布了一篇文章,订阅的动作可能不一样。
喜欢了一篇文章,我希望我订阅这篇文章更新、评论的动作。
而发布了一篇文章,我希望我只是订阅这篇文章的评论动作。

这时候就需要多一个参数:subscribReason
不同的subscribReason,对应着一个动作数组,
subscribReason = 喜欢,对应着 actions = [更新,评论]
subscribReason = 发布,对应着 actions = [评论]

订阅的规则还还可以扩展
用户可能会有一个自己的订阅设置,比如对于所有的喜欢的动作,我都不希望接收。
比如Knewone的提醒设置


Knewone提醒设置

所以我们需要再维护一个表:SubscriptionConfig,来存放用户的提醒设置。
并且,当用户没有提醒设置的时候,可以使用系统提供的一套默认设置:defaultSubscriptionConfig

聚合

如果我发布了一篇文章《XXX》,在我不在线的时候,被评论了10遍,当我一上线的时候,应该是收到十条信息类似于:「谁谁谁评论了你的文章《XXX》」?
还是应该收到一条信息:「甲、乙、丙、丁...评论了你的文章《XXX》」?

知乎在聚合上做的很优秀,要知道他们要实现这个还是挺有技术的:
知乎的消息机制,在技术上如何设计与规划?
网站的消息(通知)系统一般是如何实现的?

关于这部分功能,我们还没有具体的实现方法,暂时也无法讲得更加详细。⊙﹏⊙

五个实体

通过上面的分析,大概知道做这个消息系统,需要哪些实体类:

行为分解

说了这么多,整理一下整个消息流程的一些行为:

  • 系统或者管理员,创建消息
    • createNotify (make announce | remind | message)
  • 用户,订阅消息,取消订阅
    • subscribe, cancelSubscription
  • 用户管理订阅设置
    • getSubscriptionConfig, updateSubscriptionConfig
  • 用户,拉取消息
    • pullNotify (pull announce | remind | message | all)
  • 用户,查询消息队列
    • getUserNotify(get announce | remind | message | all)
  • 用户阅读消息
    • read
  >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

模型设计

Notify

<code class="javascript">id            : {type: <span class="hljs-string">'integer', primaryKey: <span class="hljs-literal">true},        <span class="hljs-comment">// 主键
content     : {type: <span class="hljs-string">'text'},    <span class="hljs-comment">// 消息的内容
type        : {type: <span class="hljs-string">'integer', required: <span class="hljs-literal">true, enum: [<span class="hljs-number">1, <span class="hljs-number">2, <span class="hljs-number">3]},  <span class="hljs-comment">// 消息的类型,1: 公告 Announce,2: 提醒 Remind,3:信息 Message
target      : {type: <span class="hljs-string">'integer'},    <span class="hljs-comment">// 目标的ID
targetType  : {type: <span class="hljs-string">'string'},    <span class="hljs-comment">// 目标的类型
action      : {type: <span class="hljs-string">'string'},    <span class="hljs-comment">// 提醒信息的动作类型
sender      : {type: <span class="hljs-string">'integer'},    <span class="hljs-comment">// 发送者的ID
createdAt    : {type: <span class="hljs-string">'datetime', required: <span class="hljs-literal">true}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code>

Save Remind
消息表,我们需要targettargetType字段,来记录该条提醒所关联的对象。而action字段,则记录该条提醒所关联的动作。
比如消息:「小明喜欢了文章」
则:

<code class="javascript">target = <span class="hljs-number">123,  <span class="hljs-comment">// 文章ID
targetType = <span class="hljs-string">'post',  <span class="hljs-comment">// 指明target所属类型是文章
sender = <span class="hljs-number">123456  <span class="hljs-comment">// 小明ID</span></span></span></span></span></span></code>

Save Announce and Message
当然,Notify还支持存储公告和信息。它们会用到content字段,而不会用到targettargetTypeaction字段。

UserNotify

<code class="javascript">id            : {type: <span class="hljs-string">'integer', primaryKey: <span class="hljs-literal">true},        <span class="hljs-comment">// 主键
isRead      : {type: <span class="hljs-string">'boolean', required: <span class="hljs-literal">true},   
user        : {type: <span class="hljs-string">'integer', required: <span class="hljs-literal">true},  <span class="hljs-comment">// 用户消息所属者
notify      : {type: <span class="hljs-string">'integer', required: <span class="hljs-literal">true}   <span class="hljs-comment">// 关联的Notify
createdAt    : {type: <span class="hljs-string">'datetime', required: <span class="hljs-literal">true}</span></span></span></span></span></span></span></span></span></span></span></span></span></code>

我们用UserNotify来存储用户的消息队列,它关联一则提醒(Notify)的具体内容。
UserNotify的创建,主要通过两个途径:

Subscription

<code class="javascript">target      : {type: <span class="hljs-string">'integer', required: <span class="hljs-literal">true},    <span class="hljs-comment">// 目标的ID
targetType  : {type: <span class="hljs-string">'string', required: <span class="hljs-literal">true},    <span class="hljs-comment">// 目标的类型
action      : {type: <span class="hljs-string">'string'},   <span class="hljs-comment">// 订阅动作,如: comment/like/post/update etc.
user        : {type: <span class="hljs-string">'integer'},
createdAt    : {type: <span class="hljs-string">'datetime', required: <span class="hljs-literal">true}</span></span></span></span></span></span></span></span></span></span></span></code>

订阅,是从Notify表拉取消息到UserNotify的前提,用户首先订阅了某一个目标的某一个动作,在此之后产生这个目标的这个动作的消息,才会被通知到该用户。
如:「小明关注了产品A的评论」,数据表现为:

<code class="javascript">target: <span class="hljs-number">123,  <span class="hljs-comment">// 产品A的ID
targetType: <span class="hljs-string">'product',
action: <span class="hljs-string">'comment',
user: <span class="hljs-number">123  <span class="hljs-comment">// 小明的ID</span></span></span></span></span></span></code>

这样,产品A下产生的每一条评论,都会产生通知给小明了。

SubscriptionConfig

<code class="javascript">action: {type: <span class="hljs-string">'json', required: <span class="hljs-literal">true},   <span class="hljs-comment">// 用户的设置
user: {type: <span class="hljs-string">'integer'}</span></span></span></span></code>

不同用户可能会有不一样的订阅习惯,在这个表中,用户可以统一针对某种动作进行是否订阅的设置。而默认是使用系统提供的默认配置:

<code class="javascript">defaultSubscriptionConfig: {
  <span class="hljs-string">'comment'   : <span class="hljs-literal">true,    <span class="hljs-comment">// 评论
  <span class="hljs-string">'like'      : <span class="hljs-literal">true,    <span class="hljs-comment">// 喜欢
}</span></span></span></span></span></span></code>
<p>在这套模型中,<code>targetType</code>、<code>action</code>是可以根据需求来扩展的,例如我们还可以增加多几个动作的提醒:<code>hate</code>被踩、<code>update</code>被更新....诸如此类。</p>

配置文件 NotifyConfig

<code class="javascript"><span class="hljs-comment">// 提醒关联的目标类型
targetType: {
  PRODUCT : <span class="hljs-string">'product',    <span class="hljs-comment">// 产品
  POST    : <span class="hljs-string">'post'    <span class="hljs-comment">// 文章
},

<span class="hljs-comment">// 提醒关联的动作
action: {
  COMMENT   : <span class="hljs-string">'comment',  <span class="hljs-comment">// 评论
  LIKE      : <span class="hljs-string">'like',     <span class="hljs-comment">// 喜欢
},

<span class="hljs-comment">// 订阅原因对应订阅事件
reasonAction: {
  <span class="hljs-string">'create_product'  : [<span class="hljs-string">'comment', <span class="hljs-string">'like']
  <span class="hljs-string">'like_product'    : [<span class="hljs-string">'comment'],
  <span class="hljs-string">'like_post'       : [<span class="hljs-string">'comment'],
},

<span class="hljs-comment">// 默认订阅配置
defaultSubscriptionConfig: {
  <span class="hljs-string">'comment'   : <span class="hljs-literal">true,    <span class="hljs-comment">// 评论
  <span class="hljs-string">'like'      : <span class="hljs-literal">true,    <span class="hljs-comment">// 喜欢
}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code>

服务层 NotifyService

NotifyService拥有以下方法:

  • createAnnounce(content, sender)
  • createRemind(target, targetType, action, sender, content)
  • createMessage(content, sender, receiver)
  • pullAnnounce(user)
  • pullRemind(user)
  • subscribe(user, target, targetType, reason)
  • cancelSubscription(user, target ,targetType)
  • getSubscriptionConfig(userID)
  • updateSubscriptionConfig(userID)
  • getUserNotify(userID)
  • read(user, notifyIDs)

各方法的处理逻辑如下:

createAnnounce(content, sender)

createRemind(target, targetType, action, sender, content)

createMessage(content, sender, receiver)

pullAnnounce(user)

pullRemind(user)

subscribe(user, target, targetType, reason)

cancelSubscription(user, target ,targetType)

getSubscriptionConfig(userID)

updateSubscriptionConfig(userID)

getUserNotify(userID)

read(user, notifyIDs)

时序图

提醒的订阅、创建、拉取


提醒的订阅、创建、拉取


我们可以在产品创建之后,调用NotifyService.subscribe方法,
然后在产品被评论之后调用NotifyService.createRemind方法,
再就是用户登录系统或者其他的某一个时刻调用NotifyService.pullRemind方法,
最后在用户查询消息队列的时候调用NotifyService.getUserNotify方法。

公告的创建、拉取


公告的创建、拉取


在管理员发送了一则公告的时候,调用NotifyService.createAnnounce方法,
然后在用户登录系统或者其他的某一个时刻调用NotifyService.pullAnnounce方法,
最后在用户查询消息队列的时候调用NotifyService.getUserNotify方法。

信息的创建


信息的创建


信息的创建,只需要直接调用NotifyService.createMessage方法就可以了,
在下一次用户查询消息队列的时候,就会查询这条信息。


 

   

www.bkjia.com本当http://www.bkjia.com/PHPjc/1114983.html技術記事メッセージ システムの設計と実装、メッセージ システムの設計と実装 text/JC_Huang (概要本の著者) 元のリンク: http://www.jianshu.com/p/f4d7827821f1 著作権は著者に属します。お問い合わせください...
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。