实时通讯系统的消息推送的失败重试

实时通讯系统中消息推送失败重试的那些事儿

你有没有遇到过这种情况:给朋友发了条消息,消息旁边一直转圈圈,显示"发送中",好一会儿才成功发送出去?或者在某个重要的群里发了一条通知,结果发现有几部分人根本没收到?说实话,我在刚开始接触实时通讯这块内容的时候,也觉得这些小问题没什么大不了的——不就是网络不好嘛,多发几次不就行了?

但后来深入了解才发现,消息推送失败这事儿远没有表面上看起来那么简单。它背后涉及到的技术细节、多样的失败场景、以及如何设计一套既可靠又高效的重试机制,其实是一门不小的学问。尤其是对于我们这种做实时音视频和通讯云服务的团队来说,消息能不能准确送达,直接关系到用户体验和产品口碑。

今天我就结合自己这些年的一些实践经验,跟大家聊聊实时通讯系统中消息推送失败重试这个话题。咱不搞那些晦涩难懂的专业术语,就用大白话把这里面的门道给说清楚。

消息推送为什么会失败?

在聊重试机制之前,咱们首先得搞清楚消息为什么会推送失败。只有知道了"病因",才能对症下药。

简单来说,消息推送失败的原因可以分成几大类。

第一类是我觉得最常见的,也就是网络层面的问题。你想想,用户可能在地铁里信号不好,可能在 WiFi 和 4G 之间切换,可能跨了运营商的网络,也可能刚好处于网络拥堵的时段。这种情况下,消息发送出去之后,服务器根本没收到响应,或者响应在路上就丢了。客户端这边一看超时了,自然就认为推送失败了。

第二类是服务端的问题。比如服务器在高并发情况下过载了,处理不过来了;或者某个服务节点临时出了故障,正在重启;还有可能消息队列堵了,后面的消息都积压着没处理完。这些服务端的问题也会导致消息推送失败,而且这种失败往往不是用户那边能解决的。

第三类可能很多人没想到,是客户端状态异常。比如用户刚好把 APP 切到后台,iOS 或者 Android 系统为了省电,直接把网络连接给断了;或者用户登录态过期了,服务器识别不了这个请求是谁发的;再比如用户设备存储空间满了,连建立新连接都困难。这种情况下,消息虽然从客户端发出去了,但根本到不了服务器。

第四类是消息内容本身的问题。虽然这种情况相对少见,但也确实存在。比如消息体太大了,超过了服务器设置的限流阈值;或者消息格式不符合协议规范,解析的时候出错了;再或者包含了某些敏感内容,被风控系统给拦截了。

了解了这些失败原因之后,你会发现,简单的"重试一下"其实解决不了所有问题。不同的失败原因,需要不同的应对策略。这也就是为什么现在稍微成熟一点的实时通讯系统,都会设计一套相对完善的重试机制。

重试机制的核心设计原则

说到重试机制的设计,这里面的学问可就大了。我见过不少团队在设计重试策略的时候,要么太保守,重试几次就不管了,可靠性不够;要么太激进,拼命重试,结果把服务器给打挂了,或者把用户流量给耗干了。那么一个好的重试机制应该遵循哪些原则呢?

第一个原则是区分可重试和不可重试的错误。

这句话什么意思呢?就是说不是所有的失败都应该重试。比如,如果服务器明确返回说"用户不存在"或者"消息内容违法",这种错误你重试一万次也是白搭,还浪费资源。但如果是超时、连接断开这种临时性问题,那确实值得重试试试。所以一般来说,我们会根据错误码或者错误类型来做判断,把错误分成"可重试"和"不可重试"两类。

第二个原则是采用指数退避策略。

啥叫指数退避?简单说就是第一次失败后等 1 秒重试,第二次失败后等 2 秒,第三次等 4 秒,以此类推。为什么这么做呢?你想啊,如果系统正处于高压状态,你还在那儿疯狂重试,岂不是雪上加霜?让重试间隔随着失败次数指数级增长,给服务器留出恢复的时间,也给自己留出观察情况的余地。当然,也不能让间隔无限制增长下去,一般会设置一个上限,比如最多等 60 秒或者 120 秒。

第三个原则是设置最大重试次数。

这个很好理解,不能无限重试下去。到底设置几次比较合适?我个人的经验是,对于实时通讯场景,普通消息重试个 3 到 5 次差不多就够了。如果是特别重要的消息,比如付款通知、验证码之类的,可以适当多几次,但也要考虑用户等待的耐心限度。

第四个原则是做好幂等设计。

什么叫幂等?就是说同一操作执行多次,结果是一样的。比如你给服务器发了一条"重试发送消息 A"的请求,服务器应该能识别出这是一条重试请求,而不是又创建一条新消息。如果没有做好幂等,同一条消息可能被发送出去好几遍,用户就得重复收消息了,这体验可就太差了。

实际场景中的重试策略

光说理论可能有点抽象,我给大家举几个实际场景的例子,看看不同情况下重试策略应该怎么设计。

场景一:弱网环境下的消息推送

这应该是最常见的场景了。用户可能在电梯里,可能在信号覆盖不好的地下室,也可能正在从 WiFi 切换到蜂窝网络。这种情况下,连接是断断续续的,第一次推送失败的可能性很高。

对于这种场景,我建议采用相对激进一点的重试策略。比如初始重试间隔可以设置短一点,500 毫秒就开始第一次重试,因为网络抖动通常恢复得比较快。同时把最大重试次数稍微提高一点,比如 5 次或者 6 次,给网络恢复留出足够的时间窗口。另外,在检测到网络状态改善的时候,可以主动触发重试,而不只是被动等待定时器。

