我们的系统有一个应用启用了连接池来连接后端的应用,最近我却发现这个连接池貌似并不能正常工作。理论上来说,当启用了连接池,应用到后端的连接应该稳定才对,而我通过 ss 观察到的现象却是应用不断的建立连接,断开连接。更为奇怪的是,应用方并没有出现 TIME_WAIT。起初我怀疑是服务端主动关闭了连接,但是在服务端也并没有发现 TIME_WAIT,所以可以基本排除这个问题。
之后抓了下包才发现,原来是应用端主动发了 RST 来终止连接:
但是应用是正常通过 close()
系统调用来关闭连接的啊,理论上是应该发 FIN 的,为什么会发送 RST 呢?google 了一番,在 @淘宝褚霸 的 blog 找到了答案:
如果你的接收缓冲去还有数据,协议栈就会发 RST 代替 FIN.
我们再来验证一下:
- 接收缓冲区还有数据,发 RST
local socket = require("socket")
local host, port = "www.baidu.com", 80
local sock = socket.connect(host, port)
sock:settimeout(1)
sock:send("GET / HTTP/1.1\r\n\r\n")
sock:close()
- 接收缓冲区读取干净了,发 FIN
local socket = require("socket")
local host, port = "www.baidu.com", 80
local sock = socket.connect(host, port)
sock:settimeout(1)
sock:send("GET / HTTP/1.1\r\n\r\n")
while true do
local line, err = sock:receive()
if err == "timeout" then
break
end
end
sock:close()
最后推荐大家使用 nicstat
来监控系统的 RST 情况: