“站内信”有两个基本功能:
1、点到点的消息传送。用户给用户发送站内信 ,管理员给用户发送站内信。
2、点到面的消息传送。管理员给用户 (指定满足某一条件的用户群) 群发消息
这两个功能实现起来也很简单 {如图} 。
只需要设计一个消息内容表和一个用户通知表,当创建一条系统通知后,数据插入到消息内容表。消息内容包含了发送渠道,根据发送 渠道决定后续动作。
如果是站内渠道 ,在插入消息内容后异步的插入记录到用户通知表。
这个方案看起来没什么问题,但实际上,我们把所有用户通知的消息全部放在一个表里 面 ,如果有 10W 个用户 ,那么同样的消息需要存储 10W 条。
很明显 ,会带来两个问题:
1. 随着用户量的增加,发送一次消息需要插入到数据库中的数据量会越来越大,导致 耗时会越来越长
2. 用户通知表的数据量会非常大 ,对未读消息的查询效率会严重下降
所以上面这种方案很明显行不通 ,要解决这两个问题 ,我有两个参考解决思路。
第一个方式 (如图) ,先取消用户通知表, 避免在发送平台消息的时候插入大量重复 数据问题。
其次增加一个“ message_offset”站内消息进度表 ,每个用户维护一个消息消费的进 度 Offset。
每个用户去获取未读消息的时候,只需要查询大于当前维护的 msg_id_offset 的数据即 可。
在这种设计方式中 ,即便我们发送给 10W 人 ,也只需要在消息内容表里面插入一条记 录即可。
在性能上和数据量上都有较大的提升。
第二种方式,和第一种方式类似,使用 Redis 中的 Set 集合来保存已经读取过的消息 id。 使用 userid_read_message 作为 key ,这样就可以为每个用户保存已经读取过的所有 消息的 id。
当用户读取了未读消息后, 就直接在 redis 的已读消息 id的 set 中新增一条记录。 这样 ,在已经得知到已读消息的数量和具体消息 id 的情况下 ,我们可以直接使用消息 id 来查询没有消费过的数据。
你们看,一个小小的方案设计的优化,就能带来性能上的巨大提升,这就是为什么很多 企业宁愿多花点钱也要招技术厉害的人的原因了吧。