2014-09-24 33 views
3

我有一个小型的Web应用程序,它打开一个TCP套接字连接,发出一个命令,读取响应,然后关闭每个请求到特定REST端点的连接。太多的TIME_WAIT连接,得到“无法分配请求的地址”

我已经开始负载测试使用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中运行。

+1

你需要SO_REUSE_ADDR吗?在这里看到答案:http://stackoverflow.com/questions/14388706/socket-options-so-reuseaddr-and-so-reuseport-how-do-they-differ-do-they-mean-t – 2014-09-25 07:20:36

+1

也http: //stackoverflow.com/questions/16014627/tcp-connection-cant-be-established-when-there-is-a-tcp-connection-with-state-t?rq = 1和几百万:)其他相关的问题 - 请参阅RHS列表 - > – 2014-09-25 07:22:11

回答

0

连接池将为您解决这个问题。

+0

嗯,它不是HTTP - 虽然我需要连接到端口2222上运行的服务,该服务使用专有协议,而不是HTTP :(我已经通过删除200和404状态并将其设置回专有协议响应来清除了这种误解。 – jcm 2014-09-25 01:13:09

+1

在人们经常与RESTful HTTP/Web服务关联的问题中,您还提到了'REST'。不必如此,就像在你的例子中一样 – monex0 2014-10-04 02:21:48

+0

@jcm我没有透露任何有关HTTP的知识,我不知道是什么让你认为HTTP是世界上唯一可以使用连接池的协议。 – EJP 2016-04-28 20:22:52

5

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

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

另外,如果你有root权限,也有一些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)了解更多信息。

+0

嗨,我没有控制服务器,并且没有'文件结束'的情况,这会导致服务器关闭它的连接。 – jcm 2014-10-01 12:31:05

+0

@ cm22你可以尝试发送一些inva盖上数据以使服务器关闭其连接。我还为答案添加了一些sysctl选项,但您需要root访问权限才能更改它们。 – abacabadabacaba 2014-10-01 12:55:51

相关问题