基于Spyne与Twisted的Python RPC服务器压测连接异常排查求助
问题场景
我基于Spyne搭配Twisted搭建了一个Python RPC服务器,用Multi-Mechanize做压测的时候遇到了奇怪的问题:测试启动刚满1分钟,服务器就开始出现连接建立失败的错误,具体报错如下:
111274, 254.989, 1516806285, user_group-1, 0.017, HTTPConnectionPool(host='0.0.0.0' port=4321): Max retries exceeded with url: / (Caused by NewConnectionError('<requests.packages.urllib3.connection.HTTPConnection object at 0x7f2c78bf2810>: Failed to establish a new connection: [Errno 99] Cannot assign requested address')), {'increment': 0.0179598331451416}
因为问题刚好在60秒后定时出现,我一开始以为是Twisted有什么默认的隐式速率限制,但翻遍配置也没找到相关设置,就纠结到底是Twisted的限制还是单纯服务器过载导致的。
排查结果
多亏Jean-Paul Calderone的提示,我用命令netstat -at | wc -l统计TCP连接数,发现只要连接数超过28K,就会触发这个“无法分配请求地址”的错误。
这说明问题根本不是Twisted的速率限制,而是系统TCP连接资源耗尽了:
- 压测客户端短时间内创建了大量新连接,而TCP连接关闭后会进入TIME_WAIT状态默认保持60秒,这正好对应问题出现的时间点
- 当客户端的临时端口被耗尽,或者系统允许的TCP连接总数达到上限时,就会出现无法分配地址的报错
优化方向
针对这个问题,可以从这几个角度着手优化:
- 调整系统TCP参数:比如缩短
net.ipv4.tcp_fin_timeout来减少TIME_WAIT的持续时间,开启net.ipv4.tcp_tw_reuse允许复用处于TIME_WAIT状态的端口,同时调高系统允许的最大文件描述符数(每个TCP连接都会占用一个文件描述符) - 优化压测逻辑:让客户端使用连接池复用连接,不要每次请求都新建连接,从根源上减少TIME_WAIT连接的数量
- 服务器端配置:检查Twisted的连接处理配置,比如开启
tcpKeepAlive参数,避免出现连接泄漏的情况
内容的提问来源于stack exchange,提问作者pydoop

