关于即时通讯:阿里IM技术分享五闲鱼亿级IM消息系统的及时性优化实践

43次阅读

共计 6414 个字符,预计需要花费 17 分钟才能阅读完成。

本文由阿里闲鱼技术团队有攸分享,原题“向音讯提早说 bybye:闲鱼音讯及时达到计划”,有订正和改变,感激作者的分享。

1、引言

IM 音讯作为闲鱼用户重要的交易征询工具,外围指标有两点:

1)第一是保障用户的音讯不失落;
2)第二是保障用户的音讯及时送达接管方。

IM 音讯依据音讯的接管方设施是否在线,分为离线和在线推送。数据显示目前闲鱼每天有超过一半以上的 IM 音讯是走在线通道的,而在线音讯的达到率、及时性是间接影响用户体验的。

本文将依据闲鱼 IM 音讯零碎在音讯及时性方面的优化实际,详细分析了 IM 在线通道面临的各种技术问题,并通过相应的技术手段来优化从而保障用户音讯的及时达到。

PS:如果您对 IM 音讯可靠性还没有概念,倡议先浏览这篇入门文章《零根底 IM 开发入门(二):什么是 IM 零碎的实时性?》。

学习交换:

  • 即时通讯 / 推送技术开发交换 5 群:215477170 [举荐]
  • 挪动端 IM 开发入门文章:《新手入门一篇就够:从零开发挪动端 IM》
  • 开源 IM 框架源码:https://github.com/JackJiang2…

(本文同步公布于:http://www.52im.net/thread-37…)

2、系列文章

本文是系列文章的第 5 篇,总目录如下:

《阿里 IM 技术分享(一):企业级 IM 王者——钉钉在后端架构上的过人之处》
《阿里 IM 技术分享(二):闲鱼 IM 基于 Flutter 的挪动端跨端革新实际》
《阿里 IM 技术分享(三):闲鱼亿级 IM 音讯零碎的架构演进之路》
《阿里 IM 技术分享(四):闲鱼亿级 IM 音讯零碎的牢靠投递优化实际》
《阿里 IM 技术分享(五):闲鱼亿级 IM 音讯零碎的及时性优化实际》(* 本文)

3、以后面临的问题

3.1 端内长连贯中断
在 IM 场景中,用户与云端通信频繁,且为了实现用户的音讯及时达到,往往采纳云端下推音讯的形式触达用户,所以用户在线时设施与云端会维持一条 TCP 长连贯通道,能够更轻量级的与服务端进行交互,古代 IM 即时通讯的上行音讯都是通过长连下发的。

以后闲鱼 IM 音讯零碎应用的是 ACCS 长连贯,ACCS 是淘宝无线提供的全双工、低延时、高平安的通道服务。

但因为用户设施网络状态的不确定性,可能会产生各种各样的网络异常情况导致 ACCS 长连贯通道中断。而长连贯一旦意外中断,就会导致用户无奈及时收到在线音讯。

针对这个问题,咱们须要尽可能及时的感知到长连中断并尝试重连。具体的优化思路会在本文前面的内容中分享。

3.2 下推的音讯未达
感知长连中断并重连只能在大多数工夫保障长连贯的有效性,然而在长连贯有效或不稳固期间下推的音讯客户端可能基本收不到。

简略说就是仅仅有重连机制无奈保障上行音讯必达,可能有以下场景导致上行音讯失败:

1)服务端发送上行音讯时长连畅通,音讯在传输路上通道断掉,客户端无奈收到;
2)设施的在线状态存在提早,服务端上行音讯时认为设施在线,实际上设施曾经离线,无奈收到;
3)客户端收到了上行音讯,但端上后续解决失败(比方落库失败,音讯没有胜利展现给用户)。

咱们通过数据埋点统计得出,ACCS 长连贯的上行成功率在 97% 左右。

ACCS 长连贯的上行成功率的统计办法如下:

ACCS 上行成功率 = 通过 ACCS 胜利上行且客户端收到的音讯量 / 服务端认为通过 ACCS 胜利上行的音讯量

有心急的同学就要问了,丢了 3% 的音讯吗?

并没有!这 3% 的音讯不会失落,只是不保障及时触达给用户。

咱们的音讯同步模型是推拉联合模式,在用户拉取音讯时会拉取到设施以后位点与服务端最新位点的所有音讯,ACCS 上行失败的音讯会通过被动拉模式获取到,但客户端被动拉取音讯的触发机会无限。

以后客户端被动拉取音讯的触发机会次要有以下几个:

