之前有客户反馈,经常会收到客户端断开连接的提醒。影响聊天,希望能查下问题。开始我以为是用户网络波动,导致的连接断开,后来同事跟我反馈,网络正常的时候也会出现断开连接的现象,希望我查下服务器是否配置了什么,会话保持时长之类的参数。
这个问题在c++端比较容易重现,在web端偶现,移动端却没发生过。难道是移动端一直没用户使用,所以他们也不知道?额,不能这样想,不然容易被打。一定是有人用的,可能移动端有啥不为人知的厉害操作?
由于这个涉及的角色只有两个,server端和client端,至少目前来说,已经有两种client端都出现了问题,难道这俩端都写的有问题么?额,有一个是我写的,没弄清楚之前,不能怂。先从服务器端查起,检查相关配置,并没有发现有类似保持连接时间的配置,额。。。这就尴尬了。客户端也没有写超时自动断开的逻辑啊?几个人下午排查了半天,一直没发现问题到底是怎么回事儿。只能采用最笨的方法-抓包,然后请我们的好朋友wireshark分析下。同事在服务器端和客户端同时抓包,可是有时候就是这样,你越希望它重现,它反而越不出现。懊恼。。。
下班之前,CTO问查的如何了。大眼瞪小眼,不敢定结论。
他说他看下,第二天中午,cto拉我们去说这个问题,他找到原因了。
他给我们看异常断开连接前的包,发现断开连接之前会发两个包,每个包间隔是2s,上一条消息的间隔时间是20s,多次异常断开都是如此。这应该不是巧合,这个包来自服务器端,这说明服务器发完这两个包之后,没有得到响应,就把客户端断开了连接。这个实际上是服务器的tcp连接的keeplive机制,当服务器检测到一个socket端长时间不活动的时候,就会发送一个探测包检测client端是否还在,而当client端收到不回应的时候,会关闭连接,回收资源。linux内核跟这个相关的参数有三个:
tcp_keepalive_time(开启keepalive的闲置时长)
tcp_keepalive_intvl(keepalive探测包的发送间隔)
tcp_keepalive_probes (如果对方不予应答,探测包的发送次数)
那是不是这三个内核参数的配置问题呢?检查当前配置:
root@xxx:/# sysctl -a | grep keep net.ipv4.tcp_keepalive_intvl = 2 net.ipv4.tcp_keepalive_probes = 2 net.ipv4.tcp_keepalive_time = 20
果然,跟猜想一样,问题出自这个配置,初始化服务器的时候,会有脚本自动调优。加上应用层上编写代码时,并没有设置此参数,覆盖系统的设置。所以导致了总是莫名其妙的自己断开。
真相大白,对cto的崇拜又多了几分,总能在众人迷惑的时候,站出来当指明灯。
解决方案:
1. 应用层增加socket保活参数配置,覆盖系统配置(完美)
2. 直接修改系统配置文件/etc/sysctl.conf
,应用层增加心跳机制,空闲状态时,每隔19s发送一个心跳包过去(实际采用)。
顺便说一下,之前移动端确实没有发生断开连接的异常情况,是因为移动端的开发主动加过保活机制,赞一个。