对于(社交软件类)群消息,一般分为写扩散和读扩散
1 写扩散
当群里有一个人发送消息的时候,服务端收到消息后,先在群的消息表记录一条数据,在查出群里的人,向每个人的消息表插入一条未读的数据,如果用户在线,则把这条消息推送给用户,并且在更新个人的消息表,把这个消息置为已读。当用户上线时候,直接拉去自己的消息表,把未读的消息按照全量给或者分页给的方式响应给用户,并且把消息置为已读。
这种情况,用户发送的消息,需要保存两份,特别是大文本消息,msg_deatail在群消息表和个人消息表都存了一分,对于个人消息表设计还要考虑群消息,不过一个储存消息这种,不会采用关系型数据库,可以考虑用非关系的数据库,尽量冗余多一点字段,减少表与表的关联关系,最好是没有,只做单表查询。
2 读扩散
当群里有一个人发送消息的时候,服务端收到消息后,先在群的消息表记录一条数据,在查出群里的人,遍历每个人,判断是否在线,如果在线,就把该消息推送给用户,并且更新用户对于群消息的已读下标位,当用户不在线,就什么也不做,用户从下线变成上线,拉去群消息时,现需要查自己的群消息下标位,然后再遍历自己加入的群,获取是否有最新的群消息,如果有,则取出来,最后响应给用户
这种情况,用户发送的消息,只是在群消息表保存了一份,针对于在线的用户才做了群消息下标位的更新,相当于每个人每个群在这个表里面只会存在一条记录,后面的群消息,只是更新下标位,相比于写扩散,多了查询时候的复杂度,写扩散,用户拉去离线的群消息,只需要查自己的个人消息表,而读扩散,则需要查两个表,群消息下标位表,群消息表,也只能是遍历去查询群消息表,(这块可以考虑用线程池去做,各个群消息查询相互独立,不影响)。
对于(直播类)房间消息,用读扩散最好
这种情况下,类似于用户的临时会话,一个用户只能在一个房间里,用户的状态,要么在房间里,要么离开了房间,当房间有新的消息时,可以去redis中查房间下有多少用户,向每个用户推送消息,并且异步向数据库写入一条房间消息做备案,用户收到消息时,也查询自己的数据,做去重操作,如果不是重复的消息,就加入消息表,并向UI展示这条消息,重复的消息,什么也不做,用户向上拉去的时候,不用再请求服务器,直接查询自己的消息表,如果离开房间,可以考虑本地清除这个房间的消息