ChatGPT解决这个技术问题 Extra ChatGPT

数十亿行的最佳数据存储

我需要能够为数十亿条记录(每年约 30 亿/月)存储少量数据(大约 50-75 字节)。

唯一的要求是快速插入和快速查找具有相同 GUID 的所有记录,并且能够从 .net 访问数据存储。

我是一名 SQL Server 专家,我认为 SQL Server 可以做到这一点,但随着所有关于 BigTable、CouchDB 和其他 nosql 解决方案的讨论,它听起来越来越像传统 RDBS 的替代品,可能是最好的,因为优化了分布式查询和扩展。我尝试了 cassandra 并且 .net 库当前无法编译或都可能发生变化(以及 cassandra 本身)。

我研究了许多可用的 nosql 数据存储,但找不到一个能满足我作为强大的生产就绪平台的需求的数据存储。

如果您必须存储 360 亿条小型扁平记录,以便可以从 .net 访问它们,您会选择什么?为什么?

是的,我的数字是正确的。目前,我们有这么多数据进入系统,但我们将其聚合并仅存储聚合计数,因此我们丢失了每条记录的数据并仅维护每小时的数据总和。由于业务需求,我们希望将每条记录保持原样,即每月 3Bil 行。
你提出了一些很好的问题。答案是:95% 的正常运行时间就足够了 - 数据已经延迟了一个可变数量,所以无论如何我都需要在事后同步它,所以短时间停机不会破坏交易。丢失刀片甚至数千个刀片并不是世界末日。不过,丢失一天的数据会很糟糕。一致性也不是那么重要。基本上在一天内插入 3000 万行之后,我需要获取所有具有相同 GUID 的行(可能是 20 行),并有理由确定我会将它们全部取回。
您是在每天/每小时计划的批处理作业中每天转储 3000 万行,还是一次一个恒定的流量?
数据从 FTP 站点到达......文件不断地进来,我有一个解析文件的过程,目前它生成聚合数据并将聚合值(可能 1000 行)作为事务插入。新进程需要从每个到达的文件中插入数十万行,可能使用批量插入是最有效的方法。
这听起来像是 SSIS 和 SQL Server 的 ETL 作业。他们确实以超过 2TB/小时的上传速度保持着 ETL 的世界纪录:blogs.msdn.com/sqlperf/archive/2008/02/27/etl-world-record.aspx

S
Seth Battin

存储约 3.5TB 的数据并以大约 1K/秒 24x7 的速度插入,并以未指定的速率查询,使用 SQL Server 是可能的,但还有更多问题:

您对此有什么可用性要求? 99.999% 的正常运行时间,还是 95% 就足够了?

你有什么可靠性要求?缺少一个插页会花费您 100 万美元吗?

你有什么可恢复性要求?如果您丢失了一天的数据,这有关系吗?

你有什么一致性要求?是否需要保证写入在下一次读取时可见?

如果您需要我强调的所有这些要求,那么您提出的负载将在关系系统、任何系统上花费数百万美元的硬件和许可,无论您尝试什么噱头(分片、分区等)。根据他们的定义,nosql 系统不能满足所有这些要求。

所以很明显你已经放宽了其中一些要求。在 Visual Guide to NoSQL Systems 有一个很好的可视化指南,它比较了基于“从 3 中选择 2”范例的 nosql 产品:

https://i.stack.imgur.com/3NAOs.png

OP评论更新后

使用 SQL Server,这将是直接的实现:

一个单一的表聚集(GUID,时间)键。是的,会变得碎片化,但是碎片化会影响预读,并且预读仅在显着范围扫描时才需要。由于您只查询特定的 GUID 和日期范围,因此碎片并不重要。是的,是宽键,因此非叶子页面的键密度会很差。是的,它会导致填充因子变差。是的,可能会发生页面拆分。尽管存在这些问题,但考虑到要求,仍然是最好的集群密钥选择。

按时间对表进行分区,以便您可以通过自动滑动窗口有效地删除过期记录。通过上个月的在线索引分区重建来增强这一点,以消除由 GUID 集群引入的不良填充因子和碎片。

启用页面压缩。由于首先按 GUID 聚集键组,一个 GUID 的所有记录将彼此相邻,为页面压缩提供了部署字典压缩的好机会。

您需要一个快速的 IO 路径来存储日志文件。您感兴趣的是高吞吐量,而不是日志的低延迟以跟上 1K 插入/秒,因此剥离是必须的。

分区和页面压缩都需要企业版 SQL Server,它们在标准版上不起作用,两者对于满足要求都非常重要。

作为旁注,如果记录来自前端 Web 服务器场,我会将 Express 放在每个 Web 服务器上,而不是在后端插入 INSERT,我会使用本地的 SEND 将信息发送到后端Express 上的连接/事务与 Web 服务器位于同一位置。这为解决方案提供了更好的可用性故事。

所以这就是我在 SQL Server 中的做法。好消息是您将面临的问题很容易理解并且解决方案是已知的。这并不一定意味着这比使用 Cassandra、BigTable 或 Dynamo 可以实现的更好。我会让一些在没有 sql-ish 的事情上更博学的人来论证他们的观点。

请注意,我从未提及编程模型、.Net 支持等。老实说,我认为它们在大型部署中无关紧要。它们在开发过程中产生了巨大的差异,但是一旦部署,开发速度有多快并不重要,如果 ORM 开销会影响性能:)


我热链接了 Nathan 的网站,但这不是 slashdot 头版;)
@RemusRusanu:查看 dba.se 迁移。只是为了准备你:-)和+1
从 Microsoft SQL Server 2016 开始,表分区不再需要企业版,因为表分区现在几乎在 SQL Server 2016 的所有版本中都可用。
A
Aaronaught

与流行的看法相反,NoSQL 与性能甚至可伸缩性无关。它主要是关于最小化所谓的对象-关系阻抗失配,但也是关于水平可伸缩性与 RDBMS 更典型的垂直可伸缩性。

对于快速插入和快速查找的简单要求,几乎任何数据库产品都可以。如果您想添加关系数据或连接,或者需要强制执行任何复杂的事务逻辑或约束,那么您需要一个关系数据库。没有 NoSQL 产品可以与之相比。

如果您需要无模式数据,则需要使用面向文档的数据库,例如 MongoDB 或 CouchDB。松散的模式是这些的主要吸引力;我个人喜欢 MongoDB,并在一些自定义报告系统中使用它。当数据需求不断变化时,我发现它非常有用。

另一个主要的 NoSQL 选项是分布式键值存储,例如 BigTable 或 Cassandra。如果您想在许多运行商品硬件的机器上扩展您的数据库,这些特别有用。显然,它们在服务器上也能正常工作,但没有利用高端硬件以及 SQL Server 或 Oracle 或其他专为垂直扩展而设计的数据库,而且显然,它们不是关系型的,不利于执行规范化或约束。此外,正如您所注意到的,.NET 支持充其量只是参差不齐。

所有关系数据库产品都支持有限排序的分区。它们不像 BigTable 或其他 DKVS 系统那样灵活,它们不能轻松地在数百个服务器之间进行分区,但听起来确实不像您正在寻找的那样。他们非常擅长处理数十亿的记录数,只要您正确索引和规范化数据,在强大的硬件(尤其是 SSD,如果您能负担得起)上运行数据库,并在 2 或 3 或 5 个物理磁盘上进行分区,如果必要的。

如果您满足上述标准,如果您在公司环境中工作并且有钱花在体面的硬件和数据库优化上,那么我现在会坚持使用 SQL Server。如果您想在低端 Amazon EC2 云计算硬件上运行它,您可能希望选择 Cassandra 或 Voldemort(假设您可以使用 .NET)。


A
Andrew

很少有人以数十亿行集大小工作,而且大多数时候我在堆栈溢出时看到这样的请求,数据远不及报告的大小。

360 亿,每月 30 亿,即每天大约 1 亿,每小时 416 万,每分钟约 70k 行,每秒 1.1k 行进入系统,持续 12 个月,假设没有停机时间。

这些数字并非不可能,我已经完成了更大的系统,但是您要仔细检查这确实是您的意思 - 很少有应用程序真正拥有这个数量。

在存储/检索方面,您没有提到的一个非常关键的方面是老化旧数据 - 删除不是免费的。

常规技术是分区,但是,基于 GUID 的查找/检索会导致性能不佳,假设您必须在整个 12 个月期间获取每个匹配值。您可以在 GUID 列上放置一个聚集索引,从而使您的关联数据聚集在一起以进行读/写,但是在这些数量和插入速度下,碎片将太高而无法支持,并且会掉到地上。

