每当发出一条微信消息 , 都希望对方尽快看到 , 并尽快回复 , 但始终不知道对方是否阅读 。
每当收到一条不能立马回复的微信消息 , 都默默返回 , 假装没看见 。
画外音:不想回复的人 , 唉 , 你只是个好人 。
微信用于个人社交 , 产品设计上 , 在线状态 , 强制已读回执都有可能暴露个人隐私 , 故微信并无相关功能 。
钉钉用于商务交流 , 其“强制已读回执”功能 , 让职场人无法再“假装不在线” , “假装没收到” 。
有甚者 , 钉钉的群有“强制已读回执”功能 , 你在群里发出的消息 , 能够知道谁读了消息 , 谁没有读消息 。
群消息的流程如何 , 接收方如何确保收到群消息 , 发送方如何收已读回执 , 究竟是拉取 , 还是推送 , 是今天要讨论的问题 。
一、群消息投递流程 , 以及可达性保证
大家一起跟着楼主的节奏 , 一步一步来看群消息怎么设计 。
p>
核心问题1:群消息 , 只存一份?还是 , 每个成员存一份?
答:存一份 , 为每个成员设置一个群消息队列 , 会有大量数据冗余 , 并不合适 。
核心问题2:如果群消息只存一份 , 怎么知道每个成员读了哪些消息?
答:可以利用群消息的偏序关系 , 记录每个成员的last_ack_msgid(last_ack_time) , 这条消息之前的消息已读 , 这条消息之后的消息未读 。该方案意味着 , 对于群内的每一个用户 , 只需要记录一个值即可 。
解答上述两个核心问题后 , 很容易得到群消息的核心数据结构 。
群消息表:记录群消息 。
group_msgs(msgid, gid, sender_uid, time, content);
各字段的含义为:消息ID , 群ID , 发送方UID , 发送时间 , 发送内容 。
群成员表:记录群里的成员 , 以及每个成员收到的最后一条群消息 。
group_users(gid, uid, last_ack_msgid);
各字段的含义为:群ID , 群成员UID , 群成员最后收到的一条群消息ID 。
在核心数据结构设计完之后 , 一起来看看群消息发送的流程 。
业务场景:
(1)一个群中有A, uid1, uid2, uid3四名成员
(2)A, uid1, uid2在线 , 期望实时收到在线消息
(3)uid3离线 , 期望未来拉取到离线消息

文章插图
其整个消息发送的流程1-4如上图:
(1)A发出群消息
(2)server收到消息后 , 一来要将群消息落地 , 二来要查询群里有哪些群成员 , 以便实施推送
(3)对于群成员 , 查询在线状态
(4)对于在线的群成员 , 实施推送
这个流程里 , 只要第二步消息落地完成 , 就能保证群消息不会丢失 。
核心问题3:如何保证接收方一定收到群消息?
答:各个收到消息后 , 要修改各群成员的last_ack_msgid , 以告诉系统 , 这一条消息确认收到了 。
在线消息 , 离线消息的last_ack_msgid的修改 , 又各有不同 。

文章插图
对于在线的群友 , 收到群消息后 , 第一时间会ack , 修改last_ack_msgid 。

文章插图
对于离线的群友 , 会在下一次登录时 , 拉取未读的所有群离线消息 , 并将last_ack_msgid修改为最新的一条消息 。
核心问题4:如果ack丢失 , 群友会不会拉取重复的群消息?
答:会 , 可以根据msgid在客户端本地做去重 , 即使系统层面收到了重复的消息 , 仍然可以保证良好的用户体验 。
上述流程 , 只能确保接收方收到消息 , 发送方仍然不知道哪些人在线阅读了消息 , 哪些人离线未阅读消息 , 并没有实现已读回执 , 那已读回执会对系统设计产生什么样的影响呢?
推荐阅读
- 盐酸麻黄碱
- 凤凰茶之白叶单枞,凤凰单枞茶适合人群喝
- 世上存在鬼吗 这个世上有鬼的存在吗
- 终于还是打开了这个可以学习JavaScript的教程
- 什么运动利于增高呢?
- 女孩|从完美皮肤到满脸爆痘,这个女孩的经历,让人想给她掌声
- 古树根与中国茶史千年,贵阳花溪久安乡发现五万多株千年古茶树居群,千年古茶树
- 什么是红颜知己
- 世界上最小的电脑主机 世界上容量最大的电脑
- 不可思议的神秘文化
