墓碑
什么是墓碑?
Cassandra 删除数据的流程旨在提高性能,并与 Cassandra 的内置数据分布和容错属性协同工作。
Cassandra 将删除视为插入,并插入一个带时间戳的删除标记,称为墓碑。墓碑会经过 Cassandra 的写入路径,并写入一个或多个节点上的 SSTable。墓碑的主要特征区别在于它具有内置的过期日期/时间。在过期时间段(宽限期)结束时,墓碑将在 Cassandra 的正常压缩过程中被删除。
您还可以使用生存时间 (TTL) 值标记 Cassandra 行或列。在该时间段结束后,Cassandra 会使用墓碑标记该对象,并像处理其他墓碑对象一样处理它。 |
僵尸
在多节点集群中,Cassandra 可能会在两个或多个节点上存储相同数据的副本。这有助于防止数据丢失,但也使删除过程变得复杂。如果一个节点收到对其本地存储数据的删除命令,该节点会将指定对象标记为墓碑,并尝试将墓碑传递给包含该对象副本的其他节点。但如果其中一个副本节点此时无响应,它不会立即收到墓碑,因此它仍然包含该对象的删除前版本。如果在该节点恢复之前,墓碑对象已从集群的其余部分删除,Cassandra 会将恢复节点上的对象视为新数据,并将其传播到集群的其余部分。这种已删除但仍然存在的对象称为 僵尸。
宽限期
为了防止僵尸重新出现,Cassandra 为每个墓碑设置了一个宽限期。墓碑的宽限期由表属性 ` WITH gc_grace_seconds` 设置。其默认值为 864000 秒(十天),之后墓碑会过期,并在压缩期间被删除。在宽限期结束之前,Cassandra 会通过压缩事件保留墓碑。每个表都可以为此属性设置自己的值。
宽限期的目的是为无响应节点提供时间来恢复并正常处理墓碑。如果客户端在宽限期内写入对墓碑对象的更新,Cassandra 会覆盖墓碑。如果客户端在宽限期内发送对该对象的读取请求,Cassandra 会忽略墓碑,并尽可能从其他副本中检索该对象。
当无响应节点恢复时,Cassandra 使用提示传递来重放节点在停机期间错过的数据库变动。Cassandra 不会在宽限期内重放墓碑对象的变动。但如果节点直到宽限期结束之后才恢复,Cassandra 可能会错过删除操作。
在墓碑的宽限期结束之后,Cassandra 会在压缩期间删除墓碑。
删除
在 `gc_grace_seconds` 过期后,墓碑可能会被删除(这意味着不再存在任何关于特定数据被删除的对象)。但删除的一个复杂之处在于,墓碑可能存在于一个 SSTable 中,而它标记为删除的数据存在于另一个 SSTable 中,因此压缩也必须删除这两个 SSTable。更准确地说,删除实际的墓碑,
-
墓碑必须比 `gc_grace_seconds` 更旧。请注意,即使 `gc_grace_seconds` 已过,墓碑也不会在压缩事件之前被删除。
-
如果分区 X 包含墓碑,则包含该分区的 SSTable 以及包含比包含 X 的墓碑更旧数据的 SSTable 必须包含在同一个压缩中。如果包含分区 X 的任何 SSTable 中的所有数据都比墓碑更新,则可以忽略它。
-
如果启用了 `only_purge_repaired_tombstones` 选项,则只有在数据也被修复后才会删除墓碑。此过程在“使用墓碑的删除”部分中进行了描述。
如果节点停机或断开连接的时间超过 `gc_grace_seconds`,则其已删除的数据将被修复回其他节点,并在集群中重新出现。这与“不使用墓碑的删除”部分中的情况基本相同。
不使用墓碑的删除
假设一个三节点集群,其中值 [A] 被复制到每个节点。
[A], [A], [A]
如果其中一个节点发生故障,而我们的删除操作只删除现有值,我们最终可能会得到一个看起来像这样的集群
[], [], [A]
然后,修复操作会将值 [A] 替换回缺少该值的两个节点。
[A], [A], [A]
这会导致我们的数据作为僵尸复活,即使它已被删除。
使用墓碑的删除
从一个三节点集群开始,其中值 [A] 被复制到每个节点。
[A], [A], [A]
如果我们不是删除数据,而是添加一个墓碑对象,那么单节点故障情况将看起来像
[A, Tombstone[A]], [A, Tombstone[A]], [A]
现在,当我们执行修复操作时,墓碑将被复制到副本,而不是被删除的数据复活
[A, Tombstone[A]], [A, Tombstone[A]], [A, Tombstone[A]]
我们的修复操作将正确地将系统状态设置为我们期望的状态,即对象 [A] 在所有节点上都被标记为已删除。但这确实意味着我们最终会累积墓碑,这些墓碑会永久占用磁盘空间。为了避免永久保留墓碑,我们为 Cassandra 中的每个表设置 `gc_grace_seconds`。
完全过期的 SSTable
如果一个 SSTable 只包含墓碑,并且可以保证该 SSTable 不会覆盖任何其他 SSTable 中的数据,那么压缩可以删除该 SSTable。如果您看到只包含墓碑的 SSTable(请注意,TTL 数据在生存时间过期后被视为墓碑),但它没有被压缩删除,则很可能是其他 SSTable 包含更旧的数据。有一个名为 `sstableexpiredblockers` 的工具可以列出哪些 SSTable 可以删除,以及哪些 SSTable 阻止它们被删除。使用 `TimeWindowCompactionStrategy`,可以通过启用 `unsafe_aggressive_sstable_expiration` 来移除保证(不检查覆盖数据)。