消息推送中的已读消息和未读消息设计难题

“站内信”有两个基本功能:
1.  点到点的消息传送。 用户给用户发送站内信,管理员给用户发送站内信。
2.  点到面的消息传送。 管理员给用户(指定满足某一条件的用户群)群发消息。
   
这两个功能实现起来也很简单{如图}。只需要设计一个消息内容表和一个用户通知表,当创建一条系统通知后,数据插入到消息内容表。消息内容包含了发送渠道,根据发送渠道决定后续动作。如果是站内渠道,在插入消息内容后异步的插入记录到用户通知表。
    

消息推送中的已读消息和未读消息设计难题_第1张图片

  
这个方案看起来没什么问题,但实际上,我们把所有用户通知的消息全部放在一个表里面,如果有 10W 个用户,那么同样的消息需要存储 10W 条。
   
很明显,会带来两个问题:
1. 随着用户量的增加,发送一次消息需要插入到数据库中的数据量会越来越大,导致耗时会越来越长。
2. 用户通知表的数据量会非常大,对未读消息的查询效率会严重下降所以上面这种方案很明显行不通,要解决这两个问题,我有两个参考解决思路。
    
第一个方式(如图),先取消用户通知表, 避免在发送平台消息的时候插入大量重复数据问题。
其次增加一个“message_offset”站内消息进度表,每个用户维护一个消息消费的进度 Offset。
每个用户去获取未读消息的时候,只需要查询大于当前维护的 msg_id_offset 的数据即可。
在这种设计方式中,即便我们发送给 10W 人,也只需要在消息内容表里面插入一条记录即可。
在性能上和数据量上都有较大的提升。
   

消息推送中的已读消息和未读消息设计难题_第2张图片

       
第二种方式,和第一种方式类似,使用 Redis 中的 Set 集合来保存已经读取过的消息 id。使用 userid_read_message 作为 key,这样就可以为每个用户保存已经读取过的所有消息的 id。
当用户读取了未读消息后, 就直接在 redis 的已读消息 id 的 set 中新增一条记录。这样,在已经得知到已读消息的数量和具体消息 id 的情况下,我们可以直接使用消息 id 来查询没有消费过的数据。
   
一个小小的方案设计的优化,就能带来性能上的巨大提升,这就是为什么很多企业宁愿多花点钱也要招技术厉害的人的原因了吧。

你可能感兴趣的:(数据库)