关于未读消息数功能实现的探讨

来源:9-21 接收方获得消息后重构渲染

LBruce

2021-03-30

个人觉得因为未读消息数是个具有高频访问修改特性的业务,所以可以修改成以下方式

单独维护总未读消息数和会话未读数
总未读消息数包含了会话消息未读数,但是还可能包含其它消息,比如系统通知等
因为总未读消息数在很多业务场景里会被高频使用,比如每次消息推送需要把总未读带上用于角标未读展示。

但是这样就会带一个新的问题
未读数的一致性

案例:
用户 A 给用户 B 发送消息,用户 B 的初始未读状态是:和用户 A 的会话未读是 0,总未读也是 0。
消息到达 IM 服务后,执行加未读操作:先把用户 B 和用户 A 的会话未读加 1,再把用户 B 的总未读加 1
假设加未读操作第一步成功了,第二步失败。最后 IM 服务把消息推送给用户 B。这个时候用户 B 的未读状态是:和用户 A 的会话未读是 1,总未读是 0。
这样,由于加未读第二步执行失败导致的后果是:用户 B 不知道收到了一条新消息的情况,从而可能漏掉查看这条消息。

出现这种问题的原因是因为

两个未读的变更不是原子性的,会出现某一个成功另一个失败的情况,也会出现由于并发更新导致操作被覆盖的情况。所以要解决这些问题,需要保证两个未读更新操作的原子性。

了解到的比较常见的解决方案是使用一个分布式锁来解决,每次修改前先加锁,都变更完后再解开。像是zookeeper,redis等。
但由mongodb来实现是不是也可以呢?因为MongoDB可以存储JSON字符串,那么更新消息未读数的时候,存储的json格式为{总未读消息数:0,和用户A的未读消息数:0},当变更未读消息的时候,把这个json格式的对象总未读数和用户A未读消息数同时-1,并更新回去。这样也实现了原子性更新操作。也不用引入什么分布式锁。

老师对此有何见解??谢谢老师

写回答

1回答

风间影月

2021-03-30

多端保持强一致性是不可能的。可能出现不一致的情况,就算出现也无所谓。弱一致性即可,就算丢失全部标记也不会影响全局业务。前端会用本地缓存去存储未读数进行标记。至于服务端用mongo没问题的。

1
1
LBruce
明白了,最终一致性即可。谢谢老师
2021-03-30
共1条回复

Netty+Spring Boot仿微信-全栈开发高性能后台及客户端

SpringBoot/Netty+MUI全栈开发 同时搞定后台+ Android&iOS

1498 学习 · 684 问题

查看课程