代码改变世界

MongoDB副本集故障切换期间的回滚

2024-09-22 14:48  abce  阅读(69)  评论(0编辑  收藏  举报

每当复制集在选举中替换主节点时,旧主节点可能包含未复制到辅助节点的文档。在这种情况下,旧的主节点会回滚这些写入内容。在回滚过程中,节点将处于 ROLLBACK 状态。处于 ROLLBACK 状态的节点有资格在选举中投票。

 

从 4.2 版开始,当节点进入 ROLLBACK 状态时,MongoDB 会杀死所有正在进行的用户操作。

 

当主节点在故障切换后重新加入其副本集时,回滚会恢复前主节点上的写操作。只有当主节点接受了写操作,辅助节点在主节点停机前未成功复制写操作时,才有必要进行回滚。当主节点作为辅助节点重新加入副本集时,它会恢复或 "回滚 "其写操作,以保持与其他成员数据库的一致性。

 

MongoDB 会尽量避免回滚,因为这种情况很少发生。当发生回滚时,通常是由于网络分区造成的。辅助节点如果跟不上前主节点的操作吞吐量,就会增加回滚的规模和影响。

 

如果写操作在主服务器宕机前复制到副本集的另一个成员,且该成员对副本集的大部分成员仍然可用和可访问,则不会发生回滚。

 

收集回滚数据

配置回滚数据

createRollbackDataFiles 参数控制回滚过程中是否创建回滚文件。

> db.adminCommand({ getParameter: 1, createRollbackDataFiles: 1 })
{
  createRollbackDataFiles: true,
  ok: 1,
  '$clusterTime': {
    clusterTime: Timestamp({ t: 1726916568, i: 1 }),
    signature: {
      hash: Binary(Buffer.from("bda9d6f7fe20bbdf720debb782564bceea36638b", "hex"), 0),
      keyId: Long("7353838889632530433")
    }
  },
  operationTime: Timestamp({ t: 1726916568, i: 1 })
}

 

回滚数据

默认情况下,回滚发生时,MongoDB 会将回滚数据写入 BSON 文件。

 

对于数据被回滚的每个集合,回滚文件位于 <dbpath>/rollback/<collectionUUID> 目录中,文件名为

removed.<timestamp>.bson

 

例如,如果数据库reporting中的集合comments的数据回滚了

<dbpath>/rollback/20f74796-d5ea-42f5-8c95-f79b39bad190/removed.2020-02-19T04-57-11.0.bson

 

查看集合名称

要获取集合名称,可以在 MongoDB 日志中搜索回滚文件。例如,如果日志文件是 /var/log/mongodb/mongod.log,可以使用 grep 在日志中搜索 "rollback file "实例:

grep "rollback file" /var/log/mongodb/mongod.log

 

或者,也可以在所有数据库中循环运行 db.getCollectionInfos(),查找特定的 UUID,直到找到匹配为止。例如

var mydatabases=db.adminCommand("listDatabases").databases;
var foundcollection=false;

for (var i = 0; i < mydatabases.length; i++) {
   let mdb = db.getSiblingDB(mydatabases[i].name);
   collections = mdb.getCollectionInfos( { "info.uuid": UUID("20f74796-d5ea-42f5-8c95-f79b39bad190") } );

   for (var j = 0; j < collections.length; j++) {   // Array of 1 element
      foundcollection=true;
      print(mydatabases[i].name + '.' + collections[j].name);
      break;
   }

   if (foundcollection) { break; }
}

 

回滚数据排除

如果要回滚的操作是被删除集合或删除文档,则不会将回滚写入回滚数据目录。

 

读取回滚数据

要读取回滚文件的内容,请使用 bsondump。

 

避免副本集回滚

对于副本集,写关注 { w: 1 } 只提供对主数据写操作的确认。如果主服务器在写操作复制到任何辅助服务器之前宕机,数据可能会回滚。这包括在使用 { w: 1 } 写关注提交的多文档事务中写入的数据。

 

日志和写关注多数

为防止已向客户端确认的数据回滚,所有投票成员应启用日志功能,并使用 { w: "majority" } 写关注,以确保写操作在返回给客户端之前,传播到大多数副本集节点。

 

从 MongoDB 5.0 开始,{ w: "majority" } 是大多数 MongoDB 部署的默认设置。

 

当 writeConcernMajorityJournalDefault 设置为 false 时,MongoDB 在写入操作ack之前不会等待w: "majority"写关注写入磁盘日志。因此,写操作可能会回滚。

 

回滚注意事项

用户的操作

从 4.2 版开始,当成员进入 ROLLBACK 状态时,MongoDB 会终止所有正在进行的用户的操作。

 

索引的构建

对于FCV是4.2的,MongoDB 会等待任何正在进行的索引构建完成后才开始回滚。

 

禁用"majority"读关注会阻止修改索引的 collMod 命令回滚。如果需要回滚此类操作,必须将受影响的节点与主节点重新同步。

 

大小限制

MongoDB 支持以下具有不同大小限制的回滚算法:

·恢复到某个时间戳,这是默认的回滚算法。使用这种算法时,MongoDB 不会限制回滚的数据量。

·通过重新获取(Refetch)回滚,只有当配置文件中的 enableMajorityReadConcern 设置为 false 时,才会通过 Refetch 进行回滚。使用此算法时,MongoDB 最多只能回滚 300 MB 的数据。从 MongoDB 5.0 开始,enableMajorityReadConcern 设置为 true,且不可更改。

 

回滚运行时间限制

回滚时间限制默认为 24 小时,可使用 rollbackTimeLimitSecs 参数进行配置。

> db.adminCommand({ getParameter: 1, rollbackTimeLimitSecs: 1 })
{
  rollbackTimeLimitSecs: 86400,
  ok: 1,
  '$clusterTime': {
    clusterTime: Timestamp({ t: 1726918891, i: 363 }),
    signature: {
      hash: Binary(Buffer.from("32f85ab925666561ffec530b73d70703dd3dcf3c", "hex"), 0),
      keyId: Long("7353838889632530433")
    }
  },
  operationTime: Timestamp({ t: 1726918891, i: 363 })
}