将MongoDB3.2升级到3.4的工作

QualiArts Advent Calendar 2019 15日目担当の @tnbe21 です。
普段はNode.jsでゲーム機能やLPのサーバ側実装やコードレビューを行ったり
インフラ(ansibleとかterraform、fabricなどIaCやGCP、Jenkinsとか)の保守、
CS対応、PythonとかHiveQLとかで書いてある行動ログ集計バッチの保守など、
あるゲームのサーバーサイドのエンジニアリング全般を主に担当しています。

首先

mcm_01_top.png
    • MCMで主に活用されているのはバックアップ機能のみで、

 

    • クラスタ管理や各インスタンスのバージョン管理など

 

    • フルマネージドされている状態にしたい

 

    • 3.2系のEndOfLifeは昨年の9月、次の3.4系は来年の1月なので、

 

    • 恐らくMCMフルマネージド環境で3.4に出来るデッドラインが来年の1月

 

    • (2月以降はいつまで3.4で構築できるかわからない)

 

    • -> 飛び級でアップデートするのはリスキーなので

 

    ひとつ上の3.4へ来年の1月までにアップデートしたい

この2点を踏まえ来年1月をデッドラインとして
MCMフルマネージドな3.4へリニューアルするための準備をしてきました。
ステージング環境のリニューアル(=本番環境リニューアルのリハーサル)や
その際のフィードバックも加えた手順書の作成や準備は完了しており、
あとは本番環境のリニューアルを待つだけの状況となっています。
その試行錯誤の過程で得られた知見をお話しします。

步骤

创建新的群集

我们有两种选择:要么更新现有的集群,要么创建一个新的集群并迁移数据。然而,从3.4版本开始,需要将mongoc的配置从SCCC模式更改为CSRS模式以保存集群的元数据信息。而且,如果希望将其放在MCM管理下,后续步骤可能会变得复杂。因此,我们决定采取创建新的集群并迁移数据的方法。我们将准备一个新的GCE实例,并安装MCM代理,然后在全新的3.4系列上运行集群。

考虑数据迁移的方法

接下来,我们将考虑数据迁移的方法。
虽然在MCM上进行了备份,但现状仍需要进行数据迁移。

    • 先述の通りmongocが3.4以降未対応のSCCC型だったり、

 

    • mongocのDB(メタ情報DB)や実データRSのバックアップが別れて管理されていた関係か

 

    • MCMコンソール上から新規クラスタへ直接リストアすることが不可能

 

    • (-> だった?最近コンソールを閲覧してみたら可能そうだったかも?別の方法での手順が固まってしまったので未検証)

 

    各RSや設定DBのバックアップをダウンロードしてリストアする方法も難しい
mongodb_migration_by_mcm.png

倾倒车

在迁移服务器上,使用现有集群作为连接目标来启动mongos,并执行mongodump操作。
虽然两者都很简单,但为了预防可能遇到的陷阱,需要提醒的是,

    • 1度でダンプデータがディスクの半分以上を専有し、

 

    • 2度3度と試す機会があったのでダンプの都度過去のデータ削除をしていました

 

    • ディスクフルになりそうになると途中で止まります

 

    データベースを指定して実行(configDBのダンプは不要)
nohup mongodump --db {DB名} --out /data/mongodb/backup_`date +%Y%m%d%H%M` >
/data/mongodb/logs/dump_`date +%Y%m%d%H%M`.log &

在新的集群中为每个集合创建索引和分片键。

接下来,重新启动mongos以面向新的集群,并预先创建目标集合的索引和分片键。

恢复

在执行mongorestore之前,请确保mongos正在新建集群进行启动。

nohup mongorestore -v --writeConcern 1 --numInsertionWorkersPerCollection 8 --db {DB名} /data/mongodb/backup_{yyyymmddhhmm}/{DB名} > /data/mongodb/logs/restore_`date
+%Y%m%d%H%M`.log &

我最初使用的迁移服务器是n1-standard-1,没有指定numInsertionWorkersPerCollection或writeConcern选项进行执行,花费了大约3个半小时。但是,在阅读了grep Tips先生的文章后,我将机器规格更改为n1-standard-8(8核),并设置了这些选项。在预先创建了块信息的情况下执行,文档删除+恢复的时间缩短了1小时和7分之2。这篇文章是追溯。