1)用户冷启动 app,被动同步音讯;
2)用户被动下拉刷新;
3)app 后盾切换前台;
4)收到一条推送音讯,客户端发现新音讯的位点跟本地最新的位点有 gap,触发同步。

可见:上述被动同步音讯的触发很大水平上依赖用户行为或者有没有收到新音讯,难以保障音讯及时达到。

如果是用户高频关上的 IM 软件,这样也不会有太大的问题。然而闲鱼 app 的活跃度较低,有时候甚至依赖 IM 音讯拉活,而且一条提早的音讯触达可能导致用户错过一笔交易,闲鱼音讯不容许有这样的提早产生。

基于上述剖析,咱们先形容一个数据指标来反映现状。

通过下面的形容可知:ACCS 音讯并不全都是推下来的,也可能是被动拉下来的。如果是推,必然能够及时达到;如果是拉,则受限于用户行为。

拉的这部分音讯,咱们定义为 ACCS 音讯弥补达到,而后计算 ACCS 音讯弥补达到耗时,音讯范畴限定为服务端 ACCS 胜利上行然而客户端通过被动拉取同步到的音讯,以往的版本这个数据在 60 分钟左右。

留神:这个数据并不是音讯触达到用户的耗时,因为如果在线转离线触达,拉取到音讯的工夫取决于用户行为(用户何时关上了 app),但这个数据也能大抵反映在线音讯的达到提早情况。

ACCS 长连贯的音讯弥补达到耗时的统计办法如下:

ACCS 音讯弥补达到耗时 = 客户端通过拉获取到 ACCS 音讯的工夫 – 服务端 ACCS 上行工夫

接下来本文将从长连贯的重连和未达音讯重发两个方面具体讲述咱们是如何优化在线通道稳定性的,从而优化并保障音讯的及时达到。

4、优化伎俩 1:减少长连贯重连机制

4.1 长连贯为什么会中断?
有因必有果,咱们先来剖析下有哪些起因会导致连贯中断。

对于 IM 这种场景下来说,通常可能有以下起因:

1)用户设施断网;
2)设施产生了网络切换;
3)设施处于弱网环境,网络不稳固;
4)设施网络失常,TCP 连贯因为 NAT 超时导致连贯被运营商中断。

对于 APP 来说,如果是用户操作导致网络状态变动的状况,会有网络状态变动事件告诉,这种状况能够监听事件并被动尝试重连。但事实中的大多数状况都是“意料之外”(正如下面列举的这些断网可能性一样)。

那么既然“意料之外”的断网无奈预知,技术上能够如何无效的感知到各种异样情况呢?

PS:如果要透彻了解断网、弱网、TCP 链接有效性,并不是本文能讲的分明的,能够参照上面的材料深刻了解一下,值得好好学习。

对于 TCP 链接自身的有效性问题,能够读以下两篇:

《为何基于 TCP 协定的挪动端 IM 依然须要心跳保活机制?》
《鲜为人知的网络编程(十二):彻底搞懂 TCP 协定层的 KeepAlive 保活机制》

对于挪动网络的复杂性问题,能够从以下几篇入门的科普文章学习一下:

《IM 开发者的零根底通信技术入门(十一):为什么 WiFi 信号差?一文即懂!》
《IM 开发者的零根底通信技术入门(十二):上网卡顿?网络掉线?一文即懂!》
《IM 开发者的零根底通信技术入门(十三):为什么手机信号差?一文即懂!》
《IM 开发者的零根底通信技术入门(十四):高铁上无线上网有多难?一文即懂!》

对于挪动弱网带来的各种问题、优化计划等,能够通过以下几篇零碎学习一下:

《古代挪动端网络短连贯的优化伎俩总结:申请速度、弱网适应、平安保障》
《挪动端 IM 开发者必读(一):通俗易懂,了解挪动网络的“弱”和“慢”》
《挪动端 IM 开发者必读(二):史上最全挪动弱网络优化办法总结》
《百度 APP 挪动端网络深度优化实际分享(三):挪动端弱网优化篇》

4.2 心跳检测机制
像大多数链路保活场景一样,IM 这种场景下最无效的检测伎俩就是心跳检测(如果你对 TCP 链路保活还没有什么概念,倡议先读《为何基于 TCP 协定的挪动端 IM 依然须要心跳保活机制?》)。

原理就是:客户端通过定时发送心跳包,服务端收到心跳包后再反馈给客户端,通过客户端和服务端这一来一去的配合,就能够实现客户服和服务端各自都能感知到连贯是否中断。

从及时性成果来看:心跳距离越短越好,而频繁的心跳检测势必会带来用户流量以及电量的损耗,所以咱们的实现目标是如何尽可能少的心跳检测而又尽量及时地感知到长连中断的意外状况。

