假设有以下突发意外情况:
我们知道,为了让消息能更加实时、可靠、快速地触达到接收方,大部分 IM 系统会通过“长连接”的方式来建立收发双方的通信通道,长连接一旦建立,就一直存在,除非网络被中断。
有了这基于 TCP 长连接的通信协议,在用户上线连接时,可以在服务端维护好连接到服务器的用户设备和具体 TCP 连接的映射关系,服务端也能通过这个映射关系随时找到对应在线的用户的客户端。对于发送方来说,发送消息也能通过“长连接”通道把消息给到 IM 服务端。
但长连接并不是永久可用的,当长连接在中间链路出问题时,为了不使用户感知到,应快速通知连接的两端,并重新建立新的可用连接,从而使长连接一直保持“高可用”状态,这个能够快速、不间断识别连接可用性的机制,称为“心跳机制”。
“心跳机制”会持续地往连接发送“模拟数据”,一方面是为了试探连接的可用性,另一方面也是为了保证数据的持续流通,让连接在没有真正业务数据收发的情况下,不会被中间的网络运营商以为连接没有被使用而切断连接。
消息之所以能够实现“服务端推送”,是因为针对每一台上线的设备,都会在 IM 服务端维护相应的 用户设备<->网络连接
这样的映射关系,除此之外,为了节省网络开销,还会在服务端临时缓存一些不用每次请求都携带的客户端信息,如 app 版本号、操作系统、网络状态等,甚至还会在服务端维护一些“用户在线状态”和“所有在线设备”这些信息,便于业务使用,这样客户端一旦建好长连接,只需要首次携带这些信息,后续请求可以不用再携带,而是使用 IM 服务端缓存的这些信息。
若没有心跳机制,当长连接异常而 IM 服务端无法感知到,会产生两种不良后果:
当客户端和 IM 服务端之间的网络在中间某些环节断开,或服务器负载过高,则会出现客户端在一定的超时时间内,发出的心跳包得不到 IM 服务端响应的现象,这时客户端就可以认为和服务端的长连接不可用,自动断线重连,保持长连接的可用性。
即使用户网络和中间路由网络都正常,若一直没有数据收发,运营商就会将这个长连接清除掉,来降低自身网关的压力,这个清除动作不会被客户端和 IM 服务端感知到,为了避免被运营商干掉,客户端会在没有消息收发的空闲时间给服务端发送心跳包,使长连接存活时间更长。
Keepalive 并不是 TCP 协议的一部分,但大多数操作系统都实现了这个机制,操作系统默认是关闭这个特性的,需要由应用层来开启。TCP 的 keepalive 会在连接空闲期按一定的频次,自动发送不携带数据的探测报文,来探测对方是否存活。
Keepalive 默认是关闭的,开启 Keepalive 需要在 TCP 的 socket 中单独开启,操作系统层面有三个参数影响到 Keepalive 的行为:
tcp_keepalive_time 7200 // 心跳周期:距离上次传送数据多少时间未收到新报文判断为开始检测,单位秒,默认7200s
tcp_keepalive_intvl 75 // 超时时间:检测开始每多少时间发送心跳包,单位秒,默认75s
tcp_keepalive_probes 9 // 失败后重试次数:发送几次心跳包对方未响应则close连接,默认9次
优点:
缺点:
应用层心跳实际上是客户端每隔一定时间间隔,向 IM 服务端发送一个业务层的数据包告知自身存活。如果 IM 服务端在一定时间内没有收到心跳包,就认定客户端由于某种原因连接不可达了,此时就会从 IM 服务端把这个连接断开,同时清除相应分配的其他资源。
优点:
缺点:
心跳间隔能够根据网络环境自动调整,逐步逼近 NAT 超时临界点,在保证 NAT 不超时的情况下尽量节约设备资源,常见的有二分法。但需要权衡使用。
《即时消息技术剖析与实战》学习笔记8——IM系统如何保证长连接的可用性
原文:https://www.cnblogs.com/sunshineliulu/p/12245975.html