每当发出一条微信消息,都希望对方尽快看到,并尽快回复,但始终不知道对方是否阅读。

每当收到一条不能立马回复的微信消息,都默默返回,假装没看见。

画外音:不想回复的人,唉,你只是个好人。

微信用于个人社交,产品设计上,在线状态,强制已读回执都有可能暴露个人隐私,故微信并无相关功能。

钉钉用于商务交流,其“强制已读回执”功能,让职场人无法再“假装不在线”,“假装没收到”。

有甚者,钉钉的群有“强制已读回执”功能,你在群里发出的消息,能够知道谁读了消息,谁没有读消息。

群消息的流程如何,接收方如何确保收到群消息,发送方如何收已读回执,究竟是拉取,还是推送,是今天要讨论的问题。

一、群消息投递流程,以及可达性保证

大家一起跟着楼主的节奏,一步一步来看群消息怎么设计。

核心问题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在客户端本地做去重,即使系统层面收到了重复的消息,仍然可以保证良好的用户体验。

上述流程,只能确保接收方收到消息,发送方仍然不知道哪些人在线阅读了消息,哪些人离线未阅读消息,并没有实现已读回执,那已读回执会对系统设计产生什么样的影响呢?

二、已读回执流程

对于发送方发送的任何一条群消息,都需要知道,这条消息有多少人已读多少人未读,就需要一个基础表来记录这个关系。

消息回执表:用来记录消息的已读回执。

msg_acks(sender_uid, msgid, recv_uid, gid,if_ack);

各字段的含义为:发送方UID,消息ID,回执方UID,群ID,回执标记。

增加了已读回执逻辑后,群消息的流程会有细微的改变。

步骤二,server收到消息后,除了要:

  • 将群消息落地

  • 查询群里有哪些群成员,以便实施推送

之外,还需要:

  • 插入每条消息的初始回执状态

接收方修改last_ack_msgid的流程,会变为:

(1)发送ack请求

(2)修改last_ack_msgid,并且,修改已读回执if_ack状态

(3)查询发送方在线状态

(4)向发送方实时推送已读回执(如果发送方在线)

如果发送方不在线,ta会在下次登录的时候:

(5)从关联表里拉取每条消息的已读回执

这里的初步结论是:

  • 如果发送方在线,会实时被推送已读回执

  • 如果发送方不在线,会在下次在线时拉取已读回执

三、流程优化方案

再次详细的分析下,群消息已读回执的“消息风暴扩散系数”,假设每个群有200个用户,其中20%的用户在线,即40各用户在线。群用户每发送一条群消息,会有:

  • 40个消息,通知给群友

  • 40个ack修改last_ack_msgid,发给服务端

  • 40个已读回执,通知给发送方

可见,其消息风暴扩散系数非常之大。

同时:

  • 需要存储40条ack记录

群数量,群友数量,群消息数量越来越多之后,存储也会成为问题。

是否有优化方案呢?

群消息的推送,能否改为接收方轮询拉取?

:不能,消息接收,实时性是核心指标。

对于last_ack_msgid的修改,真的需要每个群消息都进行ack么?

:其实不需要,可以批量ack,累计收到N条群消息(例如10条),再向服务器发送一次last_ack_msgid的修改请求,同时修改这个请求之前所有请求的已读回执,这样就能将40个发送给服务端的ack请求量,降为原来的1/10。

会带来什么副作用?

:last_ack_msgid的作用是,记录接收方最近新取的一条群消息,如果不实时更新,可能导致,异常退出时,有一些群消息没来得及更新last_ack_msgid,使得下次登陆时,拉取到重复的群消息。但这不是问题,客户端可以根据msgid去重,用户体验不会受影响。

发送方在线时,对于已读回执的发送,真的需要实时推送么?

:其实不需要,发送方每发一条消息,会收到40个已读回执,采用轮询拉取(例如1分钟一次,一个小时也就60个请求),可以大大降低请求量。

画外音:或者直接放到应用层keepalive请求里,做到0额外请求增加。

会带来什么副作用?

:已读回执更新不实时,最坏的情况下,1分钟才更新回执。当然,可以根据性能与产品体验来折衷配置这个轮询时间。

如何降低数据量?

答:回执数据不是核心数据

  • 已读的消息,可以进行物理删除,而不是标记删除

  • 超过N长时间的回执,归档或者删除掉

四、总结

对于群消息已读回执,一般来说:

  • 如果发送方在线,会实时被推送已读回执

  • 如果发送方不在线,会在下次在线时拉取已读回执

如果要对进行优化,可以:

  • 接收方累计收到N条群消息再批量ack

  • 发送方轮询拉取已读回执

  • 物理删除已读回执数据,定时删除或归档非核心历史数据

推送还是拉取?

任何脱离业务的架构设计都是耍流氓。

挖坑篇:《feed流,单聊群聊,系统通知,状态同步,到底是推还是拉?》

填坑篇1:《系统通知,究竟是推还是拉?》

填坑篇2:《状态同步,究竟是推还是拉?》

