读取和解析网络上的大型文本文件的最佳方法是什么?

10

我有一个问题,需要从远程机器解析多个日志文件。 有几个问题: 1)文件可能正在使用中 2)这些文件可能相当大(100mb +) 3)每个条目可能有多行

为解决正在使用中的问题,我需要先进行复制。我目前直接从远程机器复制到本地机器,并在那里进行解析。这会导致问题2。由于文件相当大,在本地复制可能需要相当长时间。

为了提高解析速度,我想要将解析器变成多线程的,但这使得处理多行条目有些棘手。

主要的两个问题是: 1)如何加快文件传输(压缩?是否有必要在本地传输?可以用其他方式读取正在使用的文件吗?) 2)如何在将行分配给线程时处理多行条目?

更新:我没有在服务器上进行明显的解析,因为我希望对系统的性能影响尽可能小。

9个回答

2

如果您正在读取一个顺序文件,您想要在网络上传输时逐行读取它。 您需要一种能够流传输的传输方法。 您需要查看您的IO流技术以弄清楚这一点。

像此类大型IO操作不会因为多线程而受益,因为您可能可以在网络上传输时以与读取相同的速度处理项目。

您的另一个重要选择是将日志解析器放在服务器上,并下载结果。


如果直接通过网络复制100MB的文本文件需要x秒,而将文件压缩并发送给远程客户端,然后进行解压缩/读取只需要x/4秒,这是否值得?(注意,我实际上不知道压缩/发送/解压缩/读取需要多长时间) - midas06
你可以(而且应该)在网络上传输时使用一些压缩方式。就像我说的,检查一下你的IO流选项——有些人建议使用一些zip库。另一方面,如果你可以在远程端放置一个程序,那么就在那里进行处理吧! - Wesley Tarle

2
从性能的角度来看,更好的选择是在远程服务器上执行解析。除非出现异常情况,网络速度始终是瓶颈,因此限制发送到网络上的数据量将极大地提高性能。
这就是为什么许多数据库使用在服务器端运行的存储过程的原因之一。
通过使用多线程提高解析速度(如果有的话)将被网络传输的比较速度所淹没。
如果你致力于在解析文件之前传输它们,你可以考虑在文件传输时使用即时压缩的选项。 例如,有些sftp服务器可在传输过程中执行压缩。 在本地端,您可以使用类似于libcurl的东西来执行客户端传输,它还支持即时解压缩。

1

考虑到您已经在复制文件,最简单的方法是在复制之前压缩它,然后在复制完成后解压缩。压缩文本文件可以获得巨大的收益,因为zip算法通常对它们非常有效。此外,您现有的解析逻辑可以保持不变,而不必将其连接到远程网络文本阅读器上。

这种方法的缺点是您无法非常有效地获取逐行更新,逐行更新对于日志解析器非常重要。


我很想压缩它,但如果我的代码在本地机器上运行,那么在传输后它将被压缩,这就失去了意义。我想最终不得不编写一个仅用于压缩和发送的客户端。 - midas06

1

这大概取决于它有多“远”。在一个100Mb的局域网上,100MB大约需要8秒钟时间...升级到千兆网,你只需要1秒钟就能传输完毕。购买2张50美元的网卡和一台100美元的交换机,这是一个非常便宜的升级方案。

但是,假设它距离比这还要远,那么你应该可以使用只读模式来打开它(因为你复制的时候也是在读取它)。SMB/CIFS支持文件块读取,所以此时你应该是在流式传输文件(当然,你并没有说明你是通过什么方式访问的文件,我只是假设你是通过SMB)。

多线程无济于事,因为你最终还是会受限于磁盘或网络。


1

使用压缩进行传输。

如果您的解析速度真的很慢,并且您有多个处理器,您可以将解析工作分解,只需以聪明的方式执行--为哪些工作人员负责处理不完整的记录制定确定性算法。假设您可以确定一行是记录中间的一部分,例如,您可以将文件分成N/M个段,每个段负责M行;当其中一个作业确定其记录未完成时,它只需继续读取,直到达到记录的末尾。当其中一个作业确定正在读取没有开头的记录时,它应该跳过该记录。


1

如果你可以复制文件,那么你也可以读取它。所以一开始就没有必要复制它。

编辑:使用FileStream类可以更好地控制访问和共享模式。

new FileStream("logfile", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)

应该可以解决问题。


我不太同意。我的经验是,在尝试流式解析时,复制正在使用的内容会起作用,而不会出现问题。我的理论是,复制使用了一些其他的Windows API。 - midas06
你的理论是错误的,在我看来。Windows资源管理器使用与.NET(和FileStream)相同的API。你试过了吗? - VVS

0

给出的答案并不能满足我的需求,也许我的答案可以帮助其他人不认为这很复杂或多线程在这种情况下没有好处。也许它不会使传输更快,但根据您解析的复杂性,它可能会使解析/分析解析数据更快。

这真的取决于您解析的细节。您需要从日志文件中获取什么样的信息?这些信息是否像统计信息一样,还是依赖于多个日志消息?您有几个选项:

  • 同时解析多个文件可能是最容易的选择,您可以将文件作为上下文,并且可以为每个文件创建一个线程
  • 另一个选择就像之前提到的那样,使用压缩进行网络通信
  • 您还可以使用一个帮助程序将日志文件拆分为彼此相关的行,然后使用多个线程处理这些行块;这些行的解析应该相当简单和快速。
在这种情况下非常重要的是要测量您实际瓶颈所在的位置。如果您的瓶颈是网络,那么优化解析器也不会有太大的好处。如果您的解析器创建了许多相同类型的对象,则可以使用ObjectPool模式并使用多个线程创建对象。尝试在不分配太多新字符串的情况下处理输入。通常,解析器是通过使用大量的string.Split等编写的,这并不像它本应该那样快速。您可以通过检查即将到来的值而无需读取完整字符串并再次拆分它来导航Stream,而是直接填充完成解析后需要的对象。
优化几乎总是可能的,问题是您为多少输入获得多少输出以及您的场景有多关键。

0
我以前使用SharpZipLib压缩大文件以在互联网上传输之前。所以那是一个选择。
另一个想法是创建一个程序集,在远程机器上运行并在那里进行解析。您可以使用.NET remoting从本地计算机访问程序集。远程程序集需要是Windows服务或托管在IIS中。这将使您能够在同一台计算机上保留日志文件的副本,并且理论上处理它们所需的时间会更少。

0

我认为使用压缩(deflate / gzip)会有帮助


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接