一个巨大的数据存储问题

4
我开始设计一个新的应用程序,将被大约50,000台设备使用。每个设备每天会生成大约1,440个注册表,这意味着每天将存储超过7200万个注册表。这些注册表每分钟都在不断地产生,我必须能够通过Java应用程序(J2EE)查询这些数据。因此,需要快速编写、快速读取并建立索引以允许报告生成。设备仅插入数据,而J2EE应用程序需要偶尔读取数据。
现在我正在寻找软件替代方案来支持这种操作。
将这些数据放在单个表中会导致灾难性情况的发生,因为由于一年内存储的数据量太大,我将无法使用这些数据。
我正在使用Postgres,数据库分区似乎不是一个答案,因为我需要按月份或更精细的方法进行表分区,例如按天计算。
我考虑使用SQLite的解决方案。每个设备将拥有自己的SQLite数据库,这样信息就足够细粒度化,便于维护和快速插入和查询。
您认为如何?

1
问题太泛泛了。完全取决于数据/查询等的类型。 - Aryabhatta
更具体地说,这些数据是插入数据库的GPS坐标。查询将是报告,例如:“显示2010年7月设备1234在哪里”。 - gmuller
你已经在数据库中安装了PostGIS吗? - Frank Heikens
我已经安装了PostGIS,为什么呢? - gmuller
5个回答

4
  1. 仅记录设备位置的变化 - 大部分时间内,任何设备都不会移动 - 汽车将被停放,人将坐着或睡觉,手机将在不动的人身上或充电等等 - 这将使您需要存储的数据量大幅减少。

  2. 即使没有实现第一个建议,您每年最多也只会生成约1TB的数据,这并不是很大的数据量。这意味着大约30MB/s的数据,单个SATA驱动器可以处理。

  3. 即使是一个简单的未分区的Postgres数据库,只要硬件不太大,也应该能够处理这个数据量。唯一的问题可能是当您需要查询或备份时,可以使用Hot Standby镜像,使用流复制 - 这是即将发布的PostgreSQL 9.0中的新功能。只需针对/备份镜像进行查询 - 如果它繁忙,它会暂时自动排队更改,并稍后赶上。

  4. 当您确实需要分区时,请例如按照device_id模256进行分区,而不是按时间。这样,您的写入就会分布在每个分区上。如果按时间分区,任何时候只有一个分区很忙,其他分区则处于空闲状态。Postgres支持此种方式的分区非常好。然后,您还可以使用tablespaces将负载分散到几个存储设备上,这也在Postgres中得到了良好的支持。


分区设备ID是个好建议。但随着时间的推移,分区会变得太大,你不觉得吗? - gmuller
一致性哈希比设备ID模256更好。请参见http://michaelnielsen.org/blog/consistent-hashing/。 - TTT

2
时间间隔分区是一个非常好的解决方案,即使你不得不自己实现。与维护50000个SQLite数据库连接相比,即使每天有数百万次插入操作,使用单个Postgres数据库也更加实际。
根据您需要针对数据集运行的查询类型,您可能需要将远程设备分区到多个服务器上,然后查询这些服务器以将聚合数据写入后端服务器。
高容量表格的关键是:最小化编写的数据量和必须更新的索引数量;不要执行UPDATE或DELETE操作,仅进行INSERT操作(并且对于将来要删除的数据使用分区——DROP TABLE比DELETE FROM TABLE快得多!)。
随着您开始挑战数据库引擎,表格设计和查询优化变得非常特定于数据库。考虑聘请Postgres专家至少咨询您的设计。

2
也许现在是使用可以在多台机器上分片的数据库的时候了?Cassandra?Redis?不要局限于关系型数据库。

1

数据库分区管理可以自动化;基于时间的数据分区是应对这种问题的标准方法,我不确定为什么不能在PostgreSQL中执行此操作。

假设每天有大约72m行 - 假设一个设备ID、日期戳和两个坐标浮点值,每行将占用(比如)16-20字节加上一些较小的页面元数据开销。一个简单的容量规划建议每天约1-1.5GB的数据,或者每年400-500GB,如果需要还要包括索引。

如果您可以接受定期刷新数据(即不完全实时),则可以构建一个单独的报告表,并使用ETL过程定期更新该表。如果该表存储在单独的物理磁盘卷上,则可以查询该表而不会显着影响交易数据的性能。

一个单独的用于历史数据的报告数据库还可以通过删除较旧的分区来修整您的运营表,这可能有助于提高应用程序性能。您还可以为报告表创建索引和摘要表以优化报告性能。
如果您需要低延迟的数据(即针对最新数据进行报告),也可能可以构建一个视图,在该视图中,前导分区从运营系统报告,而历史数据从数据集市报告。这将使批量查询在针对此类查询进行了优化的报告表上进行,同时可以直接从运营系统中读取相对较小的当前数据量。
大多数低延迟报告系统使用此方法的某些变体 - 前导分区可以由实时进程(例如触发器)更新,并包含相对较少的数据,因此可以快速查询,但不包含减慢更新的负担。余下的历史数据可以为报告大量建立索引。按日期进行分区意味着系统将自动开始填充下一个分区,并且定期处理可以移动、重新索引或执行任何需要针对历史数据进行优化的操作。
注意:如果您的预算足以购买PostgreSQL,而不是Oracle,则可能会发现直接连接存储比SAN更快,除非您想在SAN硬件上花费大量金钱。

0

你提出的问题有点模糊。我认为你面临的不是数据库软件的选择,而是架构问题。

以下是一些考虑因素:

  • 设备的可靠性如何,它们与查询软件的连接情况如何?
  • 您需要存储的容错率有多高?
  • 这些设备处理查询需要多少额外的处理能力?

基本上,你的空间分区的想法是一个好主意。如果必要的话,这并不排除时间分区的可能性。你是在postgres还是sqlite中实现这个想法取决于其他因素,比如处理能力和可用库。

另一个考虑因素是你的设备是否足够可靠和强大来处理你的查询。否则,你可能需要使用集中式数据库集群,仍然可以并行查询。


设备和J2EE是分离的实体。设备只写入数据,而J2EE应用程序偶尔读取数据。
  • 设备将通过数据库连接到查询软件。
  • 数据必须具有故障安全性,因此丢失数据是不好的。
  • 设备不会查询数据,它们只生成数据。
- gmuller

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