k8s中mongo容器数据迁移之内存小坑

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了k8s中mongo容器数据迁移之内存小坑相关的知识,希望对你有一定的参考价值。

参考技术A   近日在进行mongo的数据迁移,使用mongodump及mongorestore工具,遇到了导出正常导入失败,无报错日志,容器退出码是137,直接容器自行重启了。现简要说说是可能是什么原因。

  源环境:mongo v3.4.10,数据量磁盘存储是3-4GB,使用mongodump不加--gzip参数时有19GB,加--gzip参数后是2GB。以单pod形式运行在A网络区的k8s集群中。
  目标环境:mongo v3.4.24,以单pod形式运行在B网络区的k8s集群中。
  操作:将数据从源环境迁移到目标环境。

排查过程:

  由上面检查连接数,延伸到是否其它资源不足导致pod退出呢?而pod的资源主要就是CPU和内存(文件系统已经检查过了)。
  核查完pod的CPU、内存后,发现CPU的最高使用率没有接近或超过yaml里设定的limits,而内存实际使用有16GB,yaml里limits限定是18G,已经很接近了。那么是否可能是内存不够了?
  重新扩大yaml的内存limits为25G,然后再重新导入,导入成功!
  此时再检查该pos内存使用率,发现最高使用到23GB了。

  本人不是专业搞mongo的,本次是初次使用,因此,可能本问题比较简单,但还是记录下来,以备后用。
  初步猜测导入时的内存大小与导出时最大的单个bson文件大小有关。本次迁移中,单个bson文件最大是18G,而考虑到额外空间,内存至少得18G+以上。时间有限,未做进一步的测试验证。

Mongorestore 似乎内存不足并杀死了 mongo 进程

【中文标题】Mongorestore 似乎内存不足并杀死了 mongo 进程【英文标题】:Mongorestore seems to run out of memory and kills the mongo process 【发布时间】:2018-09-30 08:55:28 【问题描述】:

在当前设置中,有两个 Mongo Docker 容器,在主机 A 和 B 上运行,Mongo 版本为 3.4,并在副本集中运行。我想将它们升级到 3.6 并增加一个成员,以便容器可以在主机 A、B 和 C 上运行。容器有 8GB 内存限制并且没有分配交换空间(当前),并在Rancher 中进行管理。所以我的计划是启动三个新容器,为它们初始化一个副本集,从 3.4 容器中获取一个转储,然后将其恢复为新的副本集 master。

转储文件很顺利,其大小约为 16GB。当我尝试将其恢复到新的 3.6 主服务器时,恢复开始正常,但在恢复了大约 5GB 的数据后,mongo 进程似乎被 OS/Rancher 杀死,而容器本身没有重新启动,MongoDB 进程只是崩溃并重新加载自己再次备份。如果我再次将 mongorestore 运行到同一个数据库,它会为所有已插入的条目显示唯一键错误,然后从中断处继续,仅在 5GB 左右后再次执行相同操作。所以看起来 mongorestore 会将它恢复的所有条目加载到内存中。

所以我得想办法解决这个问题,并且:

    每次它崩溃时,只需运行 mongorestore 命令,它就会从中断的地方继续。它应该可以工作,但我觉得这样做有点不安。 一次恢复数据库一个集合,但最大的集合大于 5GB,因此也无法正常工作。 向容器添加交换或物理内存(临时),这样进程就不会在物理内存用完后被终止。 还有其他问题,希望有更好的解决方案?

【问题讨论】:

这意味着您在单个主机上运行 3 个需要内存的进程:mongod v3.4、新的 mongod v3.6 和 mongorestore? 既然你这么说......是的。 【参考方案1】:

在这里记录一下我在 2020 年使用 mongodb 4.4 的经验:

我在具有 4GB 内存的机器上恢复 5GB 集合时遇到了这个问题。我添加了似乎有效的 4GB 交换,我不再看到 KILLED 消息。

但是,过了一会儿,我发现我丢失了很多数据!事实证明,如果 mongorestore 在最后一步(100%)内存不足,它不会显示被杀死,但它还没有导入你的数据

您要确保看到最后一行:

