继续答球友提问: 群离线消息,是高效推还是拉? 关于写扩散、读扩散的不会丢问题,之前专门撰文写过,群离今天不直接同步结论,线消息何重点说说设计的高效思考过程。 画外音:结论不如思路重要。不会丢 假如群离线是群离推,流程应该如何?线消息何会遇到什么问题? 先看看群离线消息的核心数据结构。 群成员表: 画外音:用来描述一个群里有多少成员。 群离线消息表: 画外音:用来描述一个群成员的离线消息。 推,群离写扩散,线消息何存储群离线消息的高效过程如何? 画外音:如果要支持消息漫游,则可以省略步骤二。 此时,用户拉取离线消息的过程如何? 离线消息推,源码库存在什么问题? 对于同一份群消息的内容,多个离线用户要存储很多份。假设群中有200个用户离线,离线消息则冗余了200份,这极大的增加了数据库的存储压力。 如何优化,减少消息冗余量? 为了减少离线消息的冗余度,增加一个群消息表,用来存储所有群消息的内容,离线消息表只存储用户的群离线消息msg_id,就能大大的降低数据库的冗余存储量。 群消息表: 画外音:用来存储一个群中所有的消息内容。 群离线消息表,需要进行优化: 画外音:优化后只存储msg_id。 这样优化后,群消息的发送和存储要做一些升级: 相应的,拉取离线消息也要做对应的升级: 画外音:毕竟msg_detail只存储了一份,不能随便删。 上述过程,能保证离线消息的可达性么? 不能。 例如:server返回客户端离线消息之后,删除了离线消息,但客户端没有展现就奔溃了,离线消息就会丢失。 如何解决离线消息可达性呢? 很容易想到,通过ACK机制,server返回离线消息之后,不能立刻删除离线消息,而必须等客户端ACK,才能删除。 此时,离线消息拉取升级为: 画外音:增加了3和4两个步骤。 还有一个问题,一次有几十个群,每个群有几千条离线消息,共计几万条群离线消息,消息量过大怎么办? 当然不能一次性拉取,可以: 如果拉取了消息,却没来得及应用层ACK,会收到重复的消息么? 可以在客户端去重,源码下载对于重复的msg_id,对用户不展现,从而不影响用户体验。 如上所示,简单总结就是: 上面讲的都是“推”模式,群离线消息的设计,真正线上应用较多的,是“拉”模式。 推模式,存在什么问题? 对于离线的每一条消息,虽然只存储了msg_id,但是每个用户的每一条离线消息都将在数据库中保存一条记录,有没有办法减少离线消息的记录数呢? 对于一个群用户,在ta登出后的离线期间内,肯定是所有的群消息都没有收到的,完全不用对所有的每一条离线消息存储一个离线msg_id,而只需要存储最近一条拉取到的离线消息的time(或者msg_id),下次登录时拉取在那之后的所有群消息即可,而完全没有必要存储每个人未拉取到的全部离线消息msg_id。 拉模式,需要对数据结构进行怎样的升级? 群成员表,增加一个属性: 画外音:用来描述一个群里有多少成员,以及每个成员最后一条ack的群消息的msg_id(或者time)。 群消息表,不变: 画外音:还是用来存储一个群中所有的消息内容。 群离线消息表:不再需要。 使用拉模式后,群消息的发送和存储也要升级: 群离线消息的拉取流程也类似: 总结 群消息还是非常有意思的,做个简单总结: 画外音:还可按需拉取,登录不拉取,点进群再拉取。 【本文为专栏作者“58沈剑”原创稿件,转载请联系原作者】 戳这里,看该作者更多好文