场景二:服务端过载时的消息推送

这种情况虽然不常见,但一旦遇到就比较棘手。比如系统突然遭遇流量高峰,或者某个后端服务出现故障,导致消息处理能力下降。这时候客户端疯狂重试其实没意义,反而会加重服务器负担。

比较好的做法是服务端在过载时返回特定的错误码或者响应头,告诉客户端"我现在处理不过来,你等会儿再试"。客户端看到这个信号之后,就可以停止当前的重试计数,进入一个较长的等待期,比如 30 秒甚至更长,之后再按正常的重试逻辑来。另外也可以引入随机抖动,避免所有客户端在同一时间点集中重试。

场景三:用户登录态过期时的消息推送

这种情况稍微复杂一点。用户登录态过期了,服务器会返回"认证失败"的错误。如果你这时候重试消息发送,肯定还是失败,因为凭证不对。

正确的做法是,客户端检测到认证失败后,应该先尝试刷新登录态,或者引导用户重新登录。登录态恢复之后,再重新发送之前失败的消息。这已经超出了单纯"重试"的范畴,属于错误恢复流程了,但在实际系统中这一步非常重要。

声网在这方面的实践

说了这么多理论,我想结合一下我们声网的实际经验来聊聊。我们作为全球领先的实时音视频云服务商,在这个领域深耕了这么多年,在消息推送的可靠性方面也积累了不少心得。

先说个大概的数字吧。我们现在服务着全球超过 60% 的泛娱乐 APP,每天的消息推送量是个天文数字。在这么大的体量下,消息推送的可靠性是我们非常重视的一个指标。我们的目标是让消息推送的失败率控制在极低的水平,同时不让用户感知到任何重试的延迟。

在技术实现上,我们的消息推送系统采用了多级别的重试策略。对于实时性要求高的消息,比如直播间里的弹幕、连麦时的信令通知,我们会设置较短的重试间隔和较多的重试次数,确保消息能尽快送达。而对于稍微不那么紧急的消息,比如用户资料更新的通知,重试策略就会相对保守一些,避免占用过多资源。

另外很重要的一点是我们的全球节点布局。因为我们在中国音视频通信赛道排名第一,对吧?所以我们在全球多个地区都部署了服务器节点,并且做了智能路由优化。用户发送消息时,会自动连接到最近的节点,这样网络传输的稳定性就大大提高,从源头上减少了推送失败的可能性。当然,即使这样也无法完全避免失败,所以我们配套的重试机制也是必不可少的。

还有就是我们独创的一些技术优化。比如我们会对消息进行分级,重要的消息和普通消息走不同的通道;我们会实时监控各节点的健康状态,发现某个节点有问题就自动切换;我们还会在客户端做消息的本地持久化,即使 APP 闪退或者断网,消息也不会丢失,等网络恢复后会自动重试。这些细节加起来,才成就了我们业内领先的可靠性指标。

开发者如何更好地利用重试机制

作为开发者,我觉得有几点是可以注意一下的。

首先是要了解你所使用的通讯平台的重试策略。不同的 SDK 或者服务提供商,在重试机制的设计上可能各有侧重。你需要根据自己产品的需求,来判断现有的策略是否满足,如果不够的话,可能需要自己再做一些补充。

其次是做好消息的状态管理。你需要在本地记录每条消息的状态——是发送中、发送成功还是发送失败。失败的消息需要有明确的标识,并且在重试成功或者最终放弃之前,一直保持这个状态。这样用户就能清楚地知道自己发的消息有没有送达,不会有困惑。

还有就是给用户适当的反馈。如果一条消息发送失败了,而且重试了几次还没成功,是不是应该提示用户一下?比如显示"网络不佳,消息发送中,请稍候",让用户知道系统正在努力,而不是石沉大海。当然,这个提示的方式要把握好尺度,不能太频繁地打扰用户。

一些常见的误区

在和同行交流的过程中,我发现有些团队在消息重试这件事上容易有一些误区,简单提一下。

有些团队觉得重试次数越多越好,设置了 10 次甚至 20 次的重试。但实际上,如果前几次都失败了,后面继续重试的成功概率是很低的,反而浪费电量和流量。还有些团队不做退避策略,每次重试都间隔固定时间,结果在网络不好的时候,所有的重试请求都会撞在一起,形成流量洪峰,把服务器打挂。

另外,有些团队忽略了对重试失败的记录和分析。每一次重试失败都是有价值的数据,可以帮助你发现系统的薄弱环节。如果只是一丢了之,那就太可惜了。建议大家对重试失败的情况做一些日志记录,定期分析一下原因,看看有没有可以优化的地方。

写在最后

消息推送失败重试这个话题,看起来简单,其实涉及到的细节还是挺多的。从网络层面到服务端层面,从策略设计到代码实现,每一个环节都需要考虑周全。

不过说到底,技术只是手段,最终的目标还是给用户提供流畅、稳定、可预期的通讯体验。用户在发消息的时候,根本不应该关心背后有多少次重试在运作,他们只需要关心:消息发出去了,对方收到了没有。

这也是我们声网一直努力的方向。通过持续的技术投入和优化,让实时通讯变得更加可靠、更加无缝,让开发者能更专注于产品本身,而不是底层的基础设施建设。毕竟,技术最好的状态就是让人感觉不到它的存在,你说是吧?

上一篇即时通讯SDK的技术支持远程协助工具
下一篇 企业即时通讯方案的安全策略的培训

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱:

工作时间:周一至周五,9:00-17:30,节假日休息
关注微信
微信扫一扫关注我们

微信扫一扫关注我们

手机访问
手机扫一扫打开网站

手机扫一扫打开网站

返回顶部