我有一个带有jails的FreeBSD机器 – 特别是两个运行nginx的机器,另一个运行一个Java程序,通过Jetty接受请求(embedded模式)
Jetty不断收到500个请求/秒,最近有一个问题,我将在Nginx和Jetty之间的LAST_ACK状态中持续有超过60,000个连接。
所有连接的分配(包括一些其他服务,特别是php-fpm)
root@host:/root # netstat -an > conns.txt root@host:/root # cat conns.txt | awk '{print $6}' | sort | uniq -c | sort -n 18 LISTEN 112 CLOSING 485 ESTABLISHED 650 FIN_WAIT_2 1425 FIN_WAIT_1 3301 TIME_WAIT 64215 LAST_ACK
分发nginx – >docker连接
root@host:/root # cat conns.txt | grep '10.10.1.57' | awk '{print $6}' | sort | uniq -c | sort -n 1 3 CLOSE_WAIT 3 LISTEN 18 FIN_WAIT_2 125 ESTABLISHED 64193 LAST_ACK
我希望每个请求都完全closures连接。 客户请求相距约10分钟,因此连接必须closures。
一些连接,
tcp4 0 0 10.10.1.50.46809 10.10.1.57.9050 LAST_ACK tcp4 0 0 10.10.1.50.46805 10.10.1.57.9050 LAST_ACK tcp4 0 0 10.10.1.50.46797 10.10.1.57.9050 LAST_ACK tcp4 0 0 10.10.1.50.46794 10.10.1.57.9050 LAST_ACK tcp4 0 0 10.10.1.50.46790 10.10.1.57.9050 LAST_ACK tcp4 0 0 10.10.1.50.46789 10.10.1.57.9050 LAST_ACK tcp4 0 0 10.10.1.50.46771 10.10.1.57.9050 LAST_ACK etc..
maxIdleTime设置为2000 – 在这之前所有的连接都在ESTABLISHED但是现在是LAST_ACK Connection: close (即response.setHeader(HttpHeaders.CONNECTION, HttpHeaderValues.CLOSE); ) reset_timedout_connection打开 我无法弄清楚如何让nginx或jetty强行closures连接,这是否需要在Jetty中修复,以便在请求完成后完全closures套接字?
非常感谢
编辑:忘记我的nginxconfiguration代理设置 –
proxy_pass http://10.10.1.57:9050; proxy_set_header HTTP_X_GEOIP $http_x_geoip; proxy_set_header GEOIP_COUNTRY_CODE $geoip_country_code; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header Connection ""; proxy_http_version 1.1;
EDIT2:强制Jetty通过request.getConnection().getEndPoint().close()不执行任何操作来closures连接 – 显然连接被closures了(因为它在LAST_ACK ),但是为什么它不能通过呢? 由于某种原因,Nginx是否保持连接对后端开放?
OK,我终于可以说服Jetty玩得很好。
回顾一下,现在我的连接在机器范围内是这样的:
24 LAST_ACK 36 CLOSING 117 FIN_WAIT_2 175 ESTABLISHED 351 FIN_WAIT_1 4725 TIME_WAIT
而在nginx和Jetty之间
1 FIN_WAIT_2 3 LISTEN 14 ESTABLISHED
我已经closures了整个连接, EndPoint (在EndPoint上调用close()closures底层的SocketChannel )使用这个方便的方法:
private void finishRequest(String message, Request baseRequest, HttpServletResponse response) throws IOException { ByteArrayISO8859Writer writer = new ByteArrayISO8859Writer(1500); writer.write(message); writer.flush(); // set the content length response.setContentLength(writer.size()); // write the response OutputStream outputStream = response.getOutputStream(); writer.writeTo(outputStream); // close the streams outputStream.close(); writer.close(); baseRequest.getConnection().getEndPoint().close(); }
(我只发送最多一行到客户端,所以没有什么奇特的需要)
然而,这仍然导致填充整个服务器与LAST_ACK …什么使这些最终消失是启用SO_LINGER (并使其强制closures套接字,没有超时)
connector.setSoLingerTime(0);