我还建议,如果这是一个具有 OLTP 类型响应速度的严肃应用程序,那么您将需要非常体面的硬件预算,这是通过一些近似的猜测,假设索引方面的开销很少,大约 2.7TB 的数据。

在 SQL Server 阵营中,您可能想要查看的唯一内容是新的并行数据仓库版本 (madison),它更多地用于分片数据并对其运行并行查询,以提供对大型数据集市的高速处理。


在生物信息学中,十亿行数据集并不少见。但它们经常以纯流媒体方式从平面文件中处理。
@Erik:对于流处理(即只需要检测某些条件,但不需要存储数据以供以后查询),StreamInsight 之类的东西比任何数据库都好microsoft.com/sqlserver/2008/en/us/r2-complex-event.aspx
G
Goran B.

“我需要能够为数十亿条记录(每年约 30 亿/月)存储少量数据(大约 50-75 字节)。

唯一的要求是快速插入和快速查找具有相同 GUID 的所有记录,并且能够从 .net 访问数据存储。”

我可以根据经验告诉你,这在 SQL Server 中是可能的,因为我在 2009 年初就已经做到了……而且它至今仍在运行,而且速度非常快。

该表被划分为 256 个分区,请记住这是 2005 SQL 版本......我们完全按照您的意思进行操作,即按 GUID 存储信息位并通过 GUID 快速检索。

当我离开时,我们有大约 2-30 亿条记录,尽管数据保留策略即将实例化,但数据检索仍然非常好(如果通过 UI,则为 1-2 秒,或者如果在 RDBMS 上则更少)。

所以,长话短说,我从 GUID 字符串中取出第 8 个字符(即在中间的某个地方),然后 SHA1 对其进行哈希处理并转换为小整数(0-255)并存储在适当的分区中,并在获取时使用相同的函数调用数据回来。

如果您需要更多信息,请联系我...


E
Eponymous

以下文章讨论了在 Microsoft SQL 中导入和使用 16 十亿 行表。 https://www.itprotoday.com/big-data/adventures-big-data-how-import-16-billion-rows-single-table

来自文章:

以下是我的经验中提炼出来的一些技巧: 具有已定义聚集索引的表中的数据越多,将未排序的记录导入其中的速度就越慢。在某些时候,它变得太慢而无法实用。如果要将表格导出为尽可能小的文件,请将其设为本机格式。这最适用于主要包含数字列的表,因为它们在二进制字段中比字符数据更紧凑地表示。如果您的所有数据都是字母数字的,则以本机格式导出它不会获得太多收益。不允许数字字段中的空值可以进一步压缩数据。如果您允许一个字段可以为空,则该字段的二进制表示将包含一个 1 字节的前缀,指示后面有多少字节的数据。您不能将 BCP 用于超过 2,147,483,647 条记录,因为 BCP 计数器变量是一个 4 字节整数。我无法在 MSDN 或 Internet 上找到对此的任何参考。如果您的表包含超过 2,147,483,647 条记录,则您必须将其分块导出或编写自己的导出例程。在预填充表上定义聚集索引会占用大量磁盘空间。在我的测试中,我的日志在完成之前爆炸到原始表大小的 10 倍。使用 BULK INSERT 语句导入大量记录时,包括 BATCHSIZE 参数并指定一次提交的记录数。如果不包含此参数,您的整个文件将作为单个事务导入,这需要大量日志空间。将数据放入具有聚集索引的表中的最快方法是首先对数据进行预排序。然后,您可以使用带有 ORDER 参数的 BULK INSERT 语句导入它。


我编辑了链接。但是 Internet 档案馆未能导入新链接,因此当它下次断开时,它可能是永久的。
J
Josef Richberg

有一个不寻常的事实似乎被忽视了。

“基本上在一天内插入 3000 万行之后,我需要获取所有具有相同 GUID 的行(可能是 20 行),并有理由确定我会将它们全部取回”

只需要 20 列,GUID 上的非聚集索引就可以正常工作。您可以聚集在另一列上以实现跨分区的数据分散。

我有一个关于数据插入的问题:它是如何插入的?

这是按特定时间表(每分钟、每小时等)进行的批量插入吗?

这些数据是从什么来源(平面文件、OLTP 等)提取的?

