2011-12-20 139 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