官方文档
集群管理
理论
在 etc/fefault.INI 文件中有以下部分:
[cluster] q=8 n=3
q - 分片的数量
n - 每一份文档的拷贝数量(加上原文档一共几份副本)
创建数据库时可以通过覆盖该值修改为自己的值.
在集群操作中, 获取操作中 CouchDB 返回状态码 200 或者是写操作返回状态码 201 即为大多数成员达成一致. 大多数成员定义为相关拷贝的数量的一半. 对于 "读写" 操作,"相关副本" 的定义稍有不同.
对于读操作, 相关副本的数量是保存请求数据的当前可访问分片的数量, 这意味着在发生故障或网络分区的情况下, 相关副本的数量可能少于集群中的副本数量. 可以使用 r 参数设置读取份数.
对于写操作, 相关副本的数量始终为 n, 即集群中的副本数量. 对于写操作, 可以使用 w 参数设置份数. 如果少于此数量的可用节点, 则返回 202.
节点管理
查看所有节点
- curl -u admin:adminpw -X GET http://localhost:5984/_membership
- {
- "all_nodes":[ # 当前节点所知道的节点
- "node1@xxx.xxx.xxx.xxx"],
- "cluster_nodes":[ #当前节点所连接的节点
- "node1@xxx.xxx.xxx.xxx"],
- }
添加一个节点
curl -u admin:adminpw -X PUT http://localhost:5986/_nodes/node2@yyy.yyy.yyy.yyy -d {}
删除一个节点
- # 首先获取关于文档的 revision
- curl -u admin:adminpw -X GET "http://xxx.xxx.xxx.xxx:5986/_nodes/node2@yyy.yyy.yyy.yyy"
- {
- "_id":"node2@yyy.yyy.yyy.yyy","_rev":"1-967a00dff5e02add41820138abb3284d"
- }
- # 删除节点
- curl -u admin:adminpw -X DELETE http://localhost:5986/_nodes/node2@yyy.yyy.yyy.yyy?rev=1-967a00dff5e02add41820138abb3284d
数据库管理
创建数据库
数据库名字不支持大写字符, 只支持[a-z],[0-9], 以及特殊字符:_ $ ( ) + - /
- # 创建一个数据库名字为 db_name
- curl -u admin:adminpw -X PUT http://localhost:5984/db_name?q=4&n=2
删除数据库
curl -u admin:adminpw -X DELETE http://localhost:5984/db_name
在一个具体的节点放置数据库
在 CouchDB 2.0 群集功能的前身 BigCouch 中, 存在区域的概念. CouchDB 2.0 通过集群放置规则来实现这一目标.
使用 placement 参数将覆盖分片副本基数的标准逻辑(由[cluster] n 指定).
首先, 每个节点必须标记有 zone 属性. 这定义了每个节点所在的区域. 您可以通过编辑 / nodes 数据库中的节点文档来实现, 该文档可通过 "后门"(5986)端口进行访问. 添加以下形式的键值对:
"zone":"metro-dc-a"
在集群上所有节点上操作.
在每一个节点的配置文件 local.INI 或者 default.INI 中, 定义相同的集群设置:
- [cluster]
- placement = metro-dc-a:2,metro-dc-b:1
在此示例中, 它将确保将一个分区的两个副本托管在将 zone 属性设置为 metro-dc-a 的节点上, 并将一个副本副本托管在一个将 zone 属性设置为 metro-dc-b 的新副本上.
请注意, 您还可以使用该系统, 通过为群集中的某些节点提供不出现在 [cluster] 放置字符串中的 zone 属性, 来确保它们不承载新创建的数据库的任何副本.
分片管理
介绍
本文档讨论了分片在 CouchDB 中的工作方式, 以及如何安全地添加, 移动, 删除和创建分片和分片副本的放置规则.
分片是数据库中数据的水平分区. 将数据划分为多个碎片, 并将每个碎片的副本 (称为 "碎片副本" 或简称为 "副本") 分布到群集中的不同节点, 可以提高数据的持久性, 防止节点丢失. CouchDB 群集自动分片数据库, 并在节点之间分配组成每个分片的文档子集. 修改群集成员身份和分片行为必须手动完成.
分片和复制
可以在全局级别或每个数据库的基础上设置每个数据库有多少个分片和副本. 相关参数是 q 和 n.
q 是要维护的数据库分片数. n 是要分发的每个文档的副本数. n 的默认值为 3,q 的默认值为 8. 当 q= 8 时, 数据库分为 8 个分片. 在 n=3 的情况下, 群集分发每个分片的三个副本. 总共, 一个数据库有 24 个分片副本. 在默认的 3 节点群集中, 每个节点将接收 8 个分片. 在 4 节点群集中, 每个节点将接收 6 个分片. 在一般情况下, 我们建议群集中的节点数应为 n 的倍数, 以使碎片均匀分布.
CouchDB 节点的 etc/local.INI 文件中的 cluster 部分:
[cluster] q=8 n=3
可以修改这些设置以设置所有数据库的分片默认值, 或者可以在创建数据库时通过指定 q 和 n 查询参数来针对每个数据库进行设置. 例如:
curl -X PUT "http://localhost:5984/database-name?q=4&n=2"
这将创建一个数据库, 该数据库分为 4 个分片和 2 个副本, 从而产生 8 个分片副本分布在整个数据库中
的集群上.
Quorum
取决于集群的大小, 每个数据库的分片数量以及分片副本的数量, 并非每个节点都可以访问每个分片, 但是每个节点都知道可以通过 CouchDB 的内部分片在哪里找到每个分片的所有副本.
进入 CouchDB 集群的每个请求均由任意一个随机协调节点处理. 该协调节点将请求代理给其他具有相关数据的节点, 这些数据可能包含也可能不包含自身. 一旦达到法定数量的数据库节点响应, 协调节点就会向客户端发送响应. 2 默认情况下, 默认的法定仲裁大小等于 r=w=((n+1)/2), 其中 r 表示读取仲裁的大小, w 表示写入仲裁的大小, n 表示数字每个分片的副本. 在 n 为 3 的默认群集中,((n+1)/2)将为 2.
集群中的每个节点都可以作为任何请求的协调节点. 集群内部没有专门的节点角色.
可以在请求时通过设置文档和视图读取的 r 参数以及文档写入的 w 参数来配置所需仲裁的大小. 例如, 这是一个请求, 一旦至少两个节点已响应, 该请求便指示协调节点发送响应:
curl "$COUCH_URL:5984/<db>/<doc>?r=2"
这是写文档的类似示例:
curl -X PUT "$COUCH_URL:5984/<db>/<doc>?w=2" -d '{...}'
将 r 或 w 设置为等于 n(副本数)意味着只有在所有具有相关分片的节点都响应或超时后, 您才会收到响应, 因此这种方法不能保证 ACID 的一致性. 将 r 或 w 设置为 1 意味着仅一个相关节点响应后, 您将收到响应.
数据库分片测试
有一些 API 端点可以帮助您了解如何分片数据库. 首先, 在集群上创建一个新数据库, 然后将几个文档放入其中:
- $ curl -X PUT $COUCH_URL:5984/mydb
- {
- "ok":true
- }
- $ curl -X PUT $COUCH_URL:5984/mydb/joan -d '{"loves":"cats"}'
- {
- "ok":true,"id":"joan","rev":"1-cc240d66a894a7ee7ad3160e69f9051f"
- }
- $ curl -X PUT $COUCH_URL:5984/mydb/robert -d '{"loves":"dogs"}'
- {
- "ok":true,"id":"robert","rev":"1-4032b428c7574a85bc04f1f271be446e"
- }
首先,/db 将告诉您数据库的分片参数:
- curl -s $COUCH_URL:5984/db | jq .
- {
- "db_name": "mydb",
- ...
- "cluster": {
- "q": 8,
- "n": 3,
- "w": 2,
- "r": 2
- }, ...
- }
因此, 我们知道此数据库是由 8 个分片 (q=8) 建的, 每个分片具有 3 个副本(n=3), 集群中节点之间总共有 24 个分片副本.
现在, 让我们看一下这些分片副本如何通过 / db/_shards 端点放置在集群上:
- curl -s $COUCH_URL:5984/mydb/_shards | jq .
- {
- "shards": {
- "00000000-1fffffff": [
- "node1@127.0.0.1",
- "node2@127.0.0.1",
- "node4@127.0.0.1"
- ],
- "20000000-3fffffff": [
- "node1@127.0.0.1",
- "node2@127.0.0.1",
- "node3@127.0.0.1"
- ],
- ...
- }
- }
现在我们看到该集群中实际上有 4 个节点, 并且 CouchDB 已将这 24 个分片副本均匀地分布在所有 4 个节点上.
我们还可以确切地看到哪个分片包含具有 / db/_shards/doc 端点的给定文档:
- curl -s $COUCH_URL:5984/mydb/_shards/joan | jq .
- {
- "range": "e0000000-ffffffff",
- "nodes": [
- "node1@127.0.0.1",
- "node3@127.0.0.1",
- "node4@127.0.0.1"
- ] }
- $ curl -s $COUCH_URL:5984/mydb/_shards/robert | jq .
- {
- "range": "60000000-7fffffff",
- "nodes": [
- "node1@127.0.0.1",
- "node3@127.0.0.1",
- "node4@127.0.0.1"
- ]
- }
CouchDB 向我们展示了两个示例文档中每个映射到的特定分片.
移动一个分片
本节介绍如何手动放置和更换碎片. 当您确定群集太大或太小, 并且想要成功调整其大小, 或者从服务器指标中注意到数据库 / 碎片布局不是最佳的, 并且您需要一些 "热点" 时, 这些活动是至关重要的步骤 解决.
考虑一个 q=8 和 n=3 的三节点群集. 每个数据库有 24 个分片, 分布在三个节点上. 如果将第四个节点添加到集群, 则 CouchDB 不会将现有数据库分片重新分配给该集群. 这将导致负载不平衡, 因为新节点将仅托管其加入集群后创建的数据库的分片. 为了平衡现有数据库中的分片分布, 必须手动移动它们.
在集群中的节点上移动分片涉及以下几个步骤:
确保目标节点已经加入集群
将分片和任何辅助索引分片复制到目标节点上.
设置目标节点为维护模式.
更新集群元数据反映新的目标分片.
监视内部复制以确保最新的分片.
清除目标节点的维护模式.
再次更新集群元数据移除原分片.
移除原节点的分片和任何辅助索引分片.
拷贝分片文件
从技术上讲, 复制数据库和辅助索引碎片是可选的. 如果在不执行此数据副本的情况下继续进行下一步, 则 CouchDB 将使用内部复制来填充新添加的分片副本. 但是, 复制文件的速度比内部复制快, 尤其是在繁忙的群集上, 这就是为什么我们建议首先执行此手动数据复制的原因.
碎片文件位于 CouchDB 安装目录的 data/shards 目录中. 这些子目录中包含分片文件本身. 例如, 对于一个名为 abc 的 q=8 数据库, 这是其数据库分片文件:
- data/shards/00000000-1fffffff/abc.1529362187.couch
- data/shards/20000000-3fffffff/abc.1529362187.couch
- data/shards/40000000-5fffffff/abc.1529362187.couch
- ...
辅助索引 (包括 JavaScript 视图, Erlang 视图和 Mango 索引) 也被分片, 并且应移动它们的分片以节省新节点重建视图的工作量. 查看 data/. 中的分片. 例如:
- data/.shards
- data/.shards/e0000000-ffffffff/_replicator.1518451591_design
- data/.shards/e0000000-ffffffff/_replicator.1518451591_design/mrview
- data/.shards/e0000000-ffffffff/_replicator.1518451591_design/mrview/3e823c2a4383ac0c18d4e574135a5b08.view
- ...
由于它们是文件, 因此可以使用 cp,rsync,scp 或其他文件复制命令将它们从一个节点复制到另一个节点. 例如:
- # 1 主机
- $ mkdir -p data/.shards/<range>
- $ mkdir -p data/shards/<range>
- # 2 主机
- $ scp <couch-dir>/data/.shards/<range>/<database>.<datecode>* \
- <node>:<couch-dir>/data/.shards/<range>/
- $ scp <couch-dir>/data/shards/<range>/<database>.<datecode>.couch \
- <node>:<couch-dir>/data/shards/<range>/
先移动视图文件再移动数据库文件! 如果视图索引在其数据库之前, 则数据库将从头开始重建它.
设置目标节点为维护模式
在告诉 CouchDB 节点上的这些新分片之前, 必须将节点置于维护模式. 维护模式指示 CouchDB 返回 404 Not Found 响应在 /_up 端点, 并确保其不参与其分片的常规交互式集群请求. 使用 GET/_up 检查节点的运行状况的正确配置的负载均衡器将检测到此 404 并将该节点从循环中删除, 从而阻止将请求发送到该节点. 例如, 要将 HAProxy 配置为使用 /_up 端点, 请使用:
- http-check disable-on-404
- option httpchk GET /_up
如果未设置维护模式, 或者负载平衡器忽略了此维护模式状态, 则在执行下一步之后, 群集在咨询相关节点时可能会返回错误的响应. 不要这样做! 在接下来的步骤中, 我们将确保此分片是最新的, 然后再允许其参与最终用户的请求.
启用维护模式:
curl -X PUT -H "Content-type: application/json" \ $COUCH_URL:5984/_node/<nodename>/_config/couchdb/maintenance_mode \ -d "\"true\""
然后, 通过在该节点的单个端点上执行 GET/_up 来验证该节点是否处于维护模式:
- curl -v $COUCH_URL/_up
- ...
- <HTTP/1.1 404 Object Not Found
- ...
- {
- "status":"maintenance_mode"
- }
最后, 检查负载均衡器是否已从可用后端节点池中删除了该节点.
更新集群元数据反映新的目标分片.
现在我们需要告诉 CouchDB, 目标节点 (必须已经加入集群) 应该为给定数据库托管碎片副本.
要更新群集元数据, 请使用特殊的 /_dbs 数据库, 该数据库是内部 CouchDB 数据库, 它将数据库映射到分片和节点. 该数据库在节点之间复制. 它只能通过节点本地端口 (通常是端口 5986) 进行访问. 默认情况下, 出于安全目的, 此端口仅在 localhost 接口上可用.
首先, 检索数据库的当前元数据:
- curl http://localhost:5986/_dbs/{name}
- {
- "_id": "{name}",
- "_rev": "1-e13fb7e79af3b3107ed62925058bfa3a",
- "shard_suffix": [46, 49, 53, 51, 48, 50, 51, 50, 53, 50, 54],
- "changelog": [
- ["add", "00000000-1fffffff", "node1@xxx.xxx.xxx.xxx"],
- ["add", "00000000-1fffffff", "node2@xxx.xxx.xxx.xxx"],
- ["add", "00000000-1fffffff", "node3@xxx.xxx.xxx.xxx"],
- ...
- ],
- "by_node": {
- "node1@xxx.xxx.xxx.xxx": [
- "00000000-1fffffff",
- ...
- ],
- ...
- },
- "by_range": {
- "00000000-1fffffff": [
- "node1@xxx.xxx.xxx.xxx",
- "node2@xxx.xxx.xxx.xxx",
- "node3@xxx.xxx.xxx.xxx"
- ],
- ...
- }
- }
这是该文档的简要剖析:
_id: 数据库的名字
_rev: 元数据的当前版本
shard_suffix: 数据库创建时的时间戳, 在 Unix 时期映射到 ASCII 数字的代码点后的秒.
changelog: 数据库分片的历史
by_node: 每个节点的分片列表
by_range: 每个分片由哪些节点持有.
要反映元数据中的分片移动, 请执行以下三个步骤:
添加合适的 changelog 实体.
更新 by_node 实体.
更新 by_range 实体.
在修改时, 此过程必须手动完成.
要将分片添加到节点, 请将以下条目添加到数据库元数据的 changelog 属性中:
- ["add", "<range>", "<node-name>"]
- <range > 是特定的硬范围设置.<node-name > 应该与集群中 GET/_membership 中显示的节点的名称和地址匹配.
如果从节点移除一个分片, 简单地将 add 替换为 remove.
找到新的变更日志条目后, 将需要更新 by_node 和 by_range 以反映谁在存储哪些分片. 更改日志条目中的数据和这些属性必须匹配. 否则, 数据库可能会损坏.
继续我们的示例, 这是上面的元数据的更新版本, 该版本将分片添加到名为 node4 的其他节点中:
- {
- "_id": "{name}",
- "_rev": "1-e13fb7e79af3b3107ed62925058bfa3a",
- "shard_suffix": [46, 49, 53, 51, 48, 50, 51, 50, 53, 50, 54],
- "changelog": [
- ["add", "00000000-1fffffff", "node1@xxx.xxx.xxx.xxx"],
- ["add", "00000000-1fffffff", "node2@xxx.xxx.xxx.xxx"],
- ["add", "00000000-1fffffff", "node3@xxx.xxx.xxx.xxx"],
- ...
- ["add", "00000000-1fffffff", "node4@xxx.xxx.xxx.xxx"]
- ],
- "by_node": {
- "node1@xxx.xxx.xxx.xxx": [
- "00000000-1fffffff",
- ...
- ],
- ...
- "node4@xxx.xxx.xxx.xxx": [
- "00000000-1fffffff"
- ]
- },
- "by_range": {
- "00000000-1fffffff": [
- "node1@xxx.xxx.xxx.xxx",
- "node2@xxx.xxx.xxx.xxx",
- "node3@xxx.xxx.xxx.xxx",
- "node4@xxx.xxx.xxx.xxx"
- ],
- ...
- }
- }
现在可以 PUT 新元数据:
curl -X PUT http://localhost:5986/_dbs/{name} -d '{...}'
强制同步分片
无论您是否将分片预先复制到新节点, 都可以强制 CouchDB 同步所有分片的所有副本.
具有 / db/_sync_shards 端点的数据库中的分片:
- curl -X POST $COUCH_URL:5984/{
- dbname
- }/_sync_shards
- {
- "ok":true
- }
这将启动同步过程. 请注意, 这将给群集增加额外的负载, 这可能会影响性能.
通过写入存储在该分片中的文档, 也可以在每个分片的基础上强制进行同步.
监视内部复制以确保最新的分片
完成上一步后, CouchDB 将开始同步分片. 可以通过监视 /_node/<nodename>/_system 端点 (包括 internal_replication_jobs 指标) 来观察这种情况.
一旦此指标从开始分片同步之前返回到基线, 或者为 0, 分片副本就可以提供数据了, 我们可以使节点退出维护模式.
清除目标节点的维护模式
现在, 可以像在步骤 2 中一样, 通过在维护模式配置端点上放置 false, 使节点开始为数据请求提供服务.
通过在该节点的单个端点上执行 GET/_up 来验证该节点是否不在维护模式下. 最后, 检查负载均衡器是否已将该节点返回到可用后端节点池中.
再次更新集群元数据移除原分片
现在, 以与在步骤 2 中将新目标分片添加到分片图中相同的方式, 从分片图中删除源分片. 确保将 ["remove",<range>,<source-shard>] 条目添加到 更改日志的末尾, 以及修改数据库元数据文档的 by_node 和 by_range 部分.
移除原节点的分片和任何辅助索引分片
最后, 可以通过从源主机上的命令行中删除源碎片副本的文件以及任何视图碎片副本来删除源碎片副本:
- rm <couch-dir>/data/shards/<range>/<dbname>.<datecode>.couch
- rm -r <couch-dir>/data/.shards/<range>/<dbname>.<datecode>*
恭喜你! 您已经移动了数据库分片副本. 通过以这种方式添加和删除数据库分片副本, 您可以更改集群的分片布局, 也称为分片映射.
指定数据库放置位置
您可以配置 CouchDB, 以使用放置规则在数据库创建时将碎片副本放置在某些节点上.
首先, 每个节点必须标记有 zone 属性. 这定义了每个节点所在的区域. 您可以通过编辑 /_nodes 数据库中的节点文档来实现, 该文档可通过本地节点端口进行访问. 添加以下形式的键值对:
"zone": "{zone-name}"
在集群中的每一个节点都这样做:
- curl -X PUT http://localhost:5986/_nodes/<node-name> \ -d '{ \
- "_id": "<node-name>",
- "_rev": "<rev>",
- "zone": "<zone-name>"
- }'
在每个节点的本地配置文件 (local.INI) 中, 定义一个一致的群集范围设置, 例如:
- [cluster]
- placement = <zone-name-1>:2,<zone-name-2>:1
在此示例中, CouchDB 将确保将分区的两个副本托管在区域属性设置为 < zone-name-1 > 的节点上, 并将一个副本托管在新的区域属性设置为 < zone-name-2 > 的节点上.
这种方法非常灵活, 因为您还可以在创建数据库时使用与 INI 文件相同的语法, 通过将放置设置指定为查询参数来基于每个数据库指定区域:
curl -X PUT $COUCH_URL:5984/<dbname>?zone=<zone>
也可以指定放置参数. 请注意, 这将覆盖确定已创建副本的数量!
请注意, 您还可以使用此系统来确保群集中的某些节点不为新主机托管任何副本.
通过为它们提供一个不会出现在 [cluster] 放置字符串中的 zone 属性, 来创建数据库.
修改数据库到一个新的 q 值
数据库的 q 值只能在创建数据库时设置, 不能进行实时重新分片. 相反, 要重新分片数据库, 必须重新生成它. 步骤如下:
通过在 PUT 操作期间将 q 值指定为查询参数来创建具有所需分片设置的临时数据库.
停止客户端访问数据库
将主数据库复制到临时数据库. 如果主数据库正在使用中, 则可能需要多次复制.
删除主数据库, 确保没有人在使用!
使用所需的分片设置重新创建主数据库.
客户端现在可以再次访问数据库.
将临时数据库复制回主数据库.
删除临时数据库.
一旦完成所有步骤, 即可再次使用该数据库. 集群将根据放置规则自动创建并分发其碎片.
如果可以指示客户端应用程序使用新数据库而不是旧数据库, 并且可以在非常短暂的中断窗口内进行切换, 则可以避免生产中的停机时间.
集群清除
群集清除的主要目的是清除具有多个删除的逻辑删除或包含大量冲突的单个文档的数据库. 但是, 它也可以用于清除具有任何修订版本的任何文档(已删除或未删除).
群集清除旨在维护最终的一致性并防止不必要的二级索引无效. 为此, 每个数据库都会跟踪数据库中请求的一定数量的历史清除以及其当前的 purge_seq. 内部复制和二级索引处理数据库的清除, 并定期更新其相应的清除检查点文档以报告由其处理的 purge_seq. 为了确保最终的一致性, 数据库将仅在内部复制作业和二级索引处理了存储的历史清除请求之后, 才删除它们.
内部结构
为了在节点和二级索引之间实现内部清除信息的复制, 将两个内部清除树添加到数据库文件中以跟踪历史清除.
- purge_tree: UUID -> {
- PurgeSeq, DocId, Revs
- }
- purge_seq_tree: PurgeSeq -> {
- UUID, DocId, Revs
- }
每次对_purge API 的交互式请求, 都会在增加 purge_seq 和 purge_request 时创建成对的有序集合, 其中 purge_request 是一个包含 docid 和修订列表的元组. 对于每个 purge_request 都会生成 uuid. 清除请求将添加到内部清除树: 将元组 {UUID-> {PurgeSeq,DocId,Revs}} 添加到 purge_tree, 元组 {PurgeSeq-> {UUID,DocId,Revs}}添加到 purge_seq_tree.
压缩清除
在数据库压缩期间, 最旧的清除请求将被删除, 以仅在数据库中存储 purged_infos_limit 个清除数目. 但是, 为了使数据库与索引和其他副本保持一致, 我们只能删除索引和内部复制作业已处理的清除请求. 因此, 有时清除树可能存储的数据超过 purged_infos_limit 清除数目. 如果数据库中存储的清除数量超出 purged_infos_limit 某个阈值, 则日志中会产生警告, 表明数据库的清除与索引和其他副本的同步问题.
本地清除检查点文档
具有清除的数据库索引和内部复制会创建并定期更新本地检查点清除文档:_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"
- }
内部复制
清除请求将以最终一致的方式在所有节点上重播. 清除的内部复制包括两个步骤:
1. 拉取复制. 内部复制首先要从目标中清除并将其应用于源, 以确保我们不会重新引入目标中已清除的源文档 / 修订版. 在这一步中, 我们使用存储在目标上的清除检查点文档来跟踪源处理的最后一个目标的 purge_seq. 我们发现清除请求在此 purge_seq 之后发生, 并在源上重播它们. 通过使用最新进程 purge_seq 和时间戳更新目标的检查点清除文档来完成此步骤.
2. 推送复制. 然后, 内部复制将照常进行, 并插入一个额外的步骤以将源的清除请求推送到目标. 在此步骤中, 我们使用本地内部复制检查点文档, 这些文档在目标和源上均已更新.
在正常情况下, 交互式清除请求已发送到包含数据库碎片副本的每个节点, 并应用于每个副本. 节点之间清除的内部复制只是确保副本之间一致性的一个额外步骤, 在此副本上, 一个节点上的所有清除请求都会在另一个节点上重播. 为了不在副本上重播相同的清除请求, 每个交互式清除请求都用唯一的 uuid 标记. 内部复制会过滤出副本的 purge_tree 中已存在的 UUID 的清除请求, 并仅应用 purge_tree 中不存在的 UUID 的清除请求. 这就是为什么我们需要有两个内部清除树的原因: 1)purge_tree:{UUID-> {PurgeSeq,DocId,Revs}}可以快速找到带有已存在的 UUID 的 purge requests 存在的副本; 2)purge_seq_tree:{PurgeSeq-> {UUID,DocId,Revs }}允许从给定的 purge_seq 进行迭代, 以收集在此 purge_seq 之后发生的所有清除请求.
索引
每个清除请求将增加数据库的 update_seq, 以便还更新每个辅助索引, 以便应用清除请求以维护主数据库内的一致性.
配置设置
这些设置可以在 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'"
如果发生这种类型的日志警告, 请从数据库中删除本地清除文档.
来源: https://www.cnblogs.com/cbkj-xd/p/12077054.html