Cassandra查询失败(Tombstones)

时间:2017-03-29 05:57:38

标签: cassandra cassandra-3.0 cassandra-node-driver

所以这让我发疯了。我试着查询我在Cassandra的一张桌子,它显示查询失败。我试着挖掘它背后的原因,发现它是因为墓碑。我将GC_GRACE_SECONDS更改为Zero并使用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之后将被删除。如果我理解正确的话。

  1. 当我从未删除任何一行表时,怎么会出现墓碑问题?
  2. 当且仅当我们删除一行时,行是否会被标记为Tombstone?
  3. 清除墓碑,然后有时查询同样的作品,有时却不这样做,为什么会如此?。
  4. 增加 tombstone_failure_threshold 值是个好主意吗? (单节点集群应用程序)
  5. 我正在使用cassandra 3.5,使用cqlsh 5.0.1版。并且查询在终端上工作正常,但是当我们使用外部客户端执行时出错(使用nodejs驱动程序为cassandra表达app)。我有一个单节点群集应用程序。

    编辑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
    

2 个答案:

答案 0 :(得分:1)

在Cassandra tombstone创建时,即使您不执行删除查询,也会在插入空值时创建。

墓碑消耗空间。当你执行select query时,cassandra需要通过tombstone过滤掉数据。如果生成巨大的逻辑删除,那么您的选择查询性能会降低。

由于巨大的墓碑和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') ;

这将非常有效地返回结果,并且不会失败。

如果您需要使用firstname和lastname查询,请在它们上创建索引

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' ;

由于基数高的问题,我没有在电子邮件和手机上创建索引。而是创建物化视图或其他表格以通过电话或电子邮件进行查询

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);

现在您可以通过电话或电子邮件查询

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

答案 1 :(得分:1)

  
    
        
  1. 当我从未删除任何一行表时,怎么会出现墓碑问题?
  2.        
@Ashraful伊斯兰教的回答是正确的。

此外, 如果使用NULL值显式插入数据,它将在内部创建逻辑删除。

例如:插入my_table(firstname,lastname,email,mobile,.....)值('abd','gef','xxx @ abc.com','+ 67899 ...',null , 空值, .....);

其他列将存在空值(内部生成逻辑删除,因为Cassandra必须指出这些列不存在或具有值的内容)。

正如你提到的太多列作为主键,它会创建太大的宽行(也不鼓励),因为太多的空值会导致大量的逻辑删除。在您的情况下,它可能超过了阈值限制。

正如@Ashraful所说这个数据模型不合适。因为你需要按时间查询 你应该设计你的模型,这样你就可以按时完成一些范围的查询。查询而不提及分区键因此在大型数据集中使用ALLOW FILTERING是Cassandra中的反模式。

  
    
        
  1. 当且仅当我们删除一行时,行是否会被标记为Tombstone?
  2.        

您可以删除完整列或特定列。如果删除行,则整行将标记为逻辑删除。如果删除了一个特定的列(或插入/ UPDATE NULL值),将在该特定列上创建逻辑删除(这也是不鼓励的)我想这会发生在你的情况下。

  
    
        
  1. 清除墓碑,然后有时查询同样的作品,有时却不这样做,为什么会如此?。
  2.        

我想你现在可以确定为什么会这样:)。

  
    
        
  1. 增加tombstone_failure_threshold值是个好主意吗? (单节点集群应用程序)
  2.        

增加tombstone_failure_threshold只会减少错误量,但无法解决实际问题。随着数据集的增加,它不会提高性能并超过阈值。

更重要的是,在单节点群集应用程序中,您可以将GC_GRACE_SECONDS设置为0.在压缩发生后,将立即删除逻辑删除。 GC_GRACE_SECONDS在使用多节点集群时至关重要,这是我猜NoSQL的实际目的。