2011-12-20 138 views
2

我有一個處理特定二進制協議的TCP服務器。一些請求包含大量要寫入文件的數據。該服務器使用NIO框架(netty),並具有邏輯來處理已分解爲多個幀的消息。保持文件句柄打開,或根據需要重新打開?

當個別幀進入時,如果該幀中的數據要寫入文件,則打開該文件並寫入數據。即使數據流還沒有完成,我期望有另一個數據幀被附加到同一個文件,但我現在關閉文件,直到我接收到下一個幀,此時我重新打開它並追加附加數據。

我選擇了這種方法,因爲它似乎是最安全的方法來避免左右打開文件句柄,並且通過一些錯誤不關閉它們,但是,我擔心這會對性能產生負面影響。是否更好(或在這種情況下是最佳實踐)使文件句柄保持打開狀態(以便保留對打開的FileOutputStream或Channel的引用)?打開文件句柄的數量是否存在資源限制問題?

+1

你在考慮什麼樣的音量(同時打開的文件)?你多長時間收到這些幀 - 或多或少的流/實時?或者延誤很長?遊戲中的限制在這方面往往達到數百(或數千)。並且打開/關閉文件所需的時間與幀之間的延遲時間可能是一個考慮因素。 – BRFennPocock 2011-12-20 23:03:45

+0

所有這些都是好點@BRPocock:對於這類問題中的大多數問題,需要考慮的是真實的工作量。 – 2011-12-20 23:15:03

+0

@BRPocock的音量有希望增加,所以我只是試圖找到最佳可擴展性的甜蜜點。幀是流/實時的(所討論的幀只是單個TCP數據包)。我試圖平衡我認爲最安全和最具擴展性(關閉文件)的內容,以及可能表現最佳(保持打開狀態)的內容。 – 2011-12-20 23:45:38

回答

1

保安回答:

  • 創建工廠類來處理:
    • 從池中返回一個開放的文件句柄,如果給定的文件仍然是開放的;
    • 關閉長子(最近使用最少)的文件句柄,如果沒有可用的 (某些可調的上限,對您的系統似乎是合理的)
    • 打完一個計時器上一個相對長的時間(30秒?一分鐘?)關閉沒有被使用了一段時間

喜歡的東西

/* initialize once */ 
    FilePool.setLimit (maxFiles); 

    /* called often */ 
    FilePool.getFile(ident); 
    FilePool.closeFile(handle); 

    /* protected/internal/… */ 
    boolean FilePool.reachedLimit(); 
    FilePool.closeLeastRecentlyUsed (number); 
    OnTimer → FilePool.closeIdleFiles (duration); 

當然句柄 ,這隻能是有道理的程度,文件的打開/關閉實際上是浪費任何時間。

如果您可以加載測試您現有的系統並嘗試使用兩種 機制來分析所花費的時間,當然,您可以更好地處理您的特定需求。

+0

謝謝,我認爲這是我會做的,只需稍作修改(或者只是命名不同)。我將使它成爲一個非靜態池對象,它返回一個基於File鍵的OutputStream(可能在匹配File對象時會遇到一些麻煩,我將忽略它)。然後,它可以返回緩存的Stream或新打開的流,以及其他池管理功能。 – 2011-12-21 00:33:58

3

建立TCP連接握手等需要10s到100s的時間,所以理想情況下你不會經常這樣做非常。看看你的解釋,我一定會保持連接的開放,因爲如果你不斷創建一個新的連接,你的有效帶寬將是真的有限。

請記住,無論如何,連接在關閉時都會關閉,並且如果對象離開定義的範圍,將在gc時間關閉。看看你是否不能把連接放在一個範圍內來利用它。

更新

剛纔看到你的意思是磁盤的註釋。儘管如此,同樣的理由也適用,儘管如此,因爲打開一個文件通常只需要幾毫秒 - 但可能仍然是10毫秒的數量級。

+2

這是他重新打開的磁盤文件,而不是TCP流。 – Alnitak 2011-12-20 23:04:14

+0

糟糕............ – 2011-12-20 23:14:08

3

恕我直言,我認爲最好讓文件句柄打開。

我已經straced多年來沒有結束通過套接字傳輸文件的程序,我從來沒有見過一個重複關閉並打開目標文件的程序。

此外,我可能會將傳入流寫入臨時文件名,並且只能在完成時將其重命名爲正確的文件名。

+0

那些程序服務器是處理多重連接還是單一連接/低容量?前@ – 2011-12-20 23:47:39

+0

@ increment1。 – Alnitak 2011-12-21 08:12:13