状态机 + 音讯心跳队列:

在心跳协定设计上,要留神心跳包的外围指标是检测长连通道是否畅通,客户端被动上行心跳包且能收到服务端回包,就认为长连通道衰弱。所以心跳的上行音讯以及回包的数据包应尽可能小。一般来说,通过协定头标识心跳包及响应即可(这样就能节俭协定包大小)。

PS:对于心跳机制的入门文章能够详读《一文读懂即时通讯利用中的网络心跳包机制:作用、原理、实现思路等》。

4.3 心跳策略
心跳策略是实现咱们上述指标的外围机制,本文仅简略列举几种心跳策略。

比方以下这几种:

1)短心跳检测 初始状态间断 ping 3 次 收到 ACK 后,能够认为进入稳固状态;
2)惯例固定时长心跳(依据 app 状态不同,频率可调 Mid+,Mid-, Long);
3)自适应心跳 依据设施网络状态变动主动适应的心跳距离;
4)冗余心跳,app 后盾切前台,被动心跳一次。
对于心跳策略的具体设计甚至能够独自写一篇文章,有趣味的同学能够浏览以下举荐的文章持续深入研究。

《微信团队原创分享:Android 版微信后盾保活实战分享(网络保活篇)》
《挪动端 IM 实际:实现 Android 版微信的智能心跳机制》
《挪动端 IM 实际:WhatsApp、Line、微信的心跳策略剖析》
《融云技术分享:融云安卓端 IM 产品的网络链路保活技术实际》
《Web 端即时通讯实际干货:如何让你的 WebSocket 断网重连更疾速?》
《正确理解 IM 长连贯的心跳及重连机制,并入手实现(有残缺 IM 源码)》
《一种 Android 端 IM 智能心跳算法的设计与实现探讨(含样例代码)》
《手把手教你用 Netty 实现网络通信程序的心跳机制、断线重连机制》

5、优化伎俩 2:音讯 ACK 应答与重发机制

5.1 概述
为了解决下面的问题,咱们同时也引入了音讯 ACK 应答与重发机制。

整体思路是:客户端在收到 ACCS 音讯并解决胜利后,给服务端回一个 ACK 应答包,服务端下发 ACCS 音讯时将音讯退出重试队列,收到 ACK 应答包后更新音讯达到状态,并终止重试。

整体设计流程图如下:

该计划的难点即重试处理器的实现设计,接下来咱们将重点讲述这部分的具体设计。

5.2 重试队列存储设计
咱们采纳阿里云表格存储 TimeLine 模型来存储上行音讯的达到状态。Timeline 模型是针对音讯数据场景所设计的数据模型,它能满足音讯数据场景对音讯保序、海量音讯存储、实时同步的非凡需要,在 IM、Feed 流等音讯场景利用宽泛。(对于 TimeLine 模型,这里有篇具体的文章能够学习一下《古代 IM 零碎中聊天音讯的同步和存储计划探讨》)

咱们给每个用户设施定义一个 TimeLine,timeline-id 定义为 userId_deviceId,sequenceId 自定义为音讯位点。

存储构造如下:

每通过 ACCS 胜利上行一条音讯,则插入到接管用户设施的 TimeLine 中,收到 ACK 后依据音讯 id 更新音讯达到状态。

同时因为重试动作只产生在上行音讯后较短的一段时间内,所以咱们设置一个比拟短的全局过期工夫即可,防止数据收缩。

5.3 提早重试设计

如上图所示:

1)每通过 ACCS 下发一条音讯,先插入到 Timeline 中,初始状态为未达,而后生产一条提早 N 秒的提早音讯;
2)每次生产到提早音讯后,读取 tablestore 中该音讯的达到状态,如达到则终止提早,否则持续;
3)每次重试先判断设施是否在线,如果设施不在线,转发离线通道并终止重试,如果设施在线,则重推未达到的音讯,并再次提早 N 秒生产;
4)每条音讯的重试生命周期中用的同一条提早音讯,最多重试生产 M 次,超过次数不再重试并打日志埋点(后续能够监控这种状况并基于这个数据进行优化)。
5.4 提早重发策略
提早重发策略是指在重发流程中,如何抉择适合的延迟时间来使得重发的效率最高。

不同用户在不同工夫、地点所处的网络环境差异较大,网络复原到稳固态所须要的工夫也有差别,须要选用适合的提早策略来保障重发效率。

最优的提早策略的指标是在最短的工夫内,应用起码的重发次数将音讯投递胜利。以下是几种可选的计划。

5.4.1)固定延迟时间:

