即时通信 IM 开发指南 2:心跳指令详解

《即时通信 IM 开发指南》系列文章将会介绍一个 IM APP 的方方面面,包括技术选型、登录优化等。此外,本文做者会结合他在网易云信多年 iOS IM SDK 开发的经验,深度分析实际开发中的各类常见问题。git

心跳指令是什么?

在使用 TCP 长链接的 IM 服务设计中,每每都会涉及到心跳。心跳通常是指某端(绝大多数状况下是客户端)每隔必定时间向对端发送自定义指令,以判断双方是否存活,因其按照必定间隔发送,相似于心跳,故被称为心跳指令。github

  • 为何须要在应用层作心跳?

那么为何须要在应用层作心跳,难道 TCP 不是个可靠链接吗?咱们不可以依赖 TCP 作断线检测吗?好比使用 TCP 的 KeepAlive 机制来实现。应用层心跳是目前的最佳实践吗?怎么样的心跳才是最佳实践?
是否是之前历来没有仔细考虑过这些问题,仅仅只是个简单的心跳而已啊!
对于客户端而言,使用 TCP 长链接来实现业务的最大驱动力在于:在当前链接可用的状况下,每一次请求都只是简单的数据发送和接受,免去了 DNS 解析,链接创建等时间,大大加快了请求的速度,同时也有利于接受服务器的实时消息。
但前提是链接可用。若是链接没法很好地保持,每次请求就会变成撞大运:运气好,经过长链接发送请求并收到反馈。运气差,当前链接已失效,请求迟迟没有收到反馈直到超时,又须要一次链接创建的过程,其效率甚至还不如 HTTP。而链接保持的前提必然是检测链接的可用性,并在链接不可用时主动放弃当前链接并创建新的链接。
基于这个前提,必需要有一种机制用于检测链接可用性。同时移动网络的特殊性也要求客户端须要在空余时间发送必定的信令,避免链接被回收。详见《微信和运营商的撕B》
而对于服务器而言,可以及时获悉链接可用性也很是重要:一方面服务器须要及时清理无效链接以减轻负载,另外一方面也是业务的需求,如游戏副本中服务器须要及时处理玩家掉线带来的问题。
上面说了保持链接的重要性,那么如今回到具体实现上。为何咱们须要使用应用层心跳来作检测,而不是直接使用 TCP 的特性呢?
咱们知道 TCP 是一个基于链接的协议,其链接状态是由一个状态机进行维护,链接完毕后,双方都会处于 established 状态,这以后的状态并不会主动进行变化。这意味着若是上层不进行任何调用,一直使 TCP 链接空闲,那么这个链接虽然没有任何数据,但还是保持链接状态,一天,一星期,甚至一个月,即便在这期间中间路由崩溃重启无数次。举个现实中常常遇到的栗子:当咱们 ssh 到本身的 VPS 上,而后不当心踢掉网线,此时的网络变化并不会被 TCP 检测出,当咱们从新插回网线,仍旧能够正常使用 ssh,同时此时并无发生任何 TCP 的重连。
有人会说 TCP 不是有 KeepAlive 机制么,经过这个机制来实现不就能够了吗?可是事实上,TCP KeepAlive 的机制其实并不适用于此。Keep Alive 机制开启后,TCP 层将在定时时间到后发送相应的 KeepAlive 探针以肯定链接可用性。通常时间为 7200 s,失败后重试 10 次,每次超时时间 75 s。显然默认值没法知足咱们的需求,而修改过设置后就能够知足了吗?答案仍旧是否认的。由于 TCP KeepAlive 是用于检测链接的死活,而心跳机制则附带一个额外的功能:检测通信双方的存活状态。二者听起来彷佛是一个意思,但实际上却截然不同。考虑一种状况,某台服务器由于某些缘由致使负载超高,CPU 100%,没法响应任何业务请求,可是使用 TCP 探针则仍旧可以肯定链接状态,这就是典型的链接活着但业务提供方已死的状态,对客户端而言,这时的最好选择就是断线后从新链接其余服务器,而不是一直认为当前服务器是可用状态,一直向当前服务器发送些必然会失败的请求。
从上面咱们能够知道,KeepAlive 并不适用于检测双方存活的场景,这种场景还得依赖于应用层的心跳。应用层心跳有着更大的灵活性,能够控制检测时机,间隔和处理流程,甚至能够在心跳包上附带额外信息。从这个角度而言,应用层的心跳的确是最佳实践。算法

  • 如何实现心跳指令?

从上面咱们能够得出结论,目前而言,应用层心跳的确是检测链接有效性,双方是否存活的最佳实践,那么剩下的问题就是怎么实现。
最简单粗暴作法固然是定时心跳,如每隔 30 秒心跳一次,15 秒内没有收到心跳回包则认为当前链接已失效,断开链接并进行重连。这种作法最直接,实现也简单。惟一的问题是比较耗电和耗流量。以一个协议包 5 个字节计算,一天收发 2880 个心跳包,一个月就是 5 2 2880 * 30 = 0.8 M 的流量,若是手机上多装几个 IM 软件,每月光心跳就好几兆流量没了,更不用说频繁的心跳带来的电量损耗。
既然频繁心跳会带来耗电和耗流量的弊端,改进的方向天然是减小心跳频率,但也不能过于影响链接检测的实时性。基于这个需求,通常能够将心跳间隔根据程序状态进行调整,当程序在后台时(这里主要考虑安卓),尽可能拉长心跳间隔,5 分钟,甚至 10 分钟均可以。而当 App 在前台时则按照原来规则操做。链接可靠性的判断也能够放宽,避免一次心跳超时就认为链接无效的状况,使用错误积累,只在心跳超时 n 次后才断定当前链接不可用。固然还有一些小 trick 好比从收到的最后一个指令包进行心跳包周期计时而不是固定时间,这样也可以必定程度减小心跳次数。服务器

以上就是网易云信对于心跳指令的理解和实践,《移动IM开发指南》第三篇文章将为你们介绍如何优化登陆模块,敬请期待。微信


随着即时通信以及音频处理和压缩技术的不断发展,效果更好、适用范围更广、性能更高的算法和新的技术必将不断涌现,若是你有好的技术或者分享,欢迎关注网易云信官方博客和 GitHub:网络

关注更多技术干货内容: 网易云信博客
欢迎关注 网易云信 GitHub
欢迎关注 网易云信官网
相关文章
相关标签/搜索