MongoDB Helm 升级,主从仲裁架构,是否会出现宕机?

问题描述 投票:0回答:3

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

但是,作为注释,他们在升级时提到了这一点:

注意:如果启用了仲裁器且 MongoDB 副本数量为 2,则更新会使 MongoDB 副本集脱机。 Helm 同时对 MongoDB 实例和 Arbiter 的有状态集应用更新,因此您失去了三分之二的法定投票。

我不确定“使副本集离线”实际上意味着什么:

  1. 是否整个 mongo 服务都离线/关闭,因此在执行 helm 升级时服务会出现停机?

  2. 是否在执行升级时,副本集将只有一个 mongodb 服务器在工作,而另一台 mongodb 服务器和仲裁器都处于离线状态并正在升级?在这种情况下,它并不意味着停机,只是暂时只有一台服务器可用(而不是两台),与独立设置类似。

mongodb kubernetes kubernetes-helm bitnami
3个回答
2
投票

Bitnami 开发者在这里

在执行升级时,副本集是否会具有 只有一台 mongodb 服务器在工作,而另一台 mongodb 服务器都在工作 和仲裁者,是否已离线并正在升级?

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

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

正如之前的回复中提到的,如果未满足活动副本的最小法定数量,则确实意味着短暂的停机时间。


1
投票

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

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

独立的进程在启动时就会接受写入。副本集节点仅在为主节点时才接受写入,并且要拥有主节点,大多数节点必须处于运行状态。因此,如果副本集的三个节点中只有一个启动,则不可能有主节点,并且没有节点将接受写入。

在三个节点中有一个可用的情况下,如果该节点是数据承载的,您仍然可以使用允许辅助读取首选项(主要首选或次要或次要首选)发出读取,但主要读取将不起作用,写入也将不起作用工作。


0
投票

对于任何尝试在不停机的情况下升级 bitnami mongoDB Helm Chart 的人,这里有一些我用来在理论上尽可能地在 PSA 结构下消除它的技巧。

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

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

这里是一个示例脚本,您可以作为 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 图表参数:

extraVolumeMounts
extraVolumes
。将您的脚本打包到单独的包中,例如
default/mongodb-addon
。下面是一个修补 StatefulSet 以使用 helmfiles 配置的示例:

- 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 Arbiter 似乎没有按预期工作。例如,如果您要从 4.2 升级到 4.4,如果 Arbiter 映像升级到 4.4,则不会使用 FCV 4.2,因此 replset 无法恢复到健康状态并阻止我们设置中的升级。

我们目前的解决方案是再次打补丁,并将仲裁器版本固定为4.2,先滚动数据承载节点,待一切稳定后删除补丁。

© www.soinside.com 2019 - 2024. All rights reserved.