MongoDB的Helm升级具有主从仲裁器架构,是否存在停机时间



我正在考虑在K8s中设置一个bitnami mongodb复制集,如下所述。

然而,值得注意的是,他们在升级时提到了这一点:

注意:如果启用了仲裁器,并且MongoDB副本的数量为两个,则更新会使您的MongoDB副本集离线。Helm同时对MongoDB实例和仲裁器的状态集进行更新,因此您可以获得三分之二的法定投票。

我不确定它实际上是什么意思";使复制集离线":

  1. 是不是整个mongo服务离线/停机,因此在执行helm升级时服务会停机?

  2. 是不是在执行升级时,复制集只有一个mongodb服务器在工作,而另一个mongo db服务器和仲裁器都处于脱机状态并正在升级?。在这种情况下,这并不意味着停机,只是暂时只有一台服务器可用(而不是两台),因此类似于独立设置。

Bitnami开发者此处

是不是在执行升级时,复制集将具有只有一个mongodb服务器工作,而两个都工作,另一个mongo数据库服务器和仲裁器,是否处于离线状态并正在升级?

这将取决于您有多少副本。如果你安装的图表有2个副本+1个仲裁器,是的,这意味着。但是,如果您安装的图表有4个副本+1个仲裁器,则只有1个副本和仲裁器同时重新启动,其他3个副本都已启动。

在这种情况下,这并不意味着停机,只是暂时的只有一台服务器可用(而不是两台),因此类似于独立设置。

正如前面的响应中所提到的,如果不能满足活动副本的最低法定数量,这确实意味着一个小的停机时间。

我不知道Helm是什么,它做什么,也不知道为什么它一次关闭两个节点,但是:

在这种情况下,这并不意味着停机,只是暂时只有一台服务器可用(而不是两台),因此类似于独立设置。

无论何时,独立程序都会接受写入。只有当副本集节点是主节点时,副本集节点才接受写入,并且要拥有主节点,大多数节点都必须处于活动状态。因此,如果复制副本集的三个节点中只有一个节点已启动,则不可能存在主节点,也不会有任何节点接受写入。

在三分之一节点可用的情况下,如果此节点是数据承载节点,则您仍然可以使用辅助允许读取首选项(主首选项或辅助或辅助首选项)进行读取,但主读取不起作用,写入也不起作用。

对于任何试图在没有停机的情况下升级bitnami mongoDB helm chart的人,以下是我用来在PSA结构下尽可能消除的一些技巧。

bitnami图表的主要问题是仲裁器和数据节点是两个独立的StatefulSet(mongodb和mongodb仲裁器),因此任何使用helm的更新都会导致两个StatefulSets进入升级状态,并且在一段时间内可能只有一个数据节点在线。根据定义,一个数据节点的复制集将无法选择新的主节点,因此不健康。

为了维护主节点,复制集中每次只能有一个节点停机,因此您可以在关闭数据节点时添加一些延迟,这样仲裁器将比任何数据节点关闭更快地关闭和备份。您可以简单地使用PreStop挂钩。然而,我在关闭之前做了一些检查——基本上确保当数据节点关闭时,复制集中的每个成员都应该是健康的。

下面是一个可以作为PreStop钩子运行的示例脚本,请记住相应地调整terminationGracePeriodSeconds,以考虑到实例在给定时间内没有停止的一些情况。

const startTime = Date.now();
const timeLeft = () => Math.round((Date.now() - startTime) / 1000);
let success = 0;
let failedTimes = 0;
const sleepTime = 60; // seconds
// Match graceful shutdown time here
const forceKillTime = 60; // 60 mins
const exitGap = 5; // Leave 5 minutes just in case
const exitTime = forceKillTime * 60 - exitGap * 60;
const CONSECUTIVE_SUCCESS = 5;
while (true) {
const elapsedTime = (Date.now() - startTime) / 1000;
if (elapsedTime > exitTime) {
print(
`Operation does not finished within time frame: Elapsed(${elapsedTime}) > exit(${exitTime})`
);
quit(1);
}
const res = rs.status();
if (res.members) {
const everyoneIsHealthy = res.members.every((obj) => obj.health === 1);
if (everyoneIsHealthy) {
success += 1;
if (success >= CONSECUTIVE_SUCCESS) {
print(
`success count (${success} >= ${CONSECUTIVE_SUCCESS}) larger than threshold, proceeed with shutdown`
);
// First, we try to step down
// Then, we go ahead to shutdown ourselves
db.adminCommand({
replSetStepDown: timeLeft() + 60, // add some space just in case
secondaryCatchUpPeriodSecs: timeLeft() - 60,
force: false,
});
// If step down has timeout, we basically cannot do anything but proceed to force shutdown anyway
// to ensure the shutdown happened. However the final killoff is done by k8s, shutdown is also for
// index task to wrap up, etc.
db.shutdownServer({
timeoutSec: timeLeft(),
});
} else {
print(
`success count (${success} < ${CONSECUTIVE_SUCCESS}), keep checking...`
);
}
} else {
success = 0;
failedTimes += 1;
print(`[Failed ${failedTimes}] not everyone is healthy, reset counter `);
}
} else {
success = 0;
failedTimes += 1;
print(`[Failed ${failedTimes}] members info not available, retrying...`);
}
sleep(sleepTime * 1000);
}

要装载脚本,可以使用bitnami图表参数:extraVolumeMountsextraVolumes。将脚本打包到一个单独的包中,例如default/mongodb-addon。以下是一个修补StatefulSet以使用helmfiles-config:的示例

- name: mongodb
needs:
- default/mongodb-addon
namespace: default
version: 9.0.1
chart: bitnami-full-index/mongodb
strategicMergePatches:
- apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mongodb
namespace: default
spec:
template:
spec:
# If this value changed, changed the shutdown script timer as well
terminationGracePeriodSeconds: 3600 # 60 minutes
containers:
- name: mongodb
lifecycle:
preStop:
exec:
command:
- /bin/bash
# Write some wrapper scripts to execute on *local* container instance only, do not connect as replicaset mode!
# such as bash -c "mongosh 'mongodb://localhost' $SCRIPT_DIR/shutdown.js"
- /scripts/shutdown.sh

不过,你可以通过在挂钩中添加一些睡眠来省去这些麻烦,在我看来,这可能会很好。如果一切顺利,在所有实例都已正确关闭的情况下,您的复制集不应该丢失主副本。实例关闭意味着逐步关闭。


这里的另一个注意事项是mongoDB仲裁器似乎没有按预期工作。例如,如果您从4.2升级到4.4,如果Arbiter映像升级到4.4则不需要FCV 4.2,因此replset无法恢复到正常状态,并在我们的设置中阻止升级。

我们目前的解决方案是再次修补图表,并将仲裁器版本固定到4.2,首先滚动数据承载节点,然后在一切稳定时删除补丁。

相关内容

最新更新