一、背景知识
网络心跳,通常是客户端每隔一小段时间向服务器发送一个数据包(即心跳包),通知服务器自己仍然在线(心跳包中同时可能传输一些必要的数据)。
发送心跳包,从通信层面来说就是为了保持长连接,至于这个包的内容,是没有什么特别规定的,但在移动端IM中为了省流量,一般都是很小的包。
在网关上,由于端口数量有限(0~65535),端口转换表的维护占用系统资源,因此不能无休止地向端口转换表中增加记录。对于过期的记录,网关需要将其删除。
如何判断哪些是过期记录?
网关认为:一段时间内无活动的连接是过期的,应定时检测转换表中的非活动连接,并将之丢弃。而这个丢弃的过程,网关不会以任何的方式通告该连接的任何一端。
为了提升无线网络资源的利用率,运营商长则几分钟,短则数十秒就有可能回收空闲的网络连接。
1)HTTP的Keep-Alive是为了让TCP连接活得更久一点,在发起多个http请求时能复用同一个连接,提高通信效率;
2)TCP的KeepAlive机制意图在于探测连接的对端是否存活,是一种检测TCP连接状况的保鲜机制。
这两个东西看上去太像了,很容易误以为是同一个东西。
事实上,这两个完全是两样不同东西,实现的层面也不同:
HTTP 的 Keep-Alive,是由应用层(用户态) 实现的,称为 HTTP 长连接;
TCP 的 Keepalive,是由 TCP 层(内核态) 实现的,称为 TCP 保活机制。
# TCP KeepAlive 机制,保活时间、保活时间间隔和保活探测次数
net.ipv4.tcp_keepalive_time
net.ipv4.tcp_keepalive_intvl
net.ipv4.tcp_keepalve_probes
默认设置是 7200 秒(2 小时)、75 秒和 9 次探测。
如果使用 TCP 自身的 keep-Alive 机制,在 Linux 系统中,最少需要经过 2 小时 11 分 15 秒才可以发现一个“死亡”连接。
这个时间是怎么计算出来的呢?
其实是通过 2 小时,加上 75 秒乘以 9 的总和。
实际上,对很多对时延要求敏感的系统中,这个时间间隔是不可接受的。
为什么我们需要使用应用层心跳来做检测,而不是直接使用 TCP 的特性呢?
有人会说 TCP 不是有 KeepAlive 机制么,通过这个机制来实现不就可以了吗?
但是事实上,TCP KeepAlive 的机制其实并不适用于此。
因为 TCP KeepAlive 是用于检测连接的死活,而心跳机制则附带一个额外的功能:检测通讯双方的存活状态。
两者听起来似乎是一个意思,但实际上却大相径庭。
应用层心跳有着更大的灵活性,可以控制检测时机,间隔和处理流程,甚至可以在心跳包上附带额外信息。
从这个角度而言,应用层的心跳的确是最佳实践。
二、 网络设置可能存在的问题及影响
客户环境中有深信服或者其他厂家的网关设备、SLB,可能有一个 tcp 的空闲超时时间(长连接超时时间)设置参数,针对公司的消息推送相关功能,需要设置为 15分钟 (客户端心跳为 4-12分钟),否则可能会有推送延迟/收不到推动的问题。
移动端tcp长连接备被断开问题分析说明。
用户反馈移动端消息推送慢,app需要点进去,才知道有人发送了新消息。
先做如下排查工作:
查看 PC端/移动端和服务器端长连接状态,正常
移动端长连接相关工程端口监听,工程日志正常
从应用层找不到原因,就只能从网络层下手了。
登录PC端, 用wireshark指定电脑的网卡,指定服务端地址 (www.example.com:20080)开始抓包
image.png
对wireshark抓包分析:
PC端(客户端)ip 为 192.168.2.5
服务端ip为 120.xx.xx.167(www.example.com)
长连接1: 192.168.2.5:38482 <---> 120.xx.xx.167:20080
14:59:44 服务端给客户端发送了一个 RST,长连接断开
客户端重新发起连接,监听另一个随机端口,和服务端建立一个新的长连接。
长连接2: 192.168.2.5:38616 <---> 120.xx.xx.167:20080
15:01:15 服务端给客户端发送了一个 RST,长连接断开
重复几次,都是类似的效果,从而可知,此网络接入层对tcp空闲超时时间设置为 90s。
截图只列举了连接到20080的连接为例,连接到443端口的HTTP请求的连接存在同样的现象。
造成影响:
对http2请求的影响:产品绝大部分服务都是HTTP2协议,HTTP2协议客户端会积极复用底层TCP连接,网关切断连接后,如果RST包丢包,则会导致客户端继续复用失效连接发起后续请求导致请求大范围超时(安卓端真实遇到的BUG,端上已修改了连接池缓存时间为60秒规避此问题)。
对IM长连接的影响,IM依赖于客户端与服务端维持长连接,以接收数据变更信令,目前此限制导致IM长连接每90秒断开重连一次。在断开重连期间产生的数据变更,可能无法推达,导致消息延迟。
三、处理方法
硬负载 F5 设置 长连接转发,协议为tcp
SLB 设置空闲超时时间为 900s(15分钟)
image.png
image.png
image.png
四、参考
Mars的长连接管理
https://www.jianshu.com/p/394304ab387d
为什么说基于TCP的移动端IM仍然需要心跳保活?
http://www.52im.net/thread-281-1-1.html
彻底搞懂TCP协议层的KeepAlive保活机制
http://www.52im.net/thread-3506-1-1.html