TIME_WAIT连接太多,得到“无法分配请求的地址”

时间:2014-09-24 14:14:00

标签: linux scala sockets tcp scalability

我有一个小型Web应用程序,它打开TCP套接字连接,发出命令,读取响应,然后关闭每个请求到特定REST端点的连接。

我已经开始使用Apache JMeter对端点进行负载测试,并注意到在运行一段时间后,我开始看到“无法分配请求的地址”之类的错误,打开此连接的代码是:

def lookup(word: String): Option[String] = {
 try {
  val socket = new Socket(InetAddress.getByName("localhost"), 2222)
  val out = new PrintStream(socket.getOutputStream)
  val reader = new BufferedReader(new InputStreamReader(socket.getInputStream, "utf8"))
  out.println("lookup " + word)
  out.flush()

  var curr = reader.readLine()
  var response = ""
  while (!curr.contains("SUCC") && !curr.contains("FAIL")) {
    response += curr + "\n"
    curr = reader.readLine()
  }
  socket.close()
  curr match {
    case code if code.contains(SUCCESS_CODE) => {
      Some(response)
    }
    case _ => None
  }
 }
 catch {
   case e: Exception => println("Got an exception "+ e.getMessage); None
 }
}

当我运行netstat时,我也看到了很多以下的TIME_WAIT连接状态,这对我来说意味着我在短暂的空间中没有端口。

tcp6       0      0 localhost:54646         localhost:2222          TIME_WAIT  
tcp6       0      0 localhost:54638         localhost:2222          TIME_WAIT  
tcp6       0      0 localhost:54790         localhost:2222          TIME_WAIT  
tcp6       0      0 localhost:54882         localhost:2222          TIME_WAIT 

我想知道这个问题的最佳解决方案是什么。我目前的想法是创建一个连接池,在端口2222上运行的此服务的连接可以被不同的HTTP请求重用,而不是每次都创建新的请求。这是解决问题并使应用程序扩展得更好的明智方法吗?这似乎是一个很大的开销,并且肯定会使我的应用程序更加复杂。

是否还有其他解决方案可以帮助我们应用此应用程序并克服我未见到的此端口问题?我的Web应用程序在Ubuntu linux VM中运行。

2 个答案:

答案 0 :(得分:6)

是的,创建连接池是一个很好的解决方案。但是,更简单的解决方案是让服务器关闭连接,而不是客户端。在这种情况下,服务器的套接字而不是客户端将最终处于TIME_WAIT状态,因此客户端不会耗尽端口。在服务器端,处于TIME_WAIT状态的连接不会使服务器耗尽端口,因为它们都使用相同的本地端口。

要确保服务器已关闭连接,您需要从套接字(在客户端上)读取,直到达到文件结束条件。此时,可以安全地关闭客户端上的套接字,因为服务器已经关闭了它。当然,您需要确保服务器关闭套接字,而不是等待新请求。

或者,如果您具有超级用户权限,则可以调整一些sysctl个选项:

  • net.ipv4.ip_local_port_range - 短暂的端口范围。增加它以使更多端口可用于传出连接。
  • net.ipv4.tcp_tw_recycle - 在TIME_WAIT状态下更快地回收连接。
  • net.ipv4.tcp_tw_reuse - 在TIME_WAIT状态下启用连接重用。不推荐。

有关详细信息,请参见手册页ip(7)tcp(7)

答案 1 :(得分:0)

连接池将为您解决此问题。