3

我有一个程序可以接收 1000 个主题的实时数据。它平均每秒接收 5000 条消息。每条消息由两个字符串、一个主题和一个消息值组成。我想将这些字符串与指示消息到达时间的时间戳一起保存。

我在“Core 2”硬件上使用 32 位 Windows XP 并使用 C# 进行编程。

我想将这些数据保存到 1000 个文件中——每个主题一个。我知道很多人会想告诉我将数据保存到数据库中,但我不想走那条路。

我考虑了几种方法:

1) 打开 1000 个文件,并在数据到达时写入每个文件。我对此有两个担忧。不知道能不能同时打开1000个文件,也不知道这对磁盘碎片有什么影响。

2) 写入一个文件,然后——不知何故——稍后处理它以产生 1000 个文件。

3) 将其全部保存在 RAM 中直到一天结束,然后一次写入一个文件。我认为如果我有足够的内存,这会很好用,尽管我可能需要移动到 64 位才能超过 2 GB 的限制。

你会如何处理这个问题?

4

11 回答 11

10

我无法想象你为什么不想为此使用数据库。这就是他们建造的目的。他们很擅长。

如果您不愿意走这条路,将它们存储在 RAM 中并每小时将它们转出到磁盘可能是一种选择,但请记住,如果您被电源线绊倒,您会丢失大量数据。

严重地。数据库它。

编辑:我应该补充一点,如果您准备好硬件,那么获得一个强大的、可复制的和完整的数据库支持的解决方案将花费您不到一天的时间。

在任何其他环境中执行此级别的事务保护将花费您数周的时间来设置和测试。

于 2009-05-29T13:34:00.413 回答
4

像 n8wrl 我也会推荐一个数据库。但是如果你真的不喜欢这个功能......

让我们找到另一个解决方案;-)

在最小的步骤中,我将采用两个线程。第一个是工人,接收所有数据并将每个对象(时间戳,两个字符串)放入队列中。

另一个线程将检查此队列(可能通过事件信息或通过检查 Count 属性)。该线程将使每个对象出列,打开特定文件,将其写下来,关闭文件并继续下一个事件。

使用第一种方法,我将开始并查看性能。如果它很糟糕,请进行一些计量,找出问题所在并尝试完成它(将打开的文件放入字典(名称,streamWriter)等)。

但另一方面,数据库对于这个问题来说非常好......一个表,四列(id,时间戳,主题,消息),一个额外的主题索引,准备好了。

于 2009-05-29T13:43:14.997 回答
2

我想进一步探讨一下为什么您不希望使用数据库——他们在这样的事情上做得很好!但是关于你的选择......

  1. 1000 个打开的文件句柄听起来不太好。忘记磁盘碎片 - O/S 资源会很糟糕。
  2. 这接近于 db-ish-ness!也听起来比它的价值更多的麻烦。
  3. RAM = 易失性。你整天都在积累数据,下午 5 点停电。

我将如何处理这个?D B!因为那时我可以查询索引,分析等等。

:)

于 2009-05-29T13:24:03.957 回答
2

首先计算带宽!5000 条消息/秒,每个 2kb = 10mb/秒。每分钟 - 600mb。好吧,您可以将其放入 RAM 中。然后每小时冲洗一次。

编辑:纠正错误。对不起这是我的错。

于 2009-05-29T13:30:22.073 回答
2

我会同意凯尔的观点,并选择像 PI 这样的包装产品。请注意 PI 非常昂贵。

如果您正在寻找自定义解决方案,我会选择 Stephen's 并进行一些修改。让一台服务器接收消息并将它们放入队列中。您不能使用文件将消息传递给其他进程,因为您将不断遇到锁定问题。可能使用 MSMQ(MS 消息队列)之类的东西,但我不确定它的速度。

我还建议使用数据库来存储您的数据。不过,您会希望将数据批量插入到数据库中,因为我认为您需要一些强大的硬件来允许 SQL 每秒执行 5000 个事务。您最好每隔说队列中累积的 10000 条消息进行一次批量插入。

