Cassandra 查询失败(墓碑)
Cassandra query failure (Tombstones)
所以这让我发疯。我尝试在 Cassandra 中查询我的 table 之一,但它显示查询失败。我试着深入了解其背后的原因,发现这是因为墓碑。我将 GC_GRACE_SECONDS 更改为零并使用 nodetool 触发了压缩,当我再次查询时它工作正常。然而,在随后的调用中,由于同样的原因,查询再次失败。我正在使用 cassandra-nodejs 驱动程序。
这是我的数据模型。
CREATE TABLE my_table (
firstname text,
lastname text,
email text,
mobile text,
date timeuuid,
value float,
PRIMARY KEY (firstname, lastname, email, mobile)
) WITH CLUSTERING ORDER BY (lastname ASC, email ASC, mobile ASC);
这是我要对该数据模型执行的查询。
SELECT firstname, email, toDate(date) as date, mobile, value FROM my_table WHERE date >= minTimeuuid('2017-03-25 00:00:00+0000') AND date <= minTimeuuid('2017-03-28 23:59:59+0000') ALLOW FILTERING;
结果将有大约 40k 行。
this 表明,如果我们删除某些内容,它将被标记为逻辑删除,并且在 GC_GRACE_SECONDS 设置为给定 table 后将被删除。如果我没看错的话。
- 当我从不删除 table 的任何行时,怎么会出现墓碑问题?
- 当且仅当我们删除一行时,一行是否会被标记为逻辑删除?
- 清除墓碑然后查询相同的内容有时有效,有时却无效,这是为什么?
- 增加tombstone_failure_threshold值是个好主意吗? (单节点集群应用)
我使用的是 cassandra 3.5,cqlsh 版本为 5.0.1。并且查询在终端上运行良好,但是当我们使用外部客户端(使用 nodejs 驱动程序的 cassandra 的快速应用程序)执行时会出错。我有一个单节点集群应用程序。
编辑 1
这是我在字段中插入空值的日志(我只插入了名称和时间戳);
activity | timestamp | source | source_elapsed
-------------------------------------------------------------------------------------------------+----------------------------+---------------+----------------
Execute CQL3 query | 2017-03-29 10:28:27.342000 | 172.31.34.179 | 0
Parsing select * FROM testtomb WHERE name = 'Dhaval45'; [SharedPool-Worker-2] | 2017-03-29 10:28:27.342000 | 172.31.34.179 | 64
Preparing statement [SharedPool-Worker-2] | 2017-03-29 10:28:27.342000 | 172.31.34.179 | 101
Executing single-partition query on testtomb [SharedPool-Worker-3] | 2017-03-29 10:28:27.342000 | 172.31.34.179 | 210
Acquiring sstable references [SharedPool-Worker-3] | 2017-03-29 10:28:27.342000 | 172.31.34.179 | 223
Skipped 0/0 non-slice-intersecting sstables, included 0 due to tombstones [SharedPool-Worker-3] | 2017-03-29 10:28:27.342000 | 172.31.34.179 | 243
Merged data from memtables and 0 sstables [SharedPool-Worker-3] | 2017-03-29 10:28:27.342000 | 172.31.34.179 | 288
Read 2 live and 0 tombstone cells [SharedPool-Worker-3] | 2017-03-29 10:28:27.342001 | 172.31.34.179 | 310
Merged data from memtables and 0 sstables [SharedPool-Worker-3] | 2017-03-29 10:28:27.342001 | 172.31.34.179 | 323
Request complete | 2017-03-29 10:28:27.342385 | 172.31.34.179 | 385
这是我查询已执行删除查询的文件时的日志。最初用户 Dhaval15 的名字是 'aaaa' 然后我是单元格 aaa。然后再次对同一用户执行 select 查询给了我这个日志。
activity | timestamp | source | source_elapsed
-------------------------------------------------------------------------------------------------+----------------------------+---------------+----------------
Execute CQL3 query | 2017-03-29 10:35:18.581000 | 172.31.34.179 | 0
Parsing select * FROM testtomb WHERE name = 'Dhaval15'; [SharedPool-Worker-1] | 2017-03-29 10:35:18.581000 | 172.31.34.179 | 65
Preparing statement [SharedPool-Worker-1] | 2017-03-29 10:35:18.581000 | 172.31.34.179 | 113
Executing single-partition query on testtomb [SharedPool-Worker-3] | 2017-03-29 10:35:18.581000 | 172.31.34.179 | 223
Acquiring sstable references [SharedPool-Worker-3] | 2017-03-29 10:35:18.581000 | 172.31.34.179 | 235
Skipped 0/0 non-slice-intersecting sstables, included 0 due to tombstones [SharedPool-Worker-3] | 2017-03-29 10:35:18.581000 | 172.31.34.179 | 256
Merged data from memtables and 0 sstables [SharedPool-Worker-3] | 2017-03-29 10:35:18.581001 | 172.31.34.179 | 305
Read 1 live and 1 tombstone cells [SharedPool-Worker-3] | 2017-03-29 10:35:18.581001 | 172.31.34.179 | 338
Merged data from memtables and 0 sstables [SharedPool-Worker-3] | 2017-03-29 10:35:18.581001 | 172.31.34.179 | 351
Request complete | 2017-03-29 10:35:18.581430 | 172.31.34.179 | 430
在 Cassandra 中创建的逻辑删除即使您不执行删除查询,当您插入空值时。
墓碑消耗space。当你执行 select 查询时,cassandra 需要通过 tombstone 过滤掉数据。如果生成巨大的墓碑,您的 select 查询性能将会下降。
您的查询因巨大的墓碑和 ALLOW FILTERING
而失败。不要在生产环境中使用 ALLOW FILTERING
。这是非常昂贵的。当您在不指定分区键的情况下执行查询时,Cassandra 需要扫描所有节点的所有行。
将您的数据模型更改为如下所示:
CREATE TABLE my_table (
year int,
month int,
date timeuuid,
email text,
firstname text,
lastname text,
mobile text,
value float,
PRIMARY KEY ((year, month), date)
);
在这里您可以指定从日期中提取年和月。
现在您可以通过指定分区键进行查询:
SELECT * FROM my_table WHERE year = 2017 AND month = 03 AND date >= minTimeuuid('2017-03-25 00:00:00+0000') AND date <= minTimeuuid('2017-03-28 23:59:59+0000') ;
这将 return 非常有效地产生结果并且不会失败。
如果您需要使用名字和姓氏进行查询,请在其上创建索引
CREATE INDEX index_firstname ON my_table (firstname) ;
CREATE INDEX index_lastname ON my_table (lastname) ;
然后你可以用名字或姓氏查询
SELECT * FROM my_table WHERE firstname = 'ashraful' ;
SELECT * FROM my_table WHERE lastname = 'islam' ;
由于高基数问题,我没有在电子邮件和 phone 上创建索引。而是创建实体化视图或另一个 table 以使用 phone 或电子邮件
进行查询
CREATE MATERIALIZED VIEW mview_mobile AS
SELECT *
FROM my_table
WHERE mobile IS NOT NULL AND year IS NOT NULL AND month IS NOT NULL AND date IS NOT NULL
PRIMARY KEY (mobile, year, month, date);
CREATE MATERIALIZED VIEW mview_email AS
SELECT *
FROM my_table
WHERE email IS NOT NULL AND year IS NOT NULL AND month IS NOT NULL AND date IS NOT NULL
PRIMARY KEY (email, year, month, date);
现在您可以使用 phone 或电子邮件
查询
SELECT * FROM mview_mobile WHERE mobile = '018..';
SELECT * FROM mview_email WHERE email = 'ashraful@...';
关于 cassandra 墓碑的更多信息:http://thelastpickle.com/blog/2016/07/27/about-deletes-and-tombstones.html
- how come there be tombstone problem when i never delete any row of table?
@Ashraful Islam 的回答是正确的。
此外,
如果您显式插入具有 NULL 值的数据,它将在内部创建墓碑。
例如:插入 my_table(名字、姓氏、电子邮件、手机、.....)值('abd'、'gef'、'xxx@abc.com'、' +67899...', null, null, .....);
其他列将有空值(内部生成墓碑,因为 Cassandra 必须用一些东西来指示这些列不存在或没有值)。
正如您提到的作为主键的列太多,它会创建太大的宽行(这也是不鼓励的)和太多的空值,因此最终会有很多逻辑删除。在你的情况下它可能已经超过了阈值限制。
正如@Ashraful 所述,此数据模型不正确。因为需要按时间查询
您应该设计您的模型,以便您可以按时进行一些范围查询。不提及分区键的查询因此在大型数据集中使用 ALLOW FILTERING 是 Cassandra 中的反模式。
- Is that true a row will be marked as Tombstone if and only if we delete a row?
您可以删除完整的或特定的列。如果删除一行,则整行都被标记为墓碑。如果删除特定列(或 insert/UPDATE NULL 值),将在该特定列上创建墓碑(也不鼓励)我想这会发生在你的情况下。
- clearing tombstones and then querying the same works sometimes and sometimes it does not, why is so?.
我想您现在可以确定为什么会发生这种情况:)。
- is it a good idea to increase tombstone_failure_threshold value? (single node cluster application)
增加tombstone_failure_threshold只会减少错误的数量,但不能解决实际问题。随着数据集的增加,它不会提高性能并越过阈值。
而且重要的是,在单节点集群应用中,您可以将GC_GRACE_SECONDS设置为0。压缩发生后,墓碑将被立即删除。 GC_GRACE_SECONDS 在使用多节点集群时至关重要,我猜这是使用 NoSQL 的实际目的。
所以这让我发疯。我尝试在 Cassandra 中查询我的 table 之一,但它显示查询失败。我试着深入了解其背后的原因,发现这是因为墓碑。我将 GC_GRACE_SECONDS 更改为零并使用 nodetool 触发了压缩,当我再次查询时它工作正常。然而,在随后的调用中,由于同样的原因,查询再次失败。我正在使用 cassandra-nodejs 驱动程序。 这是我的数据模型。
CREATE TABLE my_table (
firstname text,
lastname text,
email text,
mobile text,
date timeuuid,
value float,
PRIMARY KEY (firstname, lastname, email, mobile)
) WITH CLUSTERING ORDER BY (lastname ASC, email ASC, mobile ASC);
这是我要对该数据模型执行的查询。
SELECT firstname, email, toDate(date) as date, mobile, value FROM my_table WHERE date >= minTimeuuid('2017-03-25 00:00:00+0000') AND date <= minTimeuuid('2017-03-28 23:59:59+0000') ALLOW FILTERING;
结果将有大约 40k 行。 this 表明,如果我们删除某些内容,它将被标记为逻辑删除,并且在 GC_GRACE_SECONDS 设置为给定 table 后将被删除。如果我没看错的话。
- 当我从不删除 table 的任何行时,怎么会出现墓碑问题?
- 当且仅当我们删除一行时,一行是否会被标记为逻辑删除?
- 清除墓碑然后查询相同的内容有时有效,有时却无效,这是为什么?
- 增加tombstone_failure_threshold值是个好主意吗? (单节点集群应用)
我使用的是 cassandra 3.5,cqlsh 版本为 5.0.1。并且查询在终端上运行良好,但是当我们使用外部客户端(使用 nodejs 驱动程序的 cassandra 的快速应用程序)执行时会出错。我有一个单节点集群应用程序。
编辑 1
这是我在字段中插入空值的日志(我只插入了名称和时间戳);
activity | timestamp | source | source_elapsed
-------------------------------------------------------------------------------------------------+----------------------------+---------------+----------------
Execute CQL3 query | 2017-03-29 10:28:27.342000 | 172.31.34.179 | 0
Parsing select * FROM testtomb WHERE name = 'Dhaval45'; [SharedPool-Worker-2] | 2017-03-29 10:28:27.342000 | 172.31.34.179 | 64
Preparing statement [SharedPool-Worker-2] | 2017-03-29 10:28:27.342000 | 172.31.34.179 | 101
Executing single-partition query on testtomb [SharedPool-Worker-3] | 2017-03-29 10:28:27.342000 | 172.31.34.179 | 210
Acquiring sstable references [SharedPool-Worker-3] | 2017-03-29 10:28:27.342000 | 172.31.34.179 | 223
Skipped 0/0 non-slice-intersecting sstables, included 0 due to tombstones [SharedPool-Worker-3] | 2017-03-29 10:28:27.342000 | 172.31.34.179 | 243
Merged data from memtables and 0 sstables [SharedPool-Worker-3] | 2017-03-29 10:28:27.342000 | 172.31.34.179 | 288
Read 2 live and 0 tombstone cells [SharedPool-Worker-3] | 2017-03-29 10:28:27.342001 | 172.31.34.179 | 310
Merged data from memtables and 0 sstables [SharedPool-Worker-3] | 2017-03-29 10:28:27.342001 | 172.31.34.179 | 323
Request complete | 2017-03-29 10:28:27.342385 | 172.31.34.179 | 385
这是我查询已执行删除查询的文件时的日志。最初用户 Dhaval15 的名字是 'aaaa' 然后我是单元格 aaa。然后再次对同一用户执行 select 查询给了我这个日志。
activity | timestamp | source | source_elapsed
-------------------------------------------------------------------------------------------------+----------------------------+---------------+----------------
Execute CQL3 query | 2017-03-29 10:35:18.581000 | 172.31.34.179 | 0
Parsing select * FROM testtomb WHERE name = 'Dhaval15'; [SharedPool-Worker-1] | 2017-03-29 10:35:18.581000 | 172.31.34.179 | 65
Preparing statement [SharedPool-Worker-1] | 2017-03-29 10:35:18.581000 | 172.31.34.179 | 113
Executing single-partition query on testtomb [SharedPool-Worker-3] | 2017-03-29 10:35:18.581000 | 172.31.34.179 | 223
Acquiring sstable references [SharedPool-Worker-3] | 2017-03-29 10:35:18.581000 | 172.31.34.179 | 235
Skipped 0/0 non-slice-intersecting sstables, included 0 due to tombstones [SharedPool-Worker-3] | 2017-03-29 10:35:18.581000 | 172.31.34.179 | 256
Merged data from memtables and 0 sstables [SharedPool-Worker-3] | 2017-03-29 10:35:18.581001 | 172.31.34.179 | 305
Read 1 live and 1 tombstone cells [SharedPool-Worker-3] | 2017-03-29 10:35:18.581001 | 172.31.34.179 | 338
Merged data from memtables and 0 sstables [SharedPool-Worker-3] | 2017-03-29 10:35:18.581001 | 172.31.34.179 | 351
Request complete | 2017-03-29 10:35:18.581430 | 172.31.34.179 | 430
在 Cassandra 中创建的逻辑删除即使您不执行删除查询,当您插入空值时。
墓碑消耗space。当你执行 select 查询时,cassandra 需要通过 tombstone 过滤掉数据。如果生成巨大的墓碑,您的 select 查询性能将会下降。
您的查询因巨大的墓碑和 ALLOW FILTERING
而失败。不要在生产环境中使用 ALLOW FILTERING
。这是非常昂贵的。当您在不指定分区键的情况下执行查询时,Cassandra 需要扫描所有节点的所有行。
将您的数据模型更改为如下所示:
CREATE TABLE my_table (
year int,
month int,
date timeuuid,
email text,
firstname text,
lastname text,
mobile text,
value float,
PRIMARY KEY ((year, month), date)
);
在这里您可以指定从日期中提取年和月。
现在您可以通过指定分区键进行查询:
SELECT * FROM my_table WHERE year = 2017 AND month = 03 AND date >= minTimeuuid('2017-03-25 00:00:00+0000') AND date <= minTimeuuid('2017-03-28 23:59:59+0000') ;
这将 return 非常有效地产生结果并且不会失败。
如果您需要使用名字和姓氏进行查询,请在其上创建索引
CREATE INDEX index_firstname ON my_table (firstname) ;
CREATE INDEX index_lastname ON my_table (lastname) ;
然后你可以用名字或姓氏查询
SELECT * FROM my_table WHERE firstname = 'ashraful' ;
SELECT * FROM my_table WHERE lastname = 'islam' ;
由于高基数问题,我没有在电子邮件和 phone 上创建索引。而是创建实体化视图或另一个 table 以使用 phone 或电子邮件
进行查询CREATE MATERIALIZED VIEW mview_mobile AS
SELECT *
FROM my_table
WHERE mobile IS NOT NULL AND year IS NOT NULL AND month IS NOT NULL AND date IS NOT NULL
PRIMARY KEY (mobile, year, month, date);
CREATE MATERIALIZED VIEW mview_email AS
SELECT *
FROM my_table
WHERE email IS NOT NULL AND year IS NOT NULL AND month IS NOT NULL AND date IS NOT NULL
PRIMARY KEY (email, year, month, date);
现在您可以使用 phone 或电子邮件
查询SELECT * FROM mview_mobile WHERE mobile = '018..';
SELECT * FROM mview_email WHERE email = 'ashraful@...';
关于 cassandra 墓碑的更多信息:http://thelastpickle.com/blog/2016/07/27/about-deletes-and-tombstones.html
- how come there be tombstone problem when i never delete any row of table?
@Ashraful Islam 的回答是正确的。
此外, 如果您显式插入具有 NULL 值的数据,它将在内部创建墓碑。
例如:插入 my_table(名字、姓氏、电子邮件、手机、.....)值('abd'、'gef'、'xxx@abc.com'、' +67899...', null, null, .....);
其他列将有空值(内部生成墓碑,因为 Cassandra 必须用一些东西来指示这些列不存在或没有值)。
正如您提到的作为主键的列太多,它会创建太大的宽行(这也是不鼓励的)和太多的空值,因此最终会有很多逻辑删除。在你的情况下它可能已经超过了阈值限制。
正如@Ashraful 所述,此数据模型不正确。因为需要按时间查询 您应该设计您的模型,以便您可以按时进行一些范围查询。不提及分区键的查询因此在大型数据集中使用 ALLOW FILTERING 是 Cassandra 中的反模式。
- Is that true a row will be marked as Tombstone if and only if we delete a row?
您可以删除完整的或特定的列。如果删除一行,则整行都被标记为墓碑。如果删除特定列(或 insert/UPDATE NULL 值),将在该特定列上创建墓碑(也不鼓励)我想这会发生在你的情况下。
- clearing tombstones and then querying the same works sometimes and sometimes it does not, why is so?.
我想您现在可以确定为什么会发生这种情况:)。
- is it a good idea to increase tombstone_failure_threshold value? (single node cluster application)
增加tombstone_failure_threshold只会减少错误的数量,但不能解决实际问题。随着数据集的增加,它不会提高性能并越过阈值。
而且重要的是,在单节点集群应用中,您可以将GC_GRACE_SECONDS设置为0。压缩发生后,墓碑将被立即删除。 GC_GRACE_SECONDS 在使用多节点集群时至关重要,我猜这是使用 NoSQL 的实际目的。