我认为需要回答这些问题以帮助理解等式的一方面。


M
Martin Taleski

Amazon Redshift 是一项很棒的服务。当问题最初在 2010 年发布时它不可用,但它现在是 2017 年的主要参与者。它是一个基于列的数据库,从 Postgres 派生,因此标准 SQL 和 Postgres 连接器库可以使用它。

它最适合用于报告目的,尤其是聚合。来自单个表的数据存储在亚马逊云中的不同服务器上,由定义的表 distkeys 分布,因此您依赖分布式 CPU 能力。

所以 SELECT 尤其是聚合的 SELECT 非常快。最好使用 Amazon S3 csv 文件中的 COPY 命令加载大数据。缺点是 DELETE 和 UPDATE 比平常慢,但这就是为什么 Redshift 主要不是跨国数据库,而是更多的数据仓库平台。


0
0xDEADC0DE

您可以尝试使用 Cassandra 或 HBase,但您需要了解如何根据您的用例设计列族。 Cassandra 提供了自己的查询语言,但您需要使用 HBase 的 Java API 来直接访问数据。如果您需要使用 Hbase,那么我建议使用 Map-R 中的 Apache Drill 查询数据,这是一个开源项目。 Drill 的查询语言是 SQL-Compliant 的(drill 中的关键字与 SQL 中的含义相同)。


F
Francisco

每年有这么多记录,你最终会用完空间。为什么不像 xfs 这样支持 2^64 个文件并使用更小的盒子的文件系统存储。无论人们想要获得多么花哨的东西,或者最终会花多少钱来获得一个带有任何数据库 SQL NoSQL 的系统 ..无论这些记录通常是由电力公司和气象站/供应商(如环境部)控制较小的全国各地的车站。如果您正在执行诸如存储压力..温度..风速..湿度等之类的操作...并且 guid 是位置..您仍然可以按年/月/日/小时划分数据。假设您在每个硬盘驱动器上存储 4 年的数据。然后,您可以让它在带有镜像的较小 Nas 上运行,它还可以提供更好的读取速度并具有多个挂载点……基于它创建的年份。您可以简单地为搜索创建一个 Web 界面因此转储 location1/2001/06/01//temperature 和 location1/2002/06/01//temperature 只会转储夏季第一天的每小时温度内容在这 2年(24 小时 * 2)48 个小文件与搜索具有数十亿条记录并可能花费数百万的数据库。简单的看待事物的方式.. 世界上有 15 亿个网站,天知道每个网站有多少页 如果像谷歌这样的公司不得不为每 30 亿次搜索花费数百万来支付超级计算机的费用,他们就会破产。相反,他们有电费……几百万台垃圾电脑。和咖啡因索引......未来证明......继续添加更多。是的,在 SQL 上运行索引是有意义的,然后是伟大的构建超级计算机来处理具有固定事物(如天气……统计数据等)的蹩脚任务,因此技术人员可以吹嘘他们的系统在 x 秒内处理 xtb……可能会浪费金钱花费在其他地方......也许通过运行 10 个 Nas 服务器之类的东西不会很快达到数百万的电费账单。


T
Thomas Kjørnes

将记录存储在普通二进制文件中,每个 GUID 一个文件,不会比这更快。


你真的希望它表现良好吗?
是的,在文件系统上创建数十亿个文件对某些文件系统来说可能是毁灭性的。我犯了这样的错误,但只有 100 万个,而且我几乎让系统崩溃,试图打开其中一个文件夹的外壳。此外,除非您基于 guid 进行查找,否则查询机制应该如何工作?
在不知道预期有多少唯一 GUID 的情况下,很难猜测这将如何执行 :) 但是没有比仅写入普通文件更简单的了。快速插入以及通过 GUID 查找是唯一的要求。
它可以工作,但您必须限制每个文件夹的文件数量。您必须为每 n 个文件生成一个新文件夹。您可以使用 guid 的子字符串作为文件夹名称。
是的,许多文件系统的 inode 数量是有限制的,我记得在 redhat 默认文件系统上达到了这个限制……限制大约是 1,000,000 个文件左右。
T
Theo

您可以使用 MongoDB 并使用 guid 作为分片键,这意味着您可以将数据分布在多台机器上,但您要选择的数据仅在一台机器上,因为您通过分片键进行选择。

MongoDb 中的分片尚未准备好生产。