要想找到最优的提早策略,必须从数据中通过剖析失去答案,天马行空的设想往往离理论相差甚远。

咱们先采纳固定的延迟时间 (10s) 最大重试 6 次来剖析一波数据:

通过这组数据能够看到:有约 85% 的音讯在 40s 内重发能够投递胜利,还有 12% 的音讯在达到最大重试次数后仍旧没有收到 ACK。在 4 次重试之后,第 5 次胜利只有 2.03%,第 6 次只有 0.92%,持续重发的收益曾经变得很低。

6 次当前还有局部音讯没有收到 ACK,这部分音讯如果用固定延迟时间策略,性价比很低,频繁重发节约系统资源,咱们须要持续改良策略。

5.4.2)固定提早 + 固定步长递增:

思考到局部用户的网络短时间无奈复原,频繁的短距离重发价值不大,咱们采纳 4 次固定短距离提早 N 秒后,每次延迟时间都是上一次延迟时间递增固定步长 M 秒的策略。直到收到 ACK、用户设施离线或者达到了最大延迟时间 MAX(N)。

这种策略肯定水平上能够解决固定延迟时间重发策略的问题,但如果用户短时间网络无奈复原,每次重发都要从新递增,也不是一种最优解。

5.4.3)自适应提早:

设计流程图:

如上图:咱们最终衍生出了自适应提早策略。

自适应提早是指:依据用户的网络情况,采取主动调整的延迟时间,以冀望达到最高的重发效率。

具体是:新音讯先通过 4 次固定 N 秒的短提早来探测设施的网络情况,一旦网络复原,咱们将设施的 N 值清空(设施 N 值是指依据上几次重发教训,以后设施网络能回复 ACK 所须要的最短时间,默认状况该值为空,代表用户设施网络失常)。4 次重发后仍旧收不到 ACK,咱们尝试读取设施 N 值,如果为空,则取初始值,当前每次提早都递增固定步长 M,并在重发后更新以后设施的 N 值,直到音讯收到 ACK 或者达到了最大延迟时间 MAX(N)。

5.5 新老版本兼容性
须要留神的是老版本的 app 是不会回 ACK 的,如果下发给老版本设施的音讯也退出重试队列,那此类音讯将始终重试到最大次数才会终止,无端耗费资源。

所以咱们设计在 ACCS 长连建设之后,客户端被动上行一条设施信息,其中蕴含 app 的版本号,服务端存储肯定工夫,在将音讯退出重试队列之前,先校验接收者设施 app 的版本号,符合要求再退出重试队列。

6、最终优化后的成果

音讯重连重发计划上线后,咱们下面定义的指标 ACCS 弥补达到工夫 从 60 分钟大幅升高至 15 分钟,降幅达 75%。

从而印证了咱们的技术剖析,同时用户无关音讯提早的舆情反馈大幅降落,可见音讯重发机制对保障用户音讯及时达到成效显著。

7、将来瞻望

音讯在线通道的稳定性优化至此已告一段落,将来咱们将持续优化闲鱼音讯的应用体验,包含根底性能的欠缺以及根底体验的晋升。

根底性能方面:咱们在近期的版本中曾经反对了音讯撤回、草稿性能,后续将逐渐反对发送定位,会话分组、备注,音讯搜寻等性能。

根底体验方面:咱们对音讯的 UI 款式做了优化降级,并优化了 app 音讯 tab 页的 cpu 及内存应用,后续将持续从流量、电量、性能方面持续优化音讯的应用体验。

附录:参考资料

[1] 为何基于 TCP 协定的挪动端 IM 依然须要心跳保活机制?
[2] 鲜为人知的网络编程(十二):彻底搞懂 TCP 协定层的 KeepAlive 保活机制
[3] 古代 IM 零碎中聊天音讯的同步和存储计划探讨
[4] 古代挪动端网络短连贯的优化伎俩总结:申请速度、弱网适应、平安保障
[5] 挪动端 IM 开发者必读(二):史上最全挪动弱网络优化办法总结
[6] IM 开发者的零根底通信技术入门(十二):上网卡顿?网络掉线?一文即懂!
[7] IM 开发者的零根底通信技术入门(十三):为什么手机信号差?一文即懂!
[8] 挪动端 IM 实际:实现 Android 版微信的智能心跳机制
[9] 融云技术分享:融云安卓端 IM 产品的网络链路保活技术实际
[10] Web 端即时通讯实际干货:如何让你的 WebSocket 断网重连更疾速?

本文已同步公布于“即时通讯技术圈”公众号。
同步公布链接是:http://www.52im.net/thread-37…

正文完
 0