[########################]  cranlike.files.chunks  5.00GB/5.00GB  (100.0%)
[########################]  cranlike.files.chunks  5.00GB/5.00GB  (100.0%)
[########################]  cranlike.files.chunks  5.00GB/5.00GB  (100.0%)
[########################]  cranlike.files.chunks  5.00GB/5.00GB  (100.0%)
[########################]  cranlike.files.chunks  5.00GB/5.00GB  (100.0%)
restoring indexes for collection cranlike.files.chunks from metadata
finished restoring cranlike.files.chunks (23674 documents, 0 failures)
34632 document(s) restored successfully. 0 document(s) failed to restore.

就我而言,我需要 4GB 内存 + 8GB 交换空间来导入 5GB GridFS 集合。

【讨论】:

感谢您的记录。应该有“0 个文档无法恢复”以确保没有数据丢失/丢失。【参考方案2】:

我通过使用mongod的--wiredTigerCacheSizeGB参数解决了OOM问题。以下摘自我的docker-compose.yaml

version: '3.6'
services:
    db:
        container_name: db
        image: mongo:3.2
        volumes:
            - ./vol/db/:/data/db
        restart: always
        # use 1.5GB for cache instead of the default (Total RAM - 1GB)/2:
        command: mongod --wiredTigerCacheSizeGB 1.5

【讨论】:

【参考方案3】:

作为测试副本集的一部分,我遇到了在单台机器上运行 3 个节点(总共 8GB RAM)的类似问题。 default storage cache size 是 0.5 *(总 RAM - 1GB)。 mongorestore 导致每个节点在恢复时使用完整的缓存大小并消耗所有可用的 RAM。

我正在使用 ansible 来模板化 mongod.conf 的这一部分,但您可以将您的 cacheSizeGB 设置为任何合理的数量,这样多个实例就不会占用 RAM。

storage:
    wiredTiger:
        engineConfig:
            cacheSizeGB:  ansible_memtotal_mb /  1024 * 0.2 

【讨论】:

【参考方案4】:

正如另一个答案指出的那样,增加交换大小对我有用。此外,--numParallelCollections 选项控制集合的数量mongodump/mongorestore 应该并行转储/恢复。默认为 4,可能会消耗大量内存。

【讨论】:

--numParallelCollections 设置为 1 是我的案例中最有效和最简单的解决方案:具有 1GB RAM 的 EC2 实例。【参考方案5】:

无需启动新的副本集,甚至可以在不离线的情况下进行整个扩展和升级。

    在主机 C 上启动 MongoDB 3.6 在主节​​点(当前为 A 或 B)上,将节点 C 添加到副本集中 节点 C 将进行数据的初始同步;这可能需要一些时间 完成后,取下节点 B;您的副本集仍然有两个工作节点(A 和 C),因此将继续不间断 将节点 B 上的 v3.4 替换为 v3.6 并重新启动备份 当节点B准备好时,取下节点A 将节点 A 上的 v3.4 替换为 v3.6 并重新启动备份

您将继续运行与以前相同的副本集,但现在三个节点都运行 v.3.4。

PS 在开始之前,请务必查看Upgrade a Replica Set to 3.6 上的文档。

【讨论】:

【参考方案6】:

由于 mongorestore 继续成功中断的地方,听起来您并没有用完磁盘空间,因此关注内存问题是正确的响应。您肯定在 mongorestore 过程中内存不足。

我强烈建议使用交换空间,因为这是处理此问题的最简单、最可靠、最不麻烦的方法,并且可以说是最受官方支持的方法。

或者,如果您出于某种原因完全反对使用交换空间,您可以暂时使用具有较大内存量的节点,在该节点上执行 mongorestore,允许其复制,然后关闭该节点并用分配给它的资源较少的节点替换它。这个选项应该可以工作,但对于更大的数据集可能会变得相当困难,并且对于这样的事情来说太过分了。

【讨论】:

通过临时增加内存和添加交换空间来做到这一点,结果很好。还按照 Mongo 文档中的建议永久添加了一些交换。谢谢! 对我来说,使用 -vvv 详细选项运行 mongorestore 至少可以显示“已杀死”,而不是静默失败。添加交换空间并增加 WiredTiger 缓存以匹配对我有用。

以上是关于k8s中mongo容器数据迁移之内存小坑的主要内容,如果未能解决你的问题,请参考以下文章

k8s版MongoShake数据迁移工具

个人总结

K8S数据迁移方法

win2016 配置IIS 和mysql5.7 迁移数据表的两个小坑

[云原生之DockerDocker容器的存储与迁移

如何从Oracle 迁移到 Mongo DB