–numInsertionWorkersPerCollection: 各コレクションにinsertするワーカ数の指定
デフォルトは1で、CPUコア数辺りまでの指定でリストアの高速化が見込めます

–writeConcern: writeConcern の指定
デフォルトはmajority = 所定レプリカセットで投票権をもつメンバの半数以上が
書き込みされたとみなされないと次のinsertに進みません
1を指定することでプライマリメンバに書き込まれた時点で次のinsertに進み、
デフォルトより高速化される見込みです
リストア処理以外での各コレクションへの書き込みがない状態の担保は必要です

考虑到金钱成本的权衡,在增加CPU核心数量和提高并行执行数的选择上,我认为可以在一定程度上缩短恢复时间。

为创建块信息进行预执行。

根据NullPointer’s的文章所述,
预先执行这些操作并提前创建区块信息。
似乎通过在这项工作之前提前执行一次,可以减少恢复所需的时间。

This execution

在执行mongorestore的过程中,需要注意从预先执行的状态到实际执行的过程中,需要删除所有文档,并进行插入操作。

不是删除集合,而是删除文档。

mongorestore命令有一个–drop选项,可以在恢复数据时删除已有的文档,但是我没有指定这个选项。可能是因为它会删除整个集合而不仅仅是文档。
尽管文字上明确写着”drop”,无论多少次看都没注意到,真是感觉有些马虎。
索引会根据mongodump生成的备份数据在恢复时重新设置,但是分片键和分块信息会丢失。

#!/bin/sh

SCRIPT_NAME=remove_`date +%Y%m%d%H%M`.js
cat > $SCRIPT_NAME << EOF
function padZero(v) {
  return v < 10 ? '0' + v : v;
}

function getDt() {
  var date = new Date();
  var ymd = [date.getFullYear(), padZero(date.getMonth() + 1), padZero(date.getDate())];
  var time = [padZero(date.getHours()), padZero(date.getMinutes()), padZero(date.getSeconds())];
  return ymd.join('-') + 'T' + time.join(':');
}

var cols = db.getCollectionNames();
for (var i = 0; i < cols.length; i++) {
  var col = cols[i];
  print(getDt() + ': ' + 'remove ' + col);
  db[col].remove({});
  print(getDt() + ': ' + 'finished removing ' + col);
}
EOF

mongo {db名} $SCRIPT_NAME
rm $SCRIPT_NAME
nohup sh remove.sh > /data/mongodb/logs/remove_`date +%Y%m%d%H%M`.log &

为了停止进行块迁移并在关闭平衡器的情况下,执行类似以下的脚本,先删除文档(比删除后再drop花费更多时间),然后执行mongorestore without –drop。

比较收藏品数量

在完成还原后,尽管无法确认新旧集群中所有文档的值是否一致,但至少可以检查文档的数量。

db.collection.aggregate([
  { $group: { _id: null, count: { $sum: 1 } } }
]);

进行结果比较。
虽然有更简单的命令 db.collection.count();,但在分片群集环境中,
在进行分片迁移时可能会失败并且连同群集管理下的孤立文档(孤兒文件)一同计数,
因此可能无法获取准确的数量。据说采用聚合方式进行上述查询可以更准确。

总结和感想

    • mongocがSCCC型となっている3.2クラスタを3.4にアップデートする関係で、

 

    • MCM管理下で新規クラスタを作成して

 

    • 移行サーバ経由でmongodump -> mongorestoreする手順をとることにした

 

    • mongorestoreはオプションチューニング、サーバのスケールアップで高速化できる

 

    • さらなるリストア高速化のために事前のリストアを実施

本移行時のrestoreでは–dropは指定せず、
全コレクション db.collection.remove({}); をしてから実行する
事前のリハーサルと手順書の作成は本当に大事

虽然在整个数据迁移过程中承受了相当大的压力,但通过这个过程我得以深入学习MongoDB,并感到非常有趣。

可以参考

在恢复MongoDB集群时的加速技巧:

优化mongorestore速度
https://www.greptips.com/posts/1261/

MongoDB 手册
https://docs.mongodb.com/manual/reference/program/mongodump
https://docs.mongodb.com/manual/reference/program/mongorestore
https://docs.mongodb.com/manual/reference/write-concern
https://docs.mongodb.com/manual/tutorial/manage-sharded-cluster-balancer
以及其他众多资料。

广告
将在 10 秒后关闭
bannerAds