Erick Ramirez Asked: 2022-07-19 21:43:38 +0800 CST2022-07-19 21:43:38 +0800 CST 2022-07-19 21:43:38 +0800 CST 为什么 COUNT() 在 Cassandra 中不好? 772 这是刚接触分布式系统和高速、互联网规模环境的用户经常提出的问题。 COUNT()为什么在 Cassandra中对表中的分区进行计数不是一个好主意? cassandra 1 个回答 Voted Best Answer Erick Ramirez 2022-07-19T21:43:38+08:002022-07-19T21:43:38+08:00 介绍 我们经常遇到的问题之一是用户试图COUNT()在 Cassandra 中执行 a。通常,他们问的问题是“为什么会超时?” . 为什么确实如此? 作为关系数据库 (RDBMS) 的 DBA,执行表中的记录计数是您经常做的事情。这个问题的答案很简单,但它需要了解分布式架构的基础知识以及 Cassandra 的工作原理。让我们开始... 一个明星诞生了 Cassandra 使用日志结构的合并树来存储数据。简而言之,这意味着写入(INSERT和UPDATE语句DELETE)以某个时间间隔以像日志文件一样的顺序方式写入磁盘。这些称为SSTables 的文件是不可变的,这意味着它们一旦写入磁盘就不会更改,从而避免了读写速度非常快的读写操作。 考虑一个具有多列的简单表。在一天的正常过程中,将一个新分区插入到表中,其中包含 2 列的值。在某些时候,memtable 被刷新到写入为 SSTable 的磁盘。这个新插入的分区相当于一条记录。 一段时间后,同一分区中的另一列被插入到表中。这也算一项记录。几秒钟后,插入同一分区中的另一列,然后将 memtable 刷新到磁盘。由于同一分区的这两个片段同时在 memtable 中,因此它们在写入 SSTable 之前合并在一起,因此仅“计数”为一条记录。 当天晚些时候,同一分区的现有列之一将更新为新值。由于Cassandra 在写入磁盘之前不执行读取,因此Cassandra 不知道该分区的列是否已存在于其他 SSTable 中,因此更新只是作为另一条记录插入,最终将其插入另一个 SSTable(是的,Cassandra 中的更新只是在引擎盖下插入又名“upserts”)。 在这个例子中,3 条记录存在于 3 个不同的 SSTable 中,它们实际上是同一个分区的片段。但是 Cassandra 在读取该分区之前并不知道这 3 条记录是针对同一个分区的。实际上,这就是unbounded COUNT()所做的: 它读取所有分区 跨所有 SSTables(和 memtables) 跨越 Cassandra 环中的所有节点 为了得出结果。 在小集群中的小表上,确保运行计数查询没什么大不了的。但是想象一下,如果在一个有几十个(如果不是几百个)节点的集群上,每个节点有数百个价值超过 500GB 的 SSTable。看看这样一个无辜的查询是如何变得如此昂贵的?它必须在您的集群中执行全表扫描,这就是您的查询在有机会完成之前会超时的原因——它无法扩展。 满是星星的星系 更复杂的是,考虑到在计数过程中,分区不断被创建和更新——毕竟这是大数据,你使用 Cassandra 是因为你有规模问题。即使你很幸运得到了结果,这个计数是否有效?你还不如数星星。因为当你在足够的时间内数完夜空中一半的星星时,你的计数很可能已经过时了,因为宇宙不是静止的——新星诞生而老星一直在死去。同样,您的表也不是静态的——创建新分区,更新现有分区,甚至删除一些分区。 “我可以用柜台吗?” , 你问。也许。如果您的用例是您只写入一次分区并且永远不会再次覆盖它。如果您的用例涉及覆盖,那么您无法确定它是否是第一次写入,因此您的计数器变得无用。您可能会想出某种算法并以某种方式存储计数,但很可能,您的“计数器”解决方案不会扩展,因为它可能涉及(a)先读后写,(b)额外写入每个操作,或(c)两者。 如果你必须 你也可以从中得到一个估计,nodetool tablestats但这正是你会得到的——估计。这是因为它遇到了同样的问题。当 Cassandra 将 memtable 刷新到磁盘时,它知道该 SSTable 中有多少键并相应地更新表统计信息 [1]。当我们在这里时,请注意删除也是在引擎盖下的插入,即一个墓碑被插入到表中,因此它被计入tablestats. 只有在墓碑被压实之后才会减少gc_grace_seconds。 最后,如果您真的必须进行计数,请使用 DSE Analytics 或 DSE Search 进行计数,但这些是针对另一篇博客文章的。等我数完星星后,我会解决它,也许... [1]我过度简化了表格统计更新所发生的事情,以使其易于为目标受众消化。实际上使用了诸如HyperLogLog之类的算法来提高聚合值的准确性。 更新 在我第一次发表这篇博文 2 年后,出现了DataStax Bulk Loader(又名DSBulk)。它是一种从 Apache Cassandra 有效加载和卸载数据的工具,尽管这不是它的能力范围。 DSBulk 有一个很好的功能,可以以分布式方式对大型表中的数据进行计数。它是加载或卸载 CSV 或 JSON 格式数据的推荐工具。它的执行速度比 cqlshCOPY命令快 4 倍。 是的,DataStax 让开源 Apache Cassandra 用户可以免费使用它。有关详细信息,请参阅使用 DSBulk 对表中的数据进行计数。干杯!
介绍
我们经常遇到的问题之一是用户试图
COUNT()
在 Cassandra 中执行 a。通常,他们问的问题是“为什么会超时?” . 为什么确实如此?作为关系数据库 (RDBMS) 的 DBA,执行表中的记录计数是您经常做的事情。这个问题的答案很简单,但它需要了解分布式架构的基础知识以及 Cassandra 的工作原理。让我们开始...
一个明星诞生了
Cassandra 使用日志结构的合并树来存储数据。简而言之,这意味着写入(
INSERT
和UPDATE
语句DELETE
)以某个时间间隔以像日志文件一样的顺序方式写入磁盘。这些称为SSTables 的文件是不可变的,这意味着它们一旦写入磁盘就不会更改,从而避免了读写速度非常快的读写操作。考虑一个具有多列的简单表。在一天的正常过程中,将一个新分区插入到表中,其中包含 2 列的值。在某些时候,memtable 被刷新到写入为 SSTable 的磁盘。这个新插入的分区相当于一条记录。
一段时间后,同一分区中的另一列被插入到表中。这也算一项记录。几秒钟后,插入同一分区中的另一列,然后将 memtable 刷新到磁盘。由于同一分区的这两个片段同时在 memtable 中,因此它们在写入 SSTable 之前合并在一起,因此仅“计数”为一条记录。
当天晚些时候,同一分区的现有列之一将更新为新值。由于Cassandra 在写入磁盘之前不执行读取,因此Cassandra 不知道该分区的列是否已存在于其他 SSTable 中,因此更新只是作为另一条记录插入,最终将其插入另一个 SSTable(是的,Cassandra 中的更新只是在引擎盖下插入又名“upserts”)。
在这个例子中,3 条记录存在于 3 个不同的 SSTable 中,它们实际上是同一个分区的片段。但是 Cassandra 在读取该分区之前并不知道这 3 条记录是针对同一个分区的。实际上,这就是unbounded
COUNT()
所做的:为了得出结果。
在小集群中的小表上,确保运行计数查询没什么大不了的。但是想象一下,如果在一个有几十个(如果不是几百个)节点的集群上,每个节点有数百个价值超过 500GB 的 SSTable。看看这样一个无辜的查询是如何变得如此昂贵的?它必须在您的集群中执行全表扫描,这就是您的查询在有机会完成之前会超时的原因——它无法扩展。
满是星星的星系
更复杂的是,考虑到在计数过程中,分区不断被创建和更新——毕竟这是大数据,你使用 Cassandra 是因为你有规模问题。即使你很幸运得到了结果,这个计数是否有效?你还不如数星星。因为当你在足够的时间内数完夜空中一半的星星时,你的计数很可能已经过时了,因为宇宙不是静止的——新星诞生而老星一直在死去。同样,您的表也不是静态的——创建新分区,更新现有分区,甚至删除一些分区。
“我可以用柜台吗?” , 你问。也许。如果您的用例是您只写入一次分区并且永远不会再次覆盖它。如果您的用例涉及覆盖,那么您无法确定它是否是第一次写入,因此您的计数器变得无用。您可能会想出某种算法并以某种方式存储计数,但很可能,您的“计数器”解决方案不会扩展,因为它可能涉及(a)先读后写,(b)额外写入每个操作,或(c)两者。
如果你必须
你也可以从中得到一个估计,
nodetool tablestats
但这正是你会得到的——估计。这是因为它遇到了同样的问题。当 Cassandra 将 memtable 刷新到磁盘时,它知道该 SSTable 中有多少键并相应地更新表统计信息 [1]。当我们在这里时,请注意删除也是在引擎盖下的插入,即一个墓碑被插入到表中,因此它被计入tablestats
. 只有在墓碑被压实之后才会减少gc_grace_seconds
。最后,如果您真的必须进行计数,请使用 DSE Analytics 或 DSE Search 进行计数,但这些是针对另一篇博客文章的。等我数完星星后,我会解决它,也许...
[1]我过度简化了表格统计更新所发生的事情,以使其易于为目标受众消化。实际上使用了诸如HyperLogLog之类的算法来提高聚合值的准确性。
更新
在我第一次发表这篇博文 2 年后,出现了DataStax Bulk Loader(又名DSBulk)。它是一种从 Apache Cassandra 有效加载和卸载数据的工具,尽管这不是它的能力范围。
DSBulk 有一个很好的功能,可以以分布式方式对大型表中的数据进行计数。它是加载或卸载 CSV 或 JSON 格式数据的推荐工具。它的执行速度比 cqlsh
COPY
命令快 4 倍。是的,DataStax 让开源 Apache Cassandra 用户可以免费使用它。有关详细信息,请参阅使用 DSBulk 对表中的数据进行计数。干杯!