TCP服务端主动断开连接问题
作者:
| 更新日期:遇到一个神秘的问题:客户端不断的在重连服务。
本文首发于公众号:天空的代码世界,微信号:tiankonguse
零、背景
多年前的时候,我曾提起过我名下挂了一个2013年的中转服务,这个服务多年来一直在线上裸奔,没人动过。
当时在《历史悠久的微博中转》这篇文章里分享了这个中转服务的架构设计。
后来还在《记一次微博中转异常》文章里分享了遇到的一个问题。
这不,最近又遇到问题了。
一、流量不均衡
元旦晚会前几天,大家都在准备服务扩容的事情。
运维问我中转还能扩容吗?
我回答国庆的时候已经尽最大可能扩容了,之后再扩整个服务就起不来了,应该到达系统架构上限了。
我也曾在内心自问:具体架构的哪里到达上限呢?
自己回答:还没细看代码,不是很清楚。
然后又进行合理推理:宏观上看架构是可以无限扩容的,应该是微观上某个地方遇到类似于千年虫的问题了。
而元旦前夕,突然收到最大值告警。
一看流量,访问量翻了好几倍,部分机器网卡跑的很高。
看下机型配置,都是8核、16G内存、1G流量。
竟然有单机 qps 高达 18~20W/s,流量几乎跑满。
注:周四流量还低,不过监控系统只能看到最近的若干天,我记得暴涨之前大概只有不到 40M,与高峰期比翻了 3倍。
为啥有这么大的流量呢?
这应该归属是业务架构设计不合理,没有正确使用中转这个原因。
1、使用多台机器重复生产相同的数据。
2、每台机器死循环的方式生产相同数据。
3、生产的每条数据是历史上全量变更消息。
4、80+个消费者分别订阅一份全量数据。
这样,相同的数据被放大了无数倍,就出现了上图的峰值每秒 200万的qps。
没业务反馈有啥问题,暂时没人敢动了。
不过我发现一个地方不对劲:服务有20台机器,总量200万的话,单机应该 10万才对。
为啥会有单机 20万的量呢?
二、发现问题
先看下中转的架构吧。
架构比较简单,分为五个模块:配置中心、生成者、接口机、转发机、消费者。
上一小节提到的单机 qps 20 万指的是转发机成功向消费者发送的包量。
我的第一反应是去那个转发机看看错误日志,结果发现这台机器没任何问题。
接着我就分析监控视图,发现在接口机到转发机发数据时,就已经不均匀了。
本来接口机会把消息平均的发给所有转发机。
现在遇到这种情况说明部分接口机或转发机有问题,只能多登陆几台机器,看看能不能发现什么错误日志。
看了五六台机器的日志后,还真发现一个问题:部分接口机在不断的创建连向转发机的连接。
那就解释通了:接口机与某些转发机连接不通,流量就被发给其他机器了,从而流量不均匀。
三、分析问题
那为什么在不断的创建连接呢?
使用 tcpdump 抓包一看,发现连上转发机后,转发机作为服务端马上主动把连接断开了。
所以问题还是出在转发机上,不过是流量低的那些转发机上(连接连不上,流量过不来)。
去有问题的转发机,没发现什么错误日志,看了看中转业务代码,也没发现什么问题。
那只能祭出终极方法了:查看网络框架的代码。
大概看了框架代码,也没发现问题。
一想,这个网络框架与中转业务都跑了六七年了,逻辑应该没有大问题,需要注意那些边界情况。
于是再回头细看网络框架的各种边界,还真发现有种情况会导致连接出问题。
框架对TCP的连接数做了最大限制。
看到这,就是验证猜想了。
使用lsof
查看fd
数量,确实挺多的。
再使用gcore
生成服务的内存镜像,然后gdb
进去输出相关变量。
还真是进入了连接最大限制这段代码。
注:这里是网络框架逻辑上的限制,而不是系统级别的限制,所以查看/proc/limit
和lsof
都不能实锤问题。
四、解决问题
既然确定问题了,就好办了。
而且发现这个限制是配置化的,现在配置的是128
,那直接设置成无限大就行了。
但是又看了下框架代码,发现连接还真不能随便设置的太大。
因为这个框架需要预先评估需要多少连接,然后启动的时候就申请创建了所有的资源。
考虑到这个连接仅仅是转发机与接口机之间的,也就是有多少转发机就有多少个连接。
那就把转发机配置成256
吧。
预留一倍的 buffer 应该可以用到这个中转退休了。
五、最后
回头想想,起初是流量暴涨问题,然后发现业务架构不合理问题,接着发现流量不均衡问题,再接着发现连接被服务端主动断开问题,最终发现是网络框架对连接数做了限制。
定位问题就是这样一环扣一环。
不过连接被断开这个现象真不好发现,只有部分接口机异常有错误日志,登录很多几次才发现问题的。
这一环节算是运气环节了,有耐心一台台看日志的话肯定可以发现。 , 如果当时只登录几台,恰好没看到错误日志,那就没有下文了。
稍等,我怎么记得遇到连接被断开问题的时候,去转发机和接口机分别执行了netstat
命令,看到的数据怎么不一致呢?
敬请期待下篇TCP话题文章:连接未释放问题。
-EOF-
本文公众号:天空的代码世界
个人微信号:tiankonguse
公众号ID:tiankonguse-code
本文首发于公众号:天空的代码世界,微信号:tiankonguse
如果你想留言,可以在微信里面关注公众号进行留言。