如何删除Cassandra中的大量行(并避免潜在的墓碑问题)?

Mil*_*vić 5 cassandra tombstone

过度简化数据模型,我们有以下表格:

CREATE TABLE storage (
    id timeuuid,
    foo blob,
    bar blob,
    baz blob,
    data blob,
    PRIMARY KEY ((id))
);

CREATE TABLE storage_idx_by_foo (
    foo blob,
    id timeuuid,
    PRIMARY KEY ((foo), id)
);

CREATE TABLE storage_idx_by_bar (
    bar blob,
    id timeuuid,
    PRIMARY KEY ((bar), id)
);

CREATE TABLE storage_idx_by_baz (
    baz blob,
    id timeuuid,
    PRIMARY KEY ((baz), id)
);
Run Code Online (Sandbox Code Playgroud)

第一个表可以包含数亿个记录,我们使用索引表根据一些可查询参数轻松定位数据.

当我们必须根据foo,barbaz 清除数据时,就会出现问题.我们必须从存储表和所有索引表中删除该条目.因此,假设我们通过例如foo删除,所采取的步骤是:

  1. 根据相应的索引表(在本例中为storage_idx_by_foo)查找id
  2. 获取baz并从存储表中删除记录
  3. 从剩余的两个索引表中删除记录(我们有bar/bazid)

由于墓碑,第3步是一个问题- 如果我们从剩下的两个索引表中删除数百万条记录(意思不是通过分区),Cassandra将创建数百万个墓碑,这会在压缩发生之前读取数据时引起很多麻烦.

一些快速的头脑风暴表明我们可以:

  1. 在吹扫过程后强制压实
  2. 不从这两个表中删除并处理指向代码中不存在的东西的索引条目
  3. ????

建议的方法是什么?我猜其他Cassandra用户也遇到过这个问题,但除了"你正在做Cassandra错误"之外我在网上找不到任何建议.我认为我们不能以不同的方式对我们的数据进行建模以避免这个问题(或者如果我们可以的话,我也会对这方面的反馈表示赞赏).

目前,我们倾向于选项2,尽管我不喜欢垃圾留在数据库中的想法.

ash*_*hic 3

“你可能做错了卡桑德拉”!

您有什么疑问?在不了解查询的情况下尝试进行概括通常会导致 Cassandra 中的模型较差。建模确实应该是查询驱动的。即使您不知道确切的查询,您也应该知道查询的类型(即您正在索引什么,等等)。

如果您知道要对 foo、bar 和 baz 建立索引,请考虑是否可以添加一些可以用作分区键的约束。对于您概述的模式,您将遇到的一个主要问题是是否存在大量相同 foo 值(或 bar 值或 baz 值)的条目。虽然从理论上讲,分区可以非常大,但分区大于数十兆或一百兆左右会对性能产生不利影响。因此,在执行宽行时,请考虑如何限制宽行的大小。如果每个 foo 或 bar 或 baz 有几百到几千个条目,这不会是问题。否则,你就是自找麻烦。在这种情况下,您可能需要添加一些分桶功能。例如,看看您是否可以将查询限制为“获取该日期 foo x 的数据”或“获取该国家/地区/邮政编码/等的 foo x 的数据”。这将防止出现巨大的宽行。

手动索引的另一个问题是索引更新不是原子的,并且索引可能位于与实际数据不同的节点上。如果您可以将查询限制为存储桶,您的架构可能如下所示:

CREATE TABLE storage (
    some_bucket text,
    id timeuuid,
    foo blob,
    bar blob,
    baz blob,
    data blob,
    PRIMARY KEY (somebucket, id)
);
Run Code Online (Sandbox Code Playgroud)

或者甚至您可以按原样保留存储并将索引设置为:

CREATE TABLE storage (
    bucket text,
    foo blob,
    bar blob,
    baz blob,
    data blob,
    PRIMARY KEY (bucket)
);
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,您都需要在 foo、bar 和 baz 上创建 cassandra 二级索引。这将允许您的查询。请记住,使用二级索引时,始终首先命中分区 - 否则它会成为集群范围的查询,可能会超时。在Cassandra 3.0中,即将推出一项称为全局索引的功能,该功能旨在减轻首先命中分区的需要,但在此之前,命中分区+二级索引,您的查询将会很快

现在...关于墓碑的话题。Cassandra 删除将使用墓碑。没有办法解决这个问题。任何 LSM 数据库都需要压缩,而逻辑删除是 cassandra 实现稳定写入吞吐量(几乎)的机制,无论负载如何。不过,您可以做一些事情。如果您可以限制何时发生此类大规模删除,则可以使用 nodetool 禁用自动压缩:

http://www.datastax.com/documentation/cassandra/2.1/cassandra/tools/toolsDisableAutoCompaction.html

然后您可以进行清除,然后强制压缩:

http://www.datastax.com/documentation/cassandra/2.1/cassandra/tools/toolsCompact.html

并再次启用自动压缩。

这显然不是“整洁”的,但是如果您要从表中删除大量数据(但不是全部),那么这会起作用。

希望有帮助。