默认
发表评论 25
想开发IM:买成品怕坑?租第3方怕贵?找开源自已撸?尽量别走弯路了... 找站长给点建议
完全自已开发的IM该如何设计“失败重试”机制?
阅读(187124) | 评论(25 收藏1 淘帖2 1
5金币
团队自己开发的IM软件,打算自己设计协议,现在在wifi和4G情况下,消息到达率都很理想,但是在电梯,地铁等等网络环境较差的情况下很容易发送失败。

在TCP连接的处理中已经定义了断线自动重连的机制,上层也定义了自动重发,但是这样容易造成消息重复(服务器不大可能把新来的消息id和过去所有消息id来对比判断重复吧?)。那么,如何设计好这个失败重试的机制,使得客户端能做好失败重试,服务器有能够排除这种重复消息,但是排重处理不太复杂?
标签:即时通讯
上一篇:为什么QQ用的是UDP协议而不是TCP协议?下一篇:socket出现少量close_wait后所有连接都不能发消息的问题

本帖已收录至以下技术专辑

推荐方案
评论 25
引用:PottermoreIron 发表于 2024-01-29 15:00
谢谢站长,我去看看

引用:JackJiang 发表于 2024-01-29 14:58
消息id客户端生成肯定吧,比如微信的方案:《IM消息ID技术专题(一):微信的海量IM聊天消息序列号生成实践 ...

谢谢站长,我去看看
引用:PottermoreIron 发表于 2024-01-29 14:55
站长,我还有个问题是,发送端的重发机制里,服务端怎么判断是否是重复消息呢?发送端发送消息的时候消息 ...

消息id客户端生成吧,比如微信的方案:《IM消息ID技术专题(一):微信的海量IM聊天消息序列号生成实践(算法原理篇)
引用:JackJiang 发表于 2024-01-29 14:50
对,所谓的ping包和pong包,就像打乒乓球一样

站长,我还有个问题是,发送端的重发机制里,服务端怎么判断是否是重复消息呢?发送端发送消息的时候消息id还没生成,直到服务器保存了消息后才有的消息id。这样假设服务器确实保存了A发过来的消息,但S->A的ACK包丢失,A重发,那么对于服务器来说这就是一条新消息,继续保存到db,但其实这是一条重复消息。这有什么办法解决呢?
引用:PottermoreIron 发表于 2024-01-29 14:45
这需要发送端和服务端分别都有重传机制吧,因为相当于是两个包来回

对,所谓的ping包和pong包,就像打乒乓球一样
引用:JackJiang 发表于 2022-09-19 23:35
在设计这种分布式系统时,尽量不要把逻辑复杂性扩散,经如重传机制你只让服务端管理,其它涉及到的路径只 ...

这需要发送端和服务端分别都有重传机制吧,因为相当于是两个包来回
引用:BrainWong 发表于 2022-09-19 23:59
了解,我是看到封宇大牛的IM设计,看上去每一层之间的消息传递都需要传ack,就比较好奇是发送消息的每一 ...

当然是其它组件只负责传达啦
引用:JackJiang 发表于 2022-09-19 23:35
在设计这种分布式系统时,尽量不要把逻辑复杂性扩散,经如重传机制你只让服务端管理,其它涉及到的路径只 ...

了解,我是看到封宇大牛的IM设计,看上去每一层之间的消息传递都需要传ack,就比较好奇是发送消息的每一层都需要配备重传,还是传递路径上的其他组件只是负责传达客户端与业务服务端发出的ack

签名: 难受,今年互联网还有机会吗
引用:BrainWong 发表于 2022-09-19 20:45
网关服务端(A) 到IM服务端, IM服务端转发到网关服务端(B),每个传递消息的连接都需要重传机制吧?

在设计这种分布式系统时,尽量不要把逻辑复杂性扩散,经如重传机制你只让服务端管理,其它涉及到的路径只负责传递,减化其它角色的复杂性,让逻辑尽可能集中,这样才能简化系统设计、并让系统架构职责变的清晰
引用:tishion 发表于 2016-05-03 21:58
**** 作者被禁止或删除 内容自动屏蔽 ****

1. 接入层服务端与业务处理服务器之间同样需要想客户端与接入层服务端之间的重传机制吧?
2. 像这种package id溢出了只能通过重连处理吗?3. 主要需要发送消息都需要维护一个ack queue,那么接入层、业务服务端、客户端都需要发送消息,每层都应该设计一个吗?
签名: 难受,今年互联网还有机会吗
引用:JackJiang 发表于 2018-11-20 18:08
肯定是im服务端了,否则要是重试了还送不到,那网关不得要实现具体的离线业务代码了,网关肯定不能放进这 ...

网关服务端(A) 到IM服务端, IM服务端转发到网关服务端(B),每个传递消息的连接都需要重传机制吧?
签名: 难受,今年互联网还有机会吗
引用:小张 发表于 2021-09-03 21:27
客户端多长时间超时重试合适?重试次数多少次好?

几秒吧,间隔太长,就失去时效性了,重试一到两次就差不多了
引用:JackJiang 发表于 2018-11-20 16:24
最简单的办法是让客户端自已来决定,即在一定的超时时间内,如果没有收到对方的应答包,就可以再次重传。 ...

客户端多长时间超时重试合适?重试次数多少次好?
引用:年糕 发表于 2018-11-20 17:32
感谢回复可能是我没表述清楚,是这样子。服务端下发消息,一条消息从im服务端 ,经过网关服务器,再 ...

肯定是im服务端了,否则要是重试了还送不到,那网关不得要实现具体的离线业务代码了,网关肯定不能放进这些具体的业务逻辑,否则重用性、独立性就差
引用:JackJiang 发表于 2018-11-20 16:24
最简单的办法是让客户端自已来决定,即在一定的超时时间内,如果没有收到对方的应答包,就可以再次重传。 ...

感谢回复可能是我没表述清楚,是这样子。服务端下发消息,一条消息从im服务端 ,经过网关服务器,再到客户端。客户端没接收到这条消息的时候是不知道有这条消息存在的就像我给你发消息,你没收到的时候是不知道我给你发了一条消息。所以这个时候就需要im服务或者网关这边没收到客户端的应达包去重试。这个重试做在im服务好还是做到网关服务去比较好。
引用:年糕 发表于 2018-11-20 16:18
大神请教下,im服务的消息经过网关再到客户端,客户端没收到消息时重试。请问这个重试加到网关去做还是im ...

最简单的办法是让客户端自已来决定,即在一定的超时时间内,如果没有收到对方的应答包,就可以再次重传。
这样的逻辑下,就不会把服务端的逻辑搞复杂。因为服务端只会越做越复杂,保持服务端逻辑的简洁性,服务端以后的升级和扩展就越来越好做。
引用:JackJiang 发表于 2016-05-03 22:09
不管传输层是TCP还是UDP协议,因为文本消息按现在主流IM的设计思路,都是ClineA-Sservr-ClinetB这种转发方 ...

大神请教下,im服务的消息经过网关再到客户端,客户端没收到消息时重试。请问这个重试加到网关去做还是im去做比较合适。
很棒,非常感谢,很清晰~
不管传输层是TCP还是UDP协议,因为文本消息按现在主流IM的设计思路,都是ClineA-Sservr-ClinetB这种转发方式实现,所以应答机制是必不可少的,相应的失败重试机制也就可以实现了(无论网络环境多复杂,只要守住最后一道关口:只有当收到应答包才认为对方已收到消息)。

但对于你所说的重传可能存在重复的情况,这是可能存在的,因为极端情况下应答包也是可能会丢失的,如果不做重传去重处理,那么重传势必导致消息重复。MobileIMSDK 是这么做的:因为UDP存在乱序的风险,所以不存在自增ID这种方法,不过可以把最近一段时间内(MobileIMSDK默认把最近5分钟内,不一定非得5分钟,只要保证这个时间大于正常的重传时间极值范围就可以了,长一点问题不大)收到的消息id给缓存了起来,这样就可以在收到重传包时进行去复判断了。不过,为了减轻服务器压力,不建议将这个缓存id保存到服务端(直接在接收端实现一个简单的队列不就行了吗),这样既可以简化server的设计、也可以防止服务性能瓶颈的发生(因为IM系统的瓶颈几乎只发生在服务端,所以server的设计一定要尽可能地简化,这样便于以后的性能扩展和优化)。
后台架设接入网关,接入网关负责每一个用户的接入session,在这一层做网络数据包的过滤,可以叫做接入层协议,协议内带有package id,如果这个package id对于这个用户已经是处理过,就直接丢弃,否则解包得到具体的业务协议,然后把业务协议发送到对应的业务处理服务器。

id采用整型,由客户端决定初始值,自增。
打赏楼主 ×
使用微信打赏! 使用支付宝打赏!

返回顶部