数据大小:

平均消息 ~50 字节 -> 小日期时间 = 4 字节 + 主题(~10 个非 unicode 字符)= 10 字节 + 消息 -> 31 个字符(非 unicode)= 31 个字节。

50 * 5000 = 244kb/秒 -> 14mb/分钟 -> 858mb/小时

于 2009-05-29T13:42:14.437 回答
2

我同意 Oliver 的观点,但我建议进行修改:有 1000 个队列,每个主题/文件一个。一个线程接收消息,给它们加上时间戳,然后将它们放入适当的队列中。另一个只是在队列中旋转,看看它们是否有数据。如果是这样,它会读取消息,然后打开相应的文件并将消息写入其中。关闭文件后,它移动到下一个队列。这样做的一个优点是,如果无法跟上流量,您可以添加额外的文件写入线程。不过,我可能会首先尝试设置写入阈值(推迟处理队列,直到收到 N 条消息)来批量写入。这样你就不会因为只写一两条消息而陷入打开和关闭文件的困境。

于 2009-05-29T14:29:03.733 回答
2

也许您不想要数据库安装的开销?

在这种情况下,您可以尝试使用基于文件系统的数据库,例如 sqlite

SQLite 是一个实现自包含、无服务器、零配置、事务性 SQL 数据库引擎的软件库。SQLite 是世界上部署最广泛的 SQL 数据库引擎。SQLite 的源代码在公共领域。

于 2009-05-29T15:42:05.210 回答
1

我会制作 2 个单独的程序:一个接收传入的请求,格式化它们,然后将它们写到一个文件中,另一个从该文件中读取并写出请求。以这种方式做事可以让您最大限度地减少打开的文件句柄的数量,同时仍然实时处理传入的请求。如果您使第一个程序格式正确输出,那么将其处理为单个文件应该很简单。

于 2009-05-29T13:24:24.813 回答
1

我会考虑购买一个实时数据历史包。类似于 PI System 或 Wonderware Data Historian。我之前曾在文件和 MS SQL 数据库中尝试过这样的事情,但结果并不好(这是客户要求,我不建议这样做)。这些产品有 API,甚至还有包,您可以在其中像 SQL 一样查询数据。

它不允许我发布超链接,所以只需用谷歌搜索这 2 种产品,您就会找到有关它们的信息。

编辑

如果您确实像大多数人建议的那样使用数据库,我会为每个主题推荐一个用于历史数据的表,并考虑表分区、索引以及存储数据的时间。

例如,如果您要为每个主题存储一天的价值及其一个表,那么您正在查看每秒 5 次更新 x 一分钟内 60 秒 x 一小时内 60 分钟 x 24 小时 = 每天 432000 条记录。导出数据后,我想您将不得不清除第二天的数据,这将导致锁定,因此您必须将写入数据库排队。然后,如果您要重建索引,以便您可以对其进行任何查询,这将导致架构修改锁定和 MS SQL 企业版进行在线索引重建。如果您不每天清除数据,则必须确保有足够的磁盘空间来处理它。

基本上我所说的是权衡购买可靠产品与构建自己的产品的成本。

于 2009-05-29T13:31:31.307 回答
1

我会保留传入消息的缓冲区,并定期在单独的线程上按顺序写入 1000 个文件。

于 2009-05-29T13:32:13.253 回答
0

如果您不想使用数据库(我会,但假设您不这样做),我会将记录写入单个文件,追加操作尽可能快,并使用单独的进程/服务将文件拆分为 1000 个文件。您甚至可以每 X 分钟滚动一次文件,例如,每 15 分钟您启动一个新文件,而另一个进程开始将它们拆分为 1000 个单独的文件。

所有这一切确实引出了一个问题,即为什么不使用数据库,以及为什么需要 1000 个不同的文件——你可能有一个很好的理由——但话又说回来,也许你应该重新考虑你的策略并确保它在你之前是合理的推理沿着这条路走得很远。

于 2009-05-29T15:36:26.037 回答