• 可靠的推送IM消息


    一、      报文类型:

    1、请求报文(request,后简称为为R);

    2、应答报文(acknowledge,后简称为A);

    3、通知报文(notify,后简称为N)。

    R:客户端主动发送给服务器的报文;

    A:服务器被动应答客户端的报文,一个A一定对应一个R;

    N:服务器主动发送给客户端的报文;

    二、      在线消息的可靠性:

    消息投递流程:

     

    1、client-A向im-server发送一个消息请求包,即msg:R;

    2、im-server在成功处理后,回复client-A一个消息响应包,即msg:A;

    3、如果此时client-B在线,则im-server主动向client-B发送一个消息通知包,即msg:N(当然,如果client-B不在线,则消息会存储离线);

    如果出现网络抖动,服务器崩溃或者Client-B崩溃,都会导致msg:N消息丢失,而Client-A以为client-B已经收到消息;

    消息的可靠性投递:

    要想实现应用层的消息可靠投递,必须加入应用层的确认机制,即:要想让发送方client-A确保接收方client-B收到了消息,必须让接收方client-B给一个消息的确认:

    1、client-B向im-server发送一个ack请求包,即ack:R;

    2、im-server在成功处理后,回复client-B一个ack响应包,即ack:A;

    3、则im-server主动向client-A发送一个ack通知包,即ack:N;

    一个应用层即时通讯消息的可靠投递,共涉及6个报文:即msg的R/A/N三个报文,ack的R/A/N三个报文。

    client-A发出了msg:R,收到了msg:A之后,在一个期待的时间内,如果没有收到ack:N,client-A会尝试将msg:R重发。可能client-A同时发出了很多消息,故client-A需要在本地维护一个等待ack队列,并配合timer超时机制,来记录哪些消息没有收到ack:N,以定时重发。

     

    一旦收到了ack:N,说明client-B收到了“你好”消息,对应的消息将从“等待ack队列”中移除。

    消息的去重:

    如果client-A不能收到报文ack:N,即client-A不能确认client-B成功收到了消息,此时会触发消息的超时和重发,如果之前client-B收到消息,而ack:N没收到导致消息重发,那么client-B有可能会重复收到消息;

    解决方法是client-A为每条消息生成一个唯一的msgid(可以采用UUID),这样即时client-B收到了重复的消息,通过msgid的判断,也不会影响用户的体验;

    三、      离线消息的可靠性:

    离线消息的发送流程:

     

     1、Step 1:用户A发送一条消息给用户B;

    2、Step 2:服务器查看用户B的状态,发现B的状态为“offline”(即B当前不在线);

    3、Step 3:服务器将此条消息以离线消息的形式持久化存储到DB中(当然,具体的持久化方案可由您IM的具体技术实现为准);

    4、Step 4:服务器返回用户A“发送成功”ACK确认包(注:对于消息发送方而言,消息一旦落地存储至DB就认为是发送成功了)。

    离线消息的拉取流程:

      

    一次性拉取所有好友发送给用户B的离线消息,到客户端本地再根据sender_uid进行计算;

    用户B一次性拉取所有好友发给ta的离线消息,消息量很大时,一个请求包很大、速度慢,容易卡顿;我们可以分页拉取:根据业务需求,先拉取最新(或者最旧)的一页消息,再按需一页页拉取,这样便能很好地解决用户体验问题。

    消息的可靠性:

    上面的流程中,如果在第三步从离线表中删除了离线消息,在执行第四步时,如果出现网路抖动、服务器宕机,B客户端宕机,那么就会造成离线消息丢失。那如何保证离线消息的绝对可靠性、可达性?

     

    如同在线消息的应用层ACK机制一样,离线消息拉时,不能够直接删除数据库中的离线消息,而必须等应用层的离线消息ACK(说明用户B真的收到离线消息了),才能删除数据库中的离线消息。

    消息的去重:

           如果用户B收到了离线消息,但是ACK消息丢掉了,下次登录时消息还是会再次推送的,那么就会造成消息重复接收;

           解决办法与前面的在线消息一样,可以为每条消息生成一个唯一的消息ID(msgid),然后在应用层通过对msgid判断去重,从而对用户体验无影响;

  • 相关阅读:
    PO-审批设置
    DIS-接收方式设置入口
    网约车
    汽车租赁
    共享单车
    共享充电宝
    佛教四大名山|道教四大名山|五岳|名山
    我读过的诗词文章书籍
    我看过的电影
    redis异常解决:jedis.exceptions.JedisDataException: ERR Client sent AUTH, but no password is set
  • 原文地址:https://www.cnblogs.com/laoxia/p/7743396.html
Copyright © 2020-2023  润新知