nginx + Jetty - 数千个连接卡在 LAST_ACK 中

nginx + Jetty - 数千个连接卡在 LAST_ACK 中

我有一台装有 jail 的 FreeBSD 机器——具体来说是两个,一个运行 nginx,另一个运行通过 Jetty 接受请求的 Java 程序(嵌入模式)

Jetty 每秒持续接收 500 个以上的请求,最近出现了一个问题,我经常会遇到6万nginx 与 jetty 之间处于 LAST_ACK 状态的连接。

所有连接的分布(包括一些其他服务,特别是 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 -> jetty 连接数分配

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

我希望每个请求都完全关闭连接。客户端请求间隔约 10 分钟,因此必须关闭连接。

有些联系,

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..
  • 在 Jetty 端,我将其设置maxIdleTime为 2000——在此之前,所有连接都已建立ESTABLISHED,但现在LAST_ACK
  • 在 Jetty 端我已经设置了Connection: close(即response.setHeader(HttpHeaders.CONNECTION, HttpHeaderValues.CLOSE);
  • Jetty 从来不会报告很多开放的连接 —— 总是很少。
  • PF/IPFW 目前未被使用
  • nginx -reset_timedout_connection已开启

我不知道如何让 nginx 或 jetty 强制关闭连接,这是否只是 Jetty 中需要修复的问题,以便它在请求完成后完全关闭套接字?

提前致谢

编辑:忘记了 nginx 代理设置配置-

    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;

编辑2:强制 Jetty 通过 关闭连接request.getConnection().getEndPoint().close()不会产生任何效果 —— 很明显连接正在关闭(因为它在 中LAST_ACK),但为什么它没有通过呢? Nginx 是否因为某种原因保持与后端的连接打开?

答案1

好吧,我终于能够说服 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

我已经关闭了整个连接并且EndPoint(调用close()关闭EndPoint底层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(并使其立即强制关闭套接字,没有超时)

connector.setSoLingerTime(0);

相关内容