2014-09-24 54 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

相關問題