MongoDB:当Primary失败时
MongoDB: When Primary fails
我想了解 MongoDB 提供了哪些保证,如果有的话,因为它与数据的持久性有关,在这种情况下,当主节点永久或暂时出现故障时,或者当它在网络级别与主节点分离时副本集的其余部分。
我了解 w:1 写关注会发生什么。我明白日记的作用。
我不明白 MongoDB 如何决定在选择新主节点时保留哪些写入以及丢弃哪些写入。在一个 4 节点(+arbiter)集群中,N1 为主节点,N2、N3、N4 为辅助节点,在这种情况下:
- {w:majority, j:true} 写入命中主节点。
- 次要轮询变化,主要等待多数人确认。
- N2 确认更改。
- N3 已收到更改并正在应用它。
- 主节点出现故障。
- N3 无法向主节点确认它已应用更改。
- 选举是被迫的。
问题:
- 选举完成后写入是否可用?
- 哪个节点将成为新的主节点重要吗?
- 如果没有执行第 4 步,结果会有所不同吗?
- 如果 Primary 已收到来自 N3 的确认,结果是否不同?
- 如果 Primary 确认了写入,而 N2 复制了写入得到多数人确认的事实,结果是否不同?
- 如果 N2 和 N3 都复制了写入被多数人确认的事实,结果是否不同?
首先是一些背景:
mongodb 副本集使用操作日志进行复制。主节点的每次写入都附加到操作日志。
每个辅助节点查询其同步源以获取 oplog 条目,批量检索和应用它们。
Oplog 条目是幂等的,必须按顺序应用。
在将条目写入 oplog 本身之前,它们首先写入日志。
如果节点在应用批次时崩溃,则可以安全地从日志中重放整个批次,因为每个条目都是幂等的。
成员互相报告他们最近应用的oplog事件的标识符。
由于必须按顺序应用 oplog 事件,这意味着每个节点都应用了报告条目之前的所有条目,并且 none 自此。
在一个 5 节点的副本集中,大多数是 3 个节点。在大多数节点报告其操作日志已达到或超过添加写入的点之前,主节点不会向 client/application 确认 w:majority
写入已完成。
副本集中的每个节点监控每个其他成员。
如果主要节点意识到它无法与大多数投票节点通信,它将降级为次要节点。
如果一个次要的to/from主没有任何通信几秒钟(默认10秒),它会要求选举。
发起选举的节点将向每个副本集成员征集选票。
每个成员通常都会投“赞成”票,他们投“反对票”的几个原因是:
- 候选人的最新oplog条目不等于或比其他节点更新
- 该节点当前正在与优先级等于或高于候选节点的主节点进行通信
如果候选节点收到足够的 'Yes' 票以构成副本集中的大多数投票节点,它将转换为主要节点并接受写入。
每次选举都会增加副本集的 term
值。 If the primary receives a heartbeat or other message from one of the other nodes that contains a higher term than when it was elected, it immediately steps down to secondary.
在您的场景中:
{w:majority, j:true} write hits the Primary.
主要意愿:
- 将写入应用到数据集的本地副本
- 将操作写入日志
- 将操作写入oplog
假设主节点的 oplog 现在包含:
Time
operation
T1
create collection
T2
create index
T3
insert document 1
T4
insert document 2
T5
update document 1
T6
insert document 3
我将使用 T5 的更新作为 w:majority
写入。
Secondaries poll for changes, primary waits for majority to confirm.
- 辅助设备可能不会同时接收数据
- 每个次级可能有不同的最后应用条目
- 辅助节点不会根据写入问题对 oplog 事件做出不同的响应(我认为辅助节点甚至不知道写入问题)
N1 是主要的,N5 是仲裁者。在 T5 写入之前,其余节点显示以下最近应用的 oplog 事件:
N2: T4
N3: T4
N4: T2
N2 confirms the change.
最近应用的 oplog 事件现在是:
N2: T5
N3: T4
N4: T3
N3 has received the change and is in process of applying it.
这意味着 N3 不会向任何其他节点报告新的上次应用的 oplog 时间,并且主节点仍不会向提交写入的应用进程确认成功或失败。
Primary goes down
在主要失败之前的那一刻,每个成员的最后应用 optime 是:
N1:T6
N2: T5
N3: T4
N4: T3
N5:N/A
N3 is unable to confirm to Primary it has applied the change.
情理之中。
Election is forced.
在适当的超时后,一个或多个辅助节点将要求进行选举。
让我们假设 N3 实际上完成了应用来自 T5 的操作。
如果N4刚好是第一个超时的,它会发起选举,要求所有成员投票。投票结果如下:
N4:是(永远投给自己)
N5:否 - 我可以看到一个节点的 oplog 事件比你的更新
N3:不 - 我有一个比你最近的 oplog 事件
N2:否 - 同上
此时接下来将由N2或N3参选,得票情况如下:
候选人 N3:是 - 自己
N5:是 - 你有最近的事件
N4:是的 - 你比我更流行
N2:是的 - 你至少和我一样更新
本次选举成功,节点转主。
如果 N3 应用了来自 T5 的事件,无论它是否已报告给主要事件,都可能发生此事件序列。由于所有节点都监视所有其他节点,因此 N3 会将其报告给 N2、N4 和 N5。
请注意,如果#4 没有发生,N3 仍将处于 T4,并且不会被选举,因为 N2 有一个更新的事件。
无论哪种情况,参与选举的任何次要应用的最近事件都将被保留。
当 N1 恢复并尝试重新加入副本集时,新主服务器上的操作日志很可能已超出 T6。由于当前主节点不知道 T6 的写入,并且之前的主节点不能成为从节点,除非它可以重放当前主节点的 oplog 条目,节点比较它们的 oplog 历史,直到找到一个共同点。
在这种情况下,这将是 T5。
然后前主服务器回滚 T6 操作所做的更改,并将回滚的数据写入本地磁盘文件,以便稍后在必要时恢复。然后它从新的主节点请求 T5 之后的 oplog 条目,并开始作为辅助节点进行复制。
在那种情况下,唯一丢失的写入是由主节点处理但未复制到任何其他节点的写入。
Are results different if Primary has acknowledged the write, and N2 replicated the fact the write was confirmed by majority?
Are results different if both N2 and N3 replicated the fact that the write was confirmed by majority?
这个事实实际上不需要复制。每个节点都在监视彼此的节点,因此每个辅助节点都会很清楚哪些操作日志条目已被大多数副本集看到,而无需被告知。
唯一的区别是,如果 N3 也向主节点报告它已复制该操作,则主节点可以向应用程序报告多数写入已成功。
替代方案
IF:
- #4 没有发生
- 故障是网络分区而不是节点故障
- N1 和 N2 在隔板的一侧,N3、N4、N5 在另一侧
在这种情况下,N1 会意识到它无法联系大多数副本集,因此会下台。
如果 N1 或 N2 试图要求选举,他们将无法获得所需的 3 票
N4 would still not be elected due to being behind N3
当 N3 要求选举时,N4 和 N5 都会投票 'Yes',因此 N3 将成为首选。
这意味着当网络分区被修复时,N1 和 N2 都会发现它们有当前主节点不知道的写入。
在这种情况下,T5 和 T6 写入都将回滚。
我想了解 MongoDB 提供了哪些保证,如果有的话,因为它与数据的持久性有关,在这种情况下,当主节点永久或暂时出现故障时,或者当它在网络级别与主节点分离时副本集的其余部分。
我了解 w:1 写关注会发生什么。我明白日记的作用。
我不明白 MongoDB 如何决定在选择新主节点时保留哪些写入以及丢弃哪些写入。在一个 4 节点(+arbiter)集群中,N1 为主节点,N2、N3、N4 为辅助节点,在这种情况下:
- {w:majority, j:true} 写入命中主节点。
- 次要轮询变化,主要等待多数人确认。
- N2 确认更改。
- N3 已收到更改并正在应用它。
- 主节点出现故障。
- N3 无法向主节点确认它已应用更改。
- 选举是被迫的。
问题:
- 选举完成后写入是否可用?
- 哪个节点将成为新的主节点重要吗?
- 如果没有执行第 4 步,结果会有所不同吗?
- 如果 Primary 已收到来自 N3 的确认,结果是否不同?
- 如果 Primary 确认了写入,而 N2 复制了写入得到多数人确认的事实,结果是否不同?
- 如果 N2 和 N3 都复制了写入被多数人确认的事实,结果是否不同?
首先是一些背景:
mongodb 副本集使用操作日志进行复制。主节点的每次写入都附加到操作日志。
每个辅助节点查询其同步源以获取 oplog 条目,批量检索和应用它们。
Oplog 条目是幂等的,必须按顺序应用。
在将条目写入 oplog 本身之前,它们首先写入日志。
如果节点在应用批次时崩溃,则可以安全地从日志中重放整个批次,因为每个条目都是幂等的。
成员互相报告他们最近应用的oplog事件的标识符。
由于必须按顺序应用 oplog 事件,这意味着每个节点都应用了报告条目之前的所有条目,并且 none 自此。
在一个 5 节点的副本集中,大多数是 3 个节点。在大多数节点报告其操作日志已达到或超过添加写入的点之前,主节点不会向 client/application 确认 w:majority
写入已完成。
副本集中的每个节点监控每个其他成员。
如果主要节点意识到它无法与大多数投票节点通信,它将降级为次要节点。
如果一个次要的to/from主没有任何通信几秒钟(默认10秒),它会要求选举。
发起选举的节点将向每个副本集成员征集选票。
每个成员通常都会投“赞成”票,他们投“反对票”的几个原因是:
- 候选人的最新oplog条目不等于或比其他节点更新
- 该节点当前正在与优先级等于或高于候选节点的主节点进行通信
如果候选节点收到足够的 'Yes' 票以构成副本集中的大多数投票节点,它将转换为主要节点并接受写入。
每次选举都会增加副本集的 term
值。 If the primary receives a heartbeat or other message from one of the other nodes that contains a higher term than when it was elected, it immediately steps down to secondary.
在您的场景中:
{w:majority, j:true} write hits the Primary.
主要意愿:
- 将写入应用到数据集的本地副本
- 将操作写入日志
- 将操作写入oplog
假设主节点的 oplog 现在包含:
Time | operation |
---|---|
T1 | create collection |
T2 | create index |
T3 | insert document 1 |
T4 | insert document 2 |
T5 | update document 1 |
T6 | insert document 3 |
我将使用 T5 的更新作为 w:majority
写入。
Secondaries poll for changes, primary waits for majority to confirm.
- 辅助设备可能不会同时接收数据
- 每个次级可能有不同的最后应用条目
- 辅助节点不会根据写入问题对 oplog 事件做出不同的响应(我认为辅助节点甚至不知道写入问题)
N1 是主要的,N5 是仲裁者。在 T5 写入之前,其余节点显示以下最近应用的 oplog 事件:
N2: T4
N3: T4
N4: T2
N2 confirms the change.
最近应用的 oplog 事件现在是:
N2: T5
N3: T4
N4: T3
N3 has received the change and is in process of applying it.
这意味着 N3 不会向任何其他节点报告新的上次应用的 oplog 时间,并且主节点仍不会向提交写入的应用进程确认成功或失败。
Primary goes down
在主要失败之前的那一刻,每个成员的最后应用 optime 是:
N1:T6
N2: T5
N3: T4
N4: T3
N5:N/A
N3 is unable to confirm to Primary it has applied the change.
情理之中。
Election is forced.
在适当的超时后,一个或多个辅助节点将要求进行选举。
让我们假设 N3 实际上完成了应用来自 T5 的操作。
如果N4刚好是第一个超时的,它会发起选举,要求所有成员投票。投票结果如下:
N4:是(永远投给自己)
N5:否 - 我可以看到一个节点的 oplog 事件比你的更新
N3:不 - 我有一个比你最近的 oplog 事件
N2:否 - 同上
此时接下来将由N2或N3参选,得票情况如下:
候选人 N3:是 - 自己
N5:是 - 你有最近的事件
N4:是的 - 你比我更流行
N2:是的 - 你至少和我一样更新
本次选举成功,节点转主。
如果 N3 应用了来自 T5 的事件,无论它是否已报告给主要事件,都可能发生此事件序列。由于所有节点都监视所有其他节点,因此 N3 会将其报告给 N2、N4 和 N5。
请注意,如果#4 没有发生,N3 仍将处于 T4,并且不会被选举,因为 N2 有一个更新的事件。
无论哪种情况,参与选举的任何次要应用的最近事件都将被保留。
当 N1 恢复并尝试重新加入副本集时,新主服务器上的操作日志很可能已超出 T6。由于当前主节点不知道 T6 的写入,并且之前的主节点不能成为从节点,除非它可以重放当前主节点的 oplog 条目,节点比较它们的 oplog 历史,直到找到一个共同点。
在这种情况下,这将是 T5。
然后前主服务器回滚 T6 操作所做的更改,并将回滚的数据写入本地磁盘文件,以便稍后在必要时恢复。然后它从新的主节点请求 T5 之后的 oplog 条目,并开始作为辅助节点进行复制。
在那种情况下,唯一丢失的写入是由主节点处理但未复制到任何其他节点的写入。
Are results different if Primary has acknowledged the write, and N2 replicated the fact the write was confirmed by majority? Are results different if both N2 and N3 replicated the fact that the write was confirmed by majority?
这个事实实际上不需要复制。每个节点都在监视彼此的节点,因此每个辅助节点都会很清楚哪些操作日志条目已被大多数副本集看到,而无需被告知。
唯一的区别是,如果 N3 也向主节点报告它已复制该操作,则主节点可以向应用程序报告多数写入已成功。
替代方案
IF:
- #4 没有发生
- 故障是网络分区而不是节点故障
- N1 和 N2 在隔板的一侧,N3、N4、N5 在另一侧
在这种情况下,N1 会意识到它无法联系大多数副本集,因此会下台。
如果 N1 或 N2 试图要求选举,他们将无法获得所需的 3 票
N4 would still not be elected due to being behind N3
当 N3 要求选举时,N4 和 N5 都会投票 'Yes',因此 N3 将成为首选。
这意味着当网络分区被修复时,N1 和 N2 都会发现它们有当前主节点不知道的写入。
在这种情况下,T5 和 T6 写入都将回滚。