企业IM比如企业微信、钉钉里面的群消息的有个已读未读的功能,发送者刚发出消息时,当前群里其他群成员都是未读状态,陆陆续续有人看了这个消息,这时候消息的详情变成x人已读,y人未读,该如何设计呢?
每一条消息,已读未读详情其实就是一个0/1的标记而已,我们可以选择维护一个bitmap来实现。
每个群的信息保存userid到自增mapid的**映射**,这样群成员每加入一个群里,就有mapid<->usreid的双向映射了。
假如群里有5个成员ABCDE, 那就对应mapid 1-5,messageid对应的消息详情存储就可以设计成{ uint32_t maxid, uint8_t readbit[]}。如上面的案例就是{5, readbit[0] =bin(0000 0000)}; 就占用了5B(4+1)(4byte+8bit),A发消息,D已读消息时,就更新成{5,readbit[0]= bin(0000 1000)};其余4人都已读消息时,更新为{5, readbit[0]=bin(0001 1110)}。这是个粗略的方案,里面还有一些细节值得思考:
1、退出的成员呢?比如C退出群,发消息时maxid还是5,已读+未读总人数应该是3(不包括发消息者本人),目前信息只有5个bit(0/1),识别不出来谁已经退出群聊了。
2、退出群聊的成员如何处理?从GruopMetaInfo里面删除么?退出群聊成员重新加入又如何分配id呢?
2这个点,退出群聊的成员只能**逻辑删除**,不能物理删除,不然客户端展示已读未读详情时,通过mapid找不到对应的userid,退出的成员又重新加入群聊这个就好办了,把标记删除改成非标记删除,还是用旧的mapid。
至于1呢?我目前想到比较好的方式就是再加多一个bitmap,记录成员在消息发送时是否已经退出群聊了,退出群聊就置为1,所以最终方案就是群信息增加userid,自增mapid双向映射,退出群聊成员标记删除,messageid已读未读详情存储 {maxid, readbit[], quitbit[]}新的方案带来怎样的收益呢?增加自增mapid字段,一个群聊维护一份,成本几乎可以忽略不计。
每个成员已读未读由8B(64bit)优化成2bit,减少62/64, 200人已读未读旧的方案1600B, 现在只需要(200/8) * 2 + 4 = 54,每条消息节约95%+ 如果maxid如果到百万甚至千万级别,那岂不是灾难?一般实际场景,群聊是会限制人数的,就算不断踢人加新人,那maxid最多也只能到企业人数。
如果maxid达到一个特别大数字,已读未读对应的存储可以增加多一个flag,如果bitmap存储成本远超过最初的方案,可以用最初的方案来实现,客户端提前埋好兼容逻辑就可以了。
关于消息未读和已读的学习
最新推荐文章于 2023-03-13 10:42:37 发布
本文探讨了企业IM如企业微信、钉钉中群消息已读未读功能的设计方案。提出使用bitmap存储每个成员的已读未读状态,并通过增加额外的bitmap来标记成员是否已退出群聊。当成员退出后再加入时,保留原有的mapid。通过这种方式,可以有效地管理和优化存储空间,例如将每个成员的已读未读状态从8B压缩到2bit。同时,讨论了当maxid增长到大规模时的解决方案,即根据实际情况选择不同的存储策略。
摘要由CSDN通过智能技术生成