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


 
二、已读回执流程
对于发送方发送的任何一条群消息 , 都需要知道 , 这条消息有多少人已读多少人未读 , 就需要一个基础表来记录这个关系 。
 
消息回执表:用来记录消息的已读回执 。
msg_acks(sender_uid, msgid, recv_uid, gid,if_ack);
各字段的含义为:发送方UID , 消息ID , 回执方UID , 群ID , 回执标记 。
 
增加了已读回执逻辑后 , 群消息的流程会有细微的改变 。

这个diao 群消息已读回执,究竟是推还是拉?

文章插图
 
步骤二 , server收到消息后 , 除了要:
  • 将群消息落地
  • 查询群里有哪些群成员 , 以便实施推送
之外 , 还需要:
  • 插入每条消息的初始回执状态

这个diao 群消息已读回执,究竟是推还是拉?

文章插图
 
接收方修改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长时间的回执 , 归档或者删除掉
 
四、总结
对于群消息已读回执 , 一般来说: