起源:https://www.toutiao.com/i6686…
一敌人和我探讨他前段时间面试某大公司的一题目:
企业 IM 比方企业微信、钉钉外面的群音讯的有个已读未读的性能,发送者刚收回音讯时,以后群里其余群成员都是未读状态,陆陆续续有人看了这个音讯,这时候音讯的详情变成 x 人已读,y 人未读,如下图所示,有具体的已读未读列表(万恶的性能,看到共事 or 老板的音讯不能伪装没看到了),每条音讯对应一个惟一的 messageid(uint64_t),每个用户对应一个惟一的 userid(uint64_t), 应该如何保留这个音讯对应的已读未读详情呢?
我第一工夫给出一个很简略粗犷的计划:
对于每一个 messageid,存以后 readids + unreadids,当群成员 A 已读某一条音讯时,把 A userid 从 unreadids 移除写到 readids 上就好了,客户端更新到 messageid 对应的详情列表,就能够展现 m 人已读,n 人未读
显然这么简略粗犷的计划面试官是不会称心的,诘问有没有更好的计划呢?
仔细分析,依照目前的设计,每一条音讯,已读未读详情就要占用 8B * 群成员数的内存,如果一个沉闷的 200 人大群,每发一条音讯,已读未读就要 1600B,如果均匀每天音讯量是 1k,那每个这样的群,每天就要 1.6MB 磁盘空间,对于客户端来说,特地是手机端,占用磁盘空间是用户不能承受的,又不能把工作音讯删了,对于服务器端来说,用户群体如果特地大,那数据库存储这个老本也不小
其实未读已读就是一个 0 / 1 的标记而已,能够保护一个 bitmap 来实现呢?具体应该怎么做呢?
群元信息保留 userid 到自增 mapid 的映射
struct UserInfo
{
uint64_t userid;
uint32_t mapid;
};
struct GroupMetaInfo
{
vector <UserInfo> members;
string name;
uint32_t maxid;
// other info
};
这样群成员每退出一个群里,就有 mapid<->usreid 的双向映射了,如果群里有 5 个成员 ABCDE, 那就对应 mapid 1-5,messageid 对应的音讯详情存储就能够设计成
{uint32_t maxid, uint8_t readbit[]}
如下面的案例就是 {5, readbit[0] =bin(0000 0000)}; 就占用了 5B(4+1),A 发消息,D 已读音讯时,就更新成 {5,readbit[0]= bin(0000 1000)}, 其余 4 人都已读音讯时 更新为 {5, readbit[0]=bin(0001 1110)}
这是个粗略的计划,外面还有一些细节值得思考:
- 退出的成员呢?比方 C 退出群,发消息时 maxid 还是 5,已读 + 未读总人数应该是 3(不包含发消息者自己),目前信息只有 5 个 bit(0/1),辨认不进去谁曾经退出群聊了
- 退出群聊的成员如何解决?从 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 存储老本远超过最后的计划,能够用最后的计划来实现,客户端提前埋好兼容逻辑就能够了
近期热文举荐:
1.1,000+ 道 Java 面试题及答案整顿 (2022 最新版)
2. 劲爆!Java 协程要来了。。。
3.Spring Boot 2.x 教程,太全了!
4.Spring Boot 2.6 正式公布,一大波新个性。。
5.《Java 开发手册(嵩山版)》最新公布,速速下载!
感觉不错,别忘了顺手点赞 + 转发哦!