我应该为大量时间序列数据使用什么类型的数据存储?

har*_*arm 6 database-design database-recommendation

想象一个项目,它需要能够每秒处理 50,000+(微小整数)写入。数据一旦插入就不会改变。数据是对特定时间的测量。不需要亚秒分辨率(同一设备的两次测量可以相隔一秒)。

我们愿意购买/租用更多硬件而不是更昂贵的硬件(没有花哨的 RAID 等)。

数据按集合(每个设备)排序,数百个。因此应该显示/绘制。设备之间没有关系,但我们确实希望将它们分组(例如,显示 10 个图表)。

唯一的另一个要求是数据存储是开源的,基于 *nix 并且有合理的(社区)支持。

你会使用什么样的数据存储?

Con*_*lls 5

解决问题的“数据记录”方法

对于每秒 50,000 次插入的任何操作,您将需要批量插入。如果您必须在廉价硬件上运行它,那么您需要考虑 I/O 的效率。

如果您假设:

  • 直到第二个延迟是不必要的(即批量写入是可以接受的)

  • 除了按设备显示图表外,您不需要在应用程序中进行分析。

  • 任何进一步的分析要求都可以通过将数据批量传输到外部系统来满足

  • 将设备添加到系统时,一些管理开销是可以接受的(即它们必须注册)。

  • 每秒轮询一次的读取是可接受的 - 传入的项目可以每秒进行批处理和记录,如果给定设备在该时间段内未生成数据,则记录空值。

然后,您可以每秒存储一行,并将所有设备非标准化为读数数组。应用程序按设备维护该数组的偏移量注册表。当您添加更多设备时,BLOB 就会扩展。

这将您的问题转变为每秒存储一个 50K 左右的 BLOB 并按时间索引,这几乎可以通过任何支持 BLOB 的 DBMS 平台来完成。您甚至可以使用键值对系统,例如 Berkely DB。

每秒 50K 相当于每小时 180MB,每天 4.3GB,每年大约 1.5TB。即使使用相当普通的硬件,这也应该可以管理。根据您需要归档的数量,您可以定期清除历史数据。不过,您将需要支持分区表的东西才能有效地完成此操作。

取回数据

这种方法的一个缺点是您必须读取整个数据集才能查询任何给定设备的统计信息,这意味着一天要扫描 4GB 的数据。如果您需要支持大量用户临时查询设备,您将需要找到一种方法来通过快速查询功能来补充该存储。一些可能性是:

  • 一小时的数据在内存中大约为180MB。缓存几个小时的滚动周期 - 在您的应用程序中,或者在可以按小时存档的快速存储(可能是 SSD)的前导分区中。

    如果显示图表的应用程序滚动查询此结构(即仅获取最新数据),则此结构可以按时键入并且仍然支持大量查询工作负载。

    您可能需要对平台的 BLOB 读取器性能进行基准测试,以判断是否需要在中间层内构建额外的缓存,尽管您几乎肯定需要某种描述的中间层服务器应用程序,以避免将整个 BLOB 记录发送到客户端。

  • 如果您只希望在任何给定时间监控一小部分传感器,那么您可以在每个传感器的基础上运行缓存,缓存在该传感器最后一次读取后存活一段时间(例如 10 分钟) 。主缓存会将值推送到每个传感器缓存中,直到每个传感器缓存过期。每个传感器的缓存可以相当有效地实现为 1-2 小时(或任何看起来合适的时间段)传感器读数的环形缓冲区,以及开始和结束时间段的补充数据。然后,时间段应解析为环形缓冲区内的偏移量。在这种情况下,每个传感器的内存开销相当于几个字节的标头信息。

  • 计算每分钟、10 分钟、小时或适当时间段的平均读数汇总,并将其存储在补充表中。可以使用聚合来绘制较长时间段内的数据图。

  • 获取聚合值并将其转变成补充数据集市中的维度结构(即具有时间和传感器 ID 维度)。这可以(例如)每晚进行。对历史数据的临时查询可以来自数据集市。

这些方法的某种组合将允许快速访问具有相当数量的读取流量的近实时数据。即使您必须使用应用程序缓存此内容并编写一些手工构建的内容来执行此操作。

行政管理费用

传感器必须在系统中注册并给出一个 ID(本质上该 ID 是或映射到 BLOB 中的数组索引)。由于 BLOB 是不透明的,数据库不需要关心列。能够有效处理 BLOB 的 KVP 存储可能就足够了。

传感器可以在系统中注册,然后系统将开始记录数据。您可能需要显式记录传感器连接的开始/结束日期,并维护将传感器 ID 链接到阵列内偏移量的元数据。您将需要回收数组槽,因为它是静态结构。任何中间层缓存也必须意识到这一点。

消息队列

您可能希望考虑使用事务性队列管理器(例如 RabbitMQ)的异步架构来管理常规写入的读取工作负载峰值。日志记录进程和查询前置进程将收集要在批处理队列中处理的请求。这将消除系统负载的峰值。如果您预计会有大量的临时查询工作负载,您可能希望研究一下这一点。

优点和缺点 - 总结

这种结构经过优化,可以最大限度地减少存储空间需求,从而最大限度地减少系统的 I/O 开销,并允许其在相对便宜的硬件上运行 - 特别是具有相对便宜的存储子系统的硬件。原则上,普通 PC 应该能够处理来自传感器的写入工作负载,尽管您可能需要更快的磁盘硬件或 SSD 来处理任何大量的查询工作负载。

然而,这种架构需要相当多的管道来获取数据。传感器 ID 无法在数据库中建立索引,因为它只是传感器读数数组的偏移量。1 这意味着必须读取整个周期的数据才能获得单个传感器读数。因此,查询功能可能需要中间层中相当复杂的缓存功能才能获得良好的性能,因此这种方法是以一些开发开销为代价的。

1这严重违反了第一范式,尽管关系存储对于此应用程序来说可能不是必需的,甚至不是可取的。