4.5. 集群清除

集群清除的主要目的是清理包含多个已删除墓碑或包含大量冲突的单个文档的数据库。但它也可以用于清除任何文档(已删除或未删除),无论其修订版本数量如何。

集群清除旨在维护最终一致性并防止不必要地使辅助索引失效。为此,每个数据库都会跟踪数据库中请求的特定数量的历史清除,以及其当前的 purge_seq。内部复制和辅助索引处理数据库的清除,并定期更新其相应的清除检查点文档以报告它们处理的 purge_seq。为了确保最终一致性,数据库将仅在内部复制作业和辅助索引处理完存储的历史清除请求后才将其删除。

4.5.1. 内部结构

为了启用清除信息的内部复制在节点和辅助索引之间,数据库文件中添加了两个内部清除树来跟踪历史清除。

purge_tree: UUID -> {PurgeSeq, DocId, Revs}
purge_seq_tree: PurgeSeq -> {UUID, DocId, Revs}

_purge API 的每个交互式请求都会创建一个按升序排列的 purge_seq 和清除请求对的集合,其中清除请求是一个包含 docid 和修订版本列表的元组。为每个清除请求生成 UUID。清除请求被添加到内部清除树中:元组 {UUID -> {PurgeSeq, DocId, Revs}} 被添加到 purge_tree 中,元组 {PurgeSeq -> {UUID, DocId, Revs}} 被添加到 purge_seq_tree 中。

4.5.2. 清除压缩

在数据库压缩期间,最旧的清除请求将被删除,以便仅在数据库中存储 purged_infos_limit 个清除。但为了使数据库与索引和其他副本保持一致,我们只能删除已被索引和内部复制作业处理的清除请求。因此,清除树偶尔可能会存储超过 purged_infos_limit 个清除。如果数据库中存储的清除数量超过 purged_infos_limit 的某个阈值,则日志中会生成警告,表明数据库的清除与索引和其他副本同步存在问题。

4.5.3. 本地清除检查点文档

包含清除的数据库的索引和内部复制会创建并定期更新本地检查点清除文档:_local/purge-$type-$hash。这些文档报告它们处理的最后一个 purge_seq 以及最后一次处理的时间戳。本地检查点清除文档的示例

{
  "_id": "_local/purge-mrview-86cacdfbaf6968d4ebbc324dd3723fe7",
  "type": "mrview",
  "purge_seq": 10,
  "updated_on": 1540541874,
  "ddoc_id": "_design/foo",
  "signature": "5d10247925f826ae3e00966ec24b7bf6"
}

下图显示了数据库可能具有的本地检查点文档。

Local Purge Checkpoint Documents

本地清除检查点文档

4.5.4. 内部复制

清除请求以最终一致的方式在所有节点之间重放。清除的内部复制包含两个步骤

1. 拉取复制。内部复制首先从目标拉取清除并将其应用于源,以确保我们不会将已在目标上清除的源的文档/修订版本重新引入到目标。在此步骤中,我们使用存储在目标上的清除检查点文档来跟踪源处理的最后一个目标的 purge_seq。我们找到在此 purge_seq 之后发生的清除请求,并在源上重放它们。此步骤通过使用最新的处理 purge_seq 和时间戳更新目标的检查点清除文档来完成。

2. 推送复制。然后,内部复制照常进行,并在其中插入一个额外的步骤,将源的清除请求推送到目标。在此步骤中,我们使用本地内部复制检查点文档,这些文档在目标和源上都更新。

在正常情况下,交互式清除请求已发送到包含数据库分片副本的每个节点,并在每个副本上应用。节点之间清除的内部复制只是一个额外的步骤,以确保副本之间的一致性,其中一个节点上的所有清除请求都在另一个节点上重放。为了不在副本上重放相同的清除请求,每个交互式清除请求都用唯一的 uuid 标记。内部复制会过滤掉副本的 purge_tree 中已存在的 UUID 的清除请求,并且仅应用 UUID 不存在于 purge_tree 中的清除请求。这就是我们需要有两个内部清除树的原因:1) purge_tree{UUID -> {PurgeSeq, DocId, Revs}} 允许快速查找副本中已存在的 UUID 的清除请求;2) purge_seq_tree{PurgeSeq -> {UUID, DocId, Revs}} 允许从给定的 purge_seq 迭代以收集在此 purge_seq 之后发生的清除请求。

4.5.5. 索引

每个清除请求都会增加数据库的 update_seq,以便每个辅助索引也更新以应用清除请求以维护主数据库内的一致性。

4.5.6. 配置设置

这些设置可以在 default.ini 或 local.ini 中更新

字段

描述

默认值

max_document_id_number

允许在一个清除请求中包含的最大文档数量

100

max_revisions_number

允许在一个清除请求中包含的最大累积修订版本数量

1000

allowed_purge_seq_lag

除了 purged_infos_limit 之外,还允许额外的缓冲区来存储清除请求

100

index_lag_warn_seconds

允许索引未更新本地清除检查点文档的时间段

86400

在数据库压缩期间,我们检查所有检查点清除文档。客户端(索引或内部复制作业)允许其最后报告的 purge_seq 小于当前数据库分片的 purge_seq(purged_infos_limit + allowed_purge_seq_lag) 值。如果客户端的 purge_seq 甚至更小,并且客户端在 index_lag_warn_seconds 内没有进行检查点,则它会阻止清除树的压缩,我们必须为此客户端发出以下日志警告

Purge checkpoint '_local/purge-mrview-9152d15c12011288629bcffba7693fd4’
not updated in 86400 seconds in
<<"shards/00000000-1fffffff/testdb12.1491979089">>

如果出现此类型的日志警告,请检查客户端以查看为什么清除请求的处理在其中停滞。

索引的设计文档和本地检查点文档之间存在映射关系。如果索引的设计文档被更新或删除,则相应的本地检查点文档也应自动删除。但在意外情况下,当设计文档被更新/删除时,但其检查点文档仍然存在于数据库中,则会发出以下警告

"Invalid purge doc '<<"_design/bar">>' on database
<<"shards/00000000-1fffffff/testdb12.1491979089">>
with purge_seq '50'"

如果出现此类型的日志警告,请从数据库中删除本地清除文档。