填坑篇3:《网页端消息,究竟是推还是拉?》

码字不易,求帮转。

群消息已读回执(这个diao),究竟是推还是拉?相关推荐

  1. 群消息已读回执(这个屌),究竟是推还是拉?

    每当发出一条微信消息,都希望对方尽快看到,并尽快回复,但始终不知道对方是否阅读. 每当收到一条不能立马回复的微信消息,都默默返回,假装没看见. 画外音:不想回复的人,唉,你只是个好人. 微信用于个人社 ...

  2. 群消息已读回执,究竟是推还是拉?

    每当发出一条微信消息,都希望对方尽快看到,并尽快回复,但始终不知道对方是否阅读. 每当收到一条不能立马回复的微信消息,都默默返回,假装没看见. 画外音:不想回复的人,唉,你只是个好人. 微信用于个人社 ...

  3. im即时通讯开发:IM群聊消息的已读回执功能

    我们平时在使用即时通讯应用时候,每当发出一条聊天消息,都希望对方尽快看到,并尽快回复,但对方到底有没有真的看到?我却并不知道. 一个残酷的现实是,很多时候对方其实是早就已经看到了这条消息,但出出种种原 ...

  4. IM消息重试机制Java实现_IM群聊消息的已读回执功能该怎么实现?

    本文引用了架构师之路公众号作者沈剑的文章,内容有改动,感谢原作者. 1.前言我们平时在使用即时通讯应用时候,每当发出一条聊天消息,都希望对方尽快看到,并尽快回复,但对方到底有没有真的看到?我却并不知道 ...

  5. IM即时通讯开发群聊消息的已读回执功能该怎么实现?

    我们平时在使用即时通讯应用时候,每当发出一条聊天消息,都希望对方尽快看到,并尽快回复,但对方到底有没有真的看到?我却并不知道.一个残酷的现实是,很多时候对方其实是早就已经看到了这条消息,但出出种种原因 ...

  6. 技术QA:在 Outlook 2000 里为何不能取消“对已读回执的请求的使用”?

    引子: 目前还有很多企业还在使用比较旧版本的Office以及Windows,因为早期版本的设计问题可能会引出一些使用上的限制.另外,Windows 2000和Outlook 2000的相关产品已过微软 ...

  7. OUTLOOK 邮箱发件人请求已读回执

    OUTLOOK 邮箱发件人请求已读回执 在发件页面如图所示选择"显示邮件选项" 发送邮件后,收件人点开邮件,若收件人设置"收到已读回执请求时总是发送已读回执", ...

  8. imap 已读回执_停止烦恼已读回执

    imap 已读回执 Let's be real. As soon as you send a text message, your recipient has probably read it. So ...

  9. imap 已读回执_确保同事看到已读回执和延迟提醒电子邮件的“重要电子邮件”...

    imap 已读回执 A lot of people ask how to schedule an email for a certain date and for good reason.  As w ...

  10. [No0000141]Outlook,设置全局已读回执

    Outlook,设置全局已读回执 文件->选项 转载于:https://www.cnblogs.com/Chary/p/No0000141.html

最新文章

  1. Leetcode 217. 存在重复元素 (每日一题 20210913)
  2. stm32系统滴答定时器使用
  3. Linux内核出错的栈打印详解,linux内核中打印栈回溯信息 - dump_stack()函数分析
  4. Enterprise Library 4.1 快速上手(图)
  5. 计算机维修队,浙江万里学院计算机维修队
  6. Nacos SDK for Scala 发布
  7. RDS 设置 group_concat的长度限制 1024 改为 102400
  8. 将connection存放在Threadlocal里和数据库连接池的区别
  9. Windows 10 JDK安装及环境配置(vim+gcc)
  10. stm32的HAL库uart的注意点
  11. BAT54C 二极管是如何工作的?
  12. C语言 饭卡管理系统
  13. 【中间件技术】第二部分 CORBA规范与中间件(3) 基于CORBA的开发过程
  14. IDEA中的SourceRoot含义及设置方法
  15. 观测云产品更新|新增阿里云账户结算方式;新增 DQL 查询查看器;新增基础设施网络模块等
  16. php的rps,如何理解RPS的本质
  17. SQL数据库移植到ARM板步骤
  18. 向量空间模型算法(Vector Space Model)
  19. 楚留香哪个服务器最新,楚留香官服和混合服哪个好 哪个服务器的人多
  20. Spring Cloud (Eureka,Feign,Hystrix整合)

热门文章

  1. Axure如何建立共享项目、如何编辑共享项目、如何获取共享项目
  2. 阿里飞天云平台架构简介
  3. Windows命令之tracert命令
  4. 原来没有网络也能扫码支付,都是因为它啊!
  5. 基于双向流固耦合的Fluent dynamic mesh 学习笔记
  6. Python抽象基类、鸭子类型介绍
  7. 支付宝支付接口开通流程
  8. 柳传志:我是任正非的知音
  9. linux查看服务器时间,Linux 查看当前时间
  10. ArcGIS:计算土地转移矩阵