7

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

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

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

当我们必须基于foobarbaz清除数据时,问题就来了。我们必须从存储表和所有索引表中删除条目。因此,假设我们通过例如foo删除,采取的步骤是:

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

第 3 步是因为tombstones的问题- 如果我们从剩余的两个索引表中删除数百万条记录(意味着不是通过分区),Cassandra 将创建数百万条 tombstones,这在压缩发生之前读取数据时会引起很多麻烦。

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

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

建议的方法是什么?我猜其他 Cassandra 用户也遇到过这个问题,但除了“你做错了 Cassandra”之外,我在网上找不到任何建议。我不认为我们可以对我们的数据进行不同的建模来避免这个问题(或者如果可以的话,我也会很感激对此的反馈)。

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

4

1 回答 1

2

“你可能做错了 cassandra”!!

您有什么疑问?在不知道查询的情况下尝试泛化通常会导致 Cassandra 中的模型不佳。建模真的应该是查询驱动的。即使您不知道确切的查询,您也应该知道查询的种类(即您在索引什么等)。

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

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

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

甚至您可以保留存储空间并将索引设置为:

CREATE TABLE storage (
    bucket text,
    foo blob,
    bar blob,
    baz blob,
    data blob,
    PRIMARY KEY (bucket)
);

在这两种情况下,您都将在 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

并再次启用自动压缩。

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

希望有帮助。

于 2014-12-29T10:59:24.247 回答