【问题标题】:How do social networking websites handle notifications社交网站如何处理通知
【发布时间】:2014-07-27 00:56:46
【问题描述】:

我正在实施一个小型社交网站,我正在尝试实施通知。

通知有以下要求

  • 所有用户都会在他们关注的用户进行某些活动时收到通知(更改个人资料图片,例如发布帖子、创建帖子、发表评论等...
  • 通知的状态为已读或未读(如 facebook 和 stackoverflow)。当用户的一组通知未读时,就像 facebook 一样,用户将继续在其导航栏上看到已读通知图标

这是我想用 MySQL 实现它的方式:

通知表type_of_eventevent_idmessage Notification_read 表user_idnotification_idread

  • 每当用户执行触发发送通知的事件时 对于所有关注者,该通知存储在Notification 表中
  • 将为新创建的通知填写Notification_read 表,其中包含新通知的 ID 和应收到通知的每个用户的 ID(通知创建者的关注者)
  • 每当用户收到通知并阅读它们时,通知将被标记为read

这个解决方案对我来说似乎效率很低,因为每次发生通知时,通知都会多次写入notification_read 表中(取决于用户拥有多少关注者)

谁能告诉我这个问题是否有更好的解决方案

【问题讨论】:

    标签: ruby-on-rails facebook notifications social-networking


    【解决方案1】:

    您可以使用has_many through 关联。它非常适合这种情况。此外,您可以使模型 Notification belongs_to :event 并且事件类型应存储在 Event 模型中。您可以通过以下方式查看更多信息:http://guides.rubyonrails.org/association_basics.html

    【讨论】:

    • 事件不存储在同一个模型中。我想要像LikePostComment 等的单独模型。另外,我知道我可以做 has_many,但问题是我是否真的应该存储那么多重复项(或者通过 notification_read 使用 has_many,或者只是将其全部存储在通知中)。因为如果一个用户做了一个简单的事件并且他有 1000 个关注者,那么每个小事件我都会有 1000 条新记录。而且事件会经常发生。
    【解决方案2】:

    您可以序列化事件的接收者并将其存储在字段中。这样不管有多少关注者,一个事件的通知永远是一个。

    Actor   ObjectType    ObjectID  Date        Recipients
    --------------------------------------------------------------------------------------
    UserA   Post          1         2014-03-02  [
                                                {'u': 1, 'r': False, 'dr': None},
                                                {'u': 2, 'r': True, 'dr': '2013-03-02'},
                                                {'u': 3, 'r': False, 'dr': None},
                                                {'u': 4, 'r': False, 'dr': None},
                                                ]
    UserB   Photo         2         2014-03-02  [
                                                {'u': 4, 'r': False, 'dr': None},
                                                {'u': 5, 'r': True, 'dr': '2013-03-02'},
                                                {'u': 6, 'r': False, 'dr': None},
                                                {'u': 8, 'r': False, 'dr': None},
                                                ]
    

    u 是收件人 id,r 是读取标志,dr 是读取日期。这样,您仍然可以进行一些查找(例如:显示 UserB 的通知),而无需执行许多 I/O,但是您必须创建帮助程序类来对通知进行后处理,这可能不会占用太多LOC 和 CPU 资源。

    但在你这样做之前,再想想你的“效率低下”问题,是关于阅读吗?如果是的话,正确的索引读取应该不是问题,如果您有正确的索引和查询,像 MySQL 和 Postgres 这样的数据库可以处理数百万(甚至数千万)行。如果担心写作,您可以将其作为后台任务,让用户继续他们的活动,而不会被进程阻止。上面的解决方案可能会减少 I/O,但它会牺牲简单性,尤其是当您希望将来重新访问或扩展该功能时。

    【讨论】:

      【解决方案3】:

      对于这类问题,通常需要权衡读取与写入。

      在这种情况下,写入可以用将通知写入数据库所需的时间和存储成本来表示。

      对于阅读,它是关于您可以多快获得特定用户的通知。

      在@kecebongsoft 的示例中,您的写入效率很高(因为字段相对较少),但读取需要很多时间。在数据库的文本字段中搜索通常很慢。对于用户,如果列出了用户,则必须检查所有通知及其检查字段,如果列出,状态是什么。

      通过为每个用户存储单独的通知,您可以增加存储空间,但您在阅读方面会收获很多。也就是说,因为您可以使用用户 ID 搜索索引表并快速找到任何通知及其状态。

      当然,有非常复杂的混合方法。但一般来说,大网站不喜欢透露这些秘密:)

      如果您从网站开始,我不会担心写作成本。用许多通知填充一个表并不昂贵。最后,它们可能都相对较小。您甚至可以考虑修剪旧通知。

      更重要的是阅读速度。发现您网站的人不会对您高效的存储适配器印象深刻,但会在收到通知时注意到照明速度。

      我的建议:现在关注读取速度,当您扩展时担心存储效率。

      最后一点:如果您在创建通知时创建了大量数据库条目,请查看从主网络服务器线程分派的解决方案。这样,创建通知的人可以快速继续,您可以在后台执行昂贵的 SQL 操作。速度更快!

      【讨论】:

        【解决方案4】:

        像您所说的那样的大型站点通常使用异步消息传递代理和协议,例如 ActiveMQ、RabbitMQ 等,使用诸如 JMS、STOMP、AMQP、MQTT 之类的协议,这样的例子不胜枚举。开。

        无论如何,我可能会如何实现这样的事情,即每个用户会话都有一个订阅其相应用户通知队列的消息侦听器。取决于所讨论的协议将确定一个人将如何准确地做到这一点,但最简单的方法是让每个用户都有自己的队列。消息代理倾向于通过文件系统和日志文件的组合来处理消息持久性,这比关系数据库要快得多(想想看;这些数据不是关系的)。

        既然这是 Ruby 并且您没有说您正在使用 JRuby,那么您选择的消息传递可能会属于 STOMP 或 MQTT,因为其他的往往更重量级。

        【讨论】:

          猜你喜欢
          • 2014-09-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-05-18
          • 2016-02-01
          • 2014-04-06
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多