离线消息的处理机制

不管是消息队列的消息投递,还是单人实时聊天的消息投递,都需要通过应用层的超时,重传,确认,去重来保证消息的可靠投递。离线消息的处理,根据实际业务需求来做处理。一般来说,要保证用户的离线消息不丢失,用户上线后能够获取离线消息。

用户A给B发送一条消息,B不在线,离线消息存储的流程如下:

1.A发送消息给B,通过服务器server中转;

2.server查看B的状态为offline离线;(服务端会缓存用户的状态)

3.server将消息存储到数据库DB;

4.server返回用户A,消息发送成功;(对于发送方而言,消息存到DB,就认为发送成功)

用户B上线了,他要拉取A给他发送的离线消息,整体流程如下:

1.B向server拉取A给B发送的离线消息;  (通过uid_B,uid_A在离线消息表查询)

2.server从DB中获取离线消息;

3.server从DB中删除离线消息;

4.server将B所需要的离线消息返回给B.

这是最原始的场景。

 

实际上用户登录后,可能要拉取所有好友的离线信息,显然他不能一个一个的去拉取,原因是要减少拉取次数,一个合理的方式是按需拉取,即先拉取各个好友的离线消息数量,真正查看离线消息时,才往服务器发送拉取请求。

进一步优化拉取次数:一次拉取B的所有好友的离线消息,通过uid_B查询离线消息表,然后在客户端本地,根据sender_uid进行计算,区分是哪个具体的好友消息。

整体流程如下:

1.B向server拉取所有给B发送的离线消息;  (通过receiver_uid=uid_B在离线消息表查询)

2.server从DB中获取离线消息;

3.server从DB中删除离线消息;

4.server将B所需要的离线消息返回给B.

 

问题:一次请求返回所有数据,返回的报文数据可能过大,速度会很慢

方案:分页拉取,根据业务需求,先拉取最新的一页消息,在按需一页页拉取。

整体流程如下:

1.B向server拉取所有给B发送的离线消息;  

2.server从DB中按页获取离线消息;

3.server从DB中按页删除离线消息;

4.server将B所需要的离线消息按页返回给B.

问题1:如果先删除离线消息,再返回数据,在返回数据的过程中服务器挂了,路由器丢失消息,或者客户端挂了,怎么弄?

显然需要用ACK机制,离线消息拉取时不能直接删除数据库中的离线消息,而必须等应用层的离线消息ACK,等客户端真的收到离线消息,才能删除数据库中的离线消息。

问题2:如果用户B拉取了一页消息,却在ACK之前挂了,下次登录时会拉到重复的离线消息吗?

在系统层面,拉取了消息但是没有ACK,服务器不会删除之前的离线消息,故下次登录还会拉取到。但是在业务层面,可以根据msg_id去重,让用户无感知。

问题3:假如有n页离线消息,如果每页消息都需要一个ACK,那么客户端与服务器的交互次数有加倍了,如何优化?

其实,不用每一页都单独ACK一次,在拉取第二页消息时相当于第一页消息的ACK,此时服务器再删除第一页消息即可,最后一页消息在ACK一次,整个过程仅仅是在最后一页拉取成功之后加了个ACK,中间是用后面的拉取请求同时做为上一次的ACK。这样的效果是,不管拉取多少页数据,只会多一个ACK请求,与服务器多一次交互。

总结:

“离线消息”的玩法,场景的优化,有:

  • 对于同一个用户B,一次性拉取所有的用户给他发送的离线信息,然后在客户端本地进行发送方分析,相比按照发送方一个个进行消息拉取,能大大减少与服务器的交互次数;
  • 按需拉取;
  • 分页拉取,是一个请求次数与包大小的折中方案;
  • 应用层的ACK,应用层去重,才能保证消息不丢不重复;
  • 下一页拉取同时作为上一页的ACK,减少与服务器的交互次数。

 

 

 

 

 

  • 7
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值