2012-03-16 95 views
157

我正在为我们的页面(社交游戏类型)构建Facebook样式通知系统,现在我正在研究设计此类系统的最佳方式。我对如何将通知推送给用户或类似的东西不感兴趣(现在甚至是)。我正在研究如何在服务器上构建系统(如何存储通知,如何存储它们,如何获取它们等)。构建通知系统

所以......一些要求,我们有:

  • 在高峰时期,我们有1K左右同时登录用户(以及更多的客人,但他们不事这里他们不会有通知)会产生很多事件
  • 会有不同类型的通知(用户A已将您添加为朋友,用户B已对您的个人资料发表了评论,用户C已经喜欢您的图片,用户D已经在游戏X中击败了您,...)
  • 大多数事件会为1个用户生成1个通知(用户X已经喜欢您的图片),但会出现一种情况t会生成很多通知(例如用户Y的生日)
  • 通知应该组合在一起;如果例如四个不同的用户喜欢一些图像,该图像的所有者应该得到一个通知,指出四个用户都喜欢的形象,而不是四个单独的通知(就像FB一样)

行,所以我在想什么我应该创建一些队列,以便在事件发生时存储事件。然后我会有一个后台作业(gearman?),它会查看该队列并根据这些事件生成通知。这项工作然后将通知存储在每个用户的数据库中(所以如果一个事件影响10个用户,将会有10个单独的通知)。然后,当用户打开一个包含通知列表的页面时,我会阅读所有这些通知(我们希望限制为100个最新通知)并将它们组合在一起,然后显示出来。

事情我很担心这种做法:

  • 复杂的地狱:)
  • 在数据库这里最好的存储(我们正在使用MySQL),或者我应该用别的东西(Redis的好像也很适合)
  • 我应该存储什么作为通知?用户ID,发起事件的用户ID,事件类型(以便我可以将它们分组并显示适当的文本),但是我有点不知道如何存储通知的实际数据(例如URL &标题被喜欢的图像)。我应该在生成通知时“烘焙”该信息,还是应该存储受影响的记录(图像,配置文件等)的ID,并在显示通知时将信息从数据库中拉出。
  • 即使我在显示通知页面时不得不处理100个通知,在这里性能仍然可以正常运行
  • 每个请求可能存在性能问题,因为我必须向用户显示未读通知的数量(这可能是一个问题,因为我会将通知分组在一起)。这可以避免,虽然如果我在后台生成通知视图(在何处分组),而不是即时的

因此,您如何看待我提出的解决方案和我的担忧?如果您认为我应该提及其他与此相关的内容,请发表评论。

哦,我们在页面上使用PHP,但这不应该是我认为的一个重要因素。

+0

需要多少时间才能将此通知系统作为一个人的努力来完成。我只是想估计一下相应的时间表。 – Shaharyar 2015-11-24 10:55:36

+0

@Shaharyar我认为这取决于通知系统的复杂性。 – tyan 2016-04-20 06:43:32

+0

我使用与MySQL相同的系统来构建基于优先级的通知系统。好的是,它可以扩展到几千个用户,如果超过这个数字,它会爆炸,特别是Android和GCM。我想知道MySQL的替代品,比如redis,rabbitMQ,Kafka,它们自然地展现了一个消息队列,一种功能。 – 2017-01-23 13:57:33

回答

154

通知是关于某人(对象=事件,友谊..)被某人(演员)改变(动词=添加,请求..)并报告给用户(主题)。这是一个规范化的数据结构(尽管我已经使用了MongoDB)。您需要通知某些用户有关更改。所以它是每个用户的通知..这意味着如果有100个用户参与,你会生成100个通知。

╔═════════════╗  ╔═══════════════════╗  ╔════════════════════╗ 
║notification ║  ║notification_object║  ║notification_change ║ 
╟─────────────╢  ╟───────────────────╢  ╟────────────────────╢ 
║ID   ║—1:n—→║ID     ║—1:n—→║ID     ║ 
║userID  ║  ║notificationID  ║  ║notificationObjectID║ 
╚═════════════╝  ║object    ║  ║verb    ║ 
        ╚═══════════════════╝  ║actor    ║ 
               ╚════════════════════╝ 

(添加在您认为合适的时间字段)

这基本上是为每个分组对象的更改,这样你就可以说:“你有3个好友请求”。每个演员的分组是有用的,所以你可以说“用户詹姆斯邦德在你的床上做出了改变”。这也可以根据需要翻译和计算通知。

但是,由于对象只是一个ID,所以需要使用单独的调用来获取关于所需对象的所有额外信息,除非对象实际发生更改并且要显示该历史记录(例如“用户更改了事件标题...“)

由于通知对于网站用户来说接近实时,所以我会将它们与nodejs + websockets客户端绑定,并将php更新添加到所有侦听器的nod​​ejs中,以便添加更改。

+0

+1 @Artjom,这是一篇很棒的文章。我想知道,你提到'object'只是一个id。你怎么知道它是什么类型的对象?例如,它可能是朋友请求或其他任何内容,那么如何将通知与适当的事件相关联?非常感谢 – Mick 2013-04-29 01:14:57

+1

notification_object.object标识更改类型,就像字符串“友谊” 我对其更多数据的改变对象的实际引用在notification_change.notificationObjectID – 2013-04-29 07:35:41

+0

我明白了,这非常聪明。那么,你是否需要将对象的类存储在数据库中的任何地方呢?或者你有没有从存储在'notification_object.object'中的字符串(如'friendship')检索类的方法?因为如果我们希望获得关于通知对象的一些信息,我们需要使用它的类和它的标识符来加载它。我对吗?你有这个技巧吗?像一个事件监听器,或将'notification_object.object'及其标识符转换为实际对象的东西?非常感谢@Artjom,这是巨大的帮助:) – Mick 2013-04-29 08:45:36

21

这实在是一个抽象的问题,所以我想我们只需要讨论它,而不是指出你应该做什么或不应该做什么。

这就是我想你的顾虑:

  • 是,通知系统是复杂的,但不是地狱,但。在建模和实现这些系统时可以有多种不同的方法,并且可以具有从中等到高级的复杂性;

  • Pesonally,我总是试图使东西数据库驱动。为什么?因为我可以保证对所发生的一切有完全的控制 - 但那只是我自己,你可以在没有数据库驱动的方法的情况下进行控制;相信我,你会想要控制这种情况;

  • 让我举例说明一个真实的案例给你,这样你就可以从某个地方开始。在过去的一年中,我已经在某种社交网络中建立并实施了一个通知系统(当然不是脸谱网)。我用来在那里存储通知的方式?我有一个notifications表,其中我保留了generator_user_id(生成通知的用户的ID),target_user_id(很明显,是不是?),notification_type_id(引用具有通知类型的不同表)以及我们需要的所有必要的东西来填充我们的表格(时间戳,标志等)。我的notification_types表用于与notification_templates表关联,该表为每种类型的通知存储特定模板。例如,我有一个POST_REPLY类型,它的模板类型如{USER} HAS REPLIED ONE OF YOUR #POSTS。从那里,我只是将{}作为变量,将#作为参考链接;

  • 是的,性能应该必须没问题。当你想到通知时,你会想到服务器从头到脚的推动。要么你打算用ajax请求做什么,你都必须担心性能。但我认为这是第二次关注。

我设计的模型当然不是唯一可以遵循的模型,也不是最好的模型。我希望我的回答至少能让你走向正确的方向。

+0

为什么我不能控制其他数据存储? – 2012-03-16 11:40:26

+0

嗯,我没有这么说。我说的是我只能用数据库驱动的方法保证数据控制;但那只是我。我要重述那个。 – 2012-03-16 11:44:28

+0

@DanielRibeiro通知模板中的占位符({...})需要替换数据库中不同类型通知的不同表集合中占位符的数据。例如。一个模板是“{user}喜欢你的照片”,另一个模板是“你的{Pagename}有新的样子。”等{PageName}和{用户}和其他占位符将从不同的数据库表映射,那么动态获取占位符值的模式应该是什么。 – 2017-03-27 14:43:32

7
╔════════════════════╗ 
║notification  ║ 
╟────────────────────╢ 
║Username   ║ 
║Object    ║ 
║verb    ║ 
║actor    ║ 
║isRead    ║ 
╚════════════════════╝ 

这看起来是一个很好的答案,而不是2个集合。你可以通过用户名,对象和isRead查询获得新的事件(如3个待处理的朋友请求,4个问题等等)。

让我知道这个模式是否有问题。

+2

最常见的答案是使用规范化的数据结构,这意味着表中没有冗余。你的答案是否这样做? – 2014-10-08 13:52:06