Mongorestore 似乎 运行 内存不足并终止了 mongo 进程
Mongorestore seems to run out of memory and kills the mongo process
在当前设置中有两个 Mongo Docker 容器,运行ning 在主机 A 和 B 上,Mongo 版本为 3.4 和 运行宁在一个副本集中。我想将它们升级到 3.6 并增加一个成员,这样容器将 运行 在主机 A、B 和 C 上。容器有 8GB 内存限制并且没有分配交换(当前),并且在 Rancher.所以我的计划是启动三个新容器,为它们初始化一个副本集,从 3.4 容器中进行转储,然后将其恢复到新的副本集主服务器。
进行转储很顺利,它的大小约为 16GB。当我尝试将其恢复到新的 3.6 master 时,恢复开始正常,但在恢复大约 5GB 的数据后,mongo 进程似乎被 OS/Rancher 杀死,而容器本身并没有't 重新启动,MongoDB 进程刚刚崩溃并重新加载自身。如果我 运行 mongo 再次恢复到同一个数据库,它会为所有已插入的条目显示唯一键错误,然后从它停止的地方继续,只有在 5GB 左右后再次执行相同的操作。所以似乎 mongorestore 加载了它恢复到内存中的所有条目。
所以我必须找到一些解决方案,并且:
- 每次崩溃时,只需 运行 mongorestore 命令,以便它从停止的地方继续。它可能应该工作,但我觉得这样做有点不安。
- 一次恢复数据库一个集合,但是最大的集合大于5GB,所以它也不能正常工作。
- 向容器添加交换内存或物理内存(临时),这样进程就不会在进程 运行s 耗尽物理内存后被终止。
- 其他问题,希望有更好的解决方案?
由于 mongorestore 在成功停止的地方继续运行,因此听起来您没有 运行 磁盘 space,关注内存问题是正确的响应。在 mongorestore 进程中,您肯定 运行 内存不足。
我强烈建议使用交换 space,因为这是最简单、最可靠、最少的 hacky,并且可以说是处理此问题最受官方支持的方法。
或者,如果您出于某种原因完全反对使用 swap space,您可以暂时使用具有更大内存的节点,在该节点上执行 mongorestore,允许其复制,然后将节点关闭并用分配给它的资源较少的节点替换它。此选项应该有效,但对于较大的数据集可能会变得非常困难,并且对于这样的事情来说是相当过分的。
无需启动新的副本集,甚至无需离线即可完成整个扩展和升级。
- 在主机 C
上启动 MongoDB 3.6
- 在主节点(目前是A或B)上,将节点C添加到副本集
- 节点C将进行数据的初始同步;这可能需要一些时间
- 完成后,关闭节点B;您的副本集仍有两个工作节点(A 和 C),因此将继续不间断
- 用 v3.6 替换节点 B 上的 v3.4 并重新开始备份
- 当节点B准备就绪时,取下节点A
- 用 v3.6 替换节点 A 上的 v3.4 并重新开始备份
您将得到与以前相同的副本集 运行,但现在三个节点都是 运行 v.3.4.
PS 请务必在开始前查看 Upgrade a Replica Set to 3.6 上的文档。
正如另一个答案指出的那样,增加交换大小对我来说很有效。此外,--numParallelCollections
选项控制集合的数量 mongodump
/mongorestore
应该 dump/restore 并行。默认为4,可能会占用大量内存。
我 运行 遇到了类似的问题 运行 一台机器上的 3 个节点(总共 8GB RAM)作为测试副本集的一部分。 default storage cache size 是 .5 *(总 RAM - 1GB)。 mongorestore 导致每个节点在恢复时使用完整的缓存大小并消耗所有可用的 RAM。
我正在使用 ansible 来模板化 mongod.conf
的这一部分,但您可以将 cacheSizeGB
设置为任何合理的数量,这样多个实例就不会消耗 RAM。
storage:
wiredTiger:
engineConfig:
cacheSizeGB: {{ ansible_memtotal_mb / 1024 * 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
只是在这里记录我在 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 集合。
我的场景类似于@qwertz,但为了能够将所有集合上传到我的数据库,创建了以下脚本来处理部分上传;上传每个集合 one-by-one 而不是尝试一次发送所有数据库是正确填充它的唯一方法。
populate.sh
:
#!/bin/bash
backupFiles=`ls ./backup/${DB_NAME}/*.bson.gz`
for file in $backupFiles
do
file="${file:1}"
collection=(${file//./ })
collection=(${collection//// })
collection=${collection[2]}
mongorestore \
$file \
--gzip \
--db=$DB_NAME \
--collection=$collection \
--drop \
--uri="${DB_URI}://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/"
done
Dockerfile.mongorestore
:
FROM alpine:3.12.4
RUN [ "apk", "add", "--no-cache", "bash", "mongodb-tools" ]
COPY populate.sh .
ENTRYPOINT [ "./populate.sh" ]
docker-compose.yml
:
...
mongorestore:
build:
context: .
dockerfile: Dockerfile.mongorestore
restart: on-failure
environment:
- DB_URI=${DB_URI}
- DB_NAME=${DB_NAME}
- DB_USERNAME=${DB_USERNAME}
- DB_PASSWORD=${DB_PASSWORD}
- DB_HOST=${DB_HOST}
- DB_PORT=${DB_PORT}
volumes:
- ${PWD}/backup:/backup
...
在当前设置中有两个 Mongo Docker 容器,运行ning 在主机 A 和 B 上,Mongo 版本为 3.4 和 运行宁在一个副本集中。我想将它们升级到 3.6 并增加一个成员,这样容器将 运行 在主机 A、B 和 C 上。容器有 8GB 内存限制并且没有分配交换(当前),并且在 Rancher.所以我的计划是启动三个新容器,为它们初始化一个副本集,从 3.4 容器中进行转储,然后将其恢复到新的副本集主服务器。
进行转储很顺利,它的大小约为 16GB。当我尝试将其恢复到新的 3.6 master 时,恢复开始正常,但在恢复大约 5GB 的数据后,mongo 进程似乎被 OS/Rancher 杀死,而容器本身并没有't 重新启动,MongoDB 进程刚刚崩溃并重新加载自身。如果我 运行 mongo 再次恢复到同一个数据库,它会为所有已插入的条目显示唯一键错误,然后从它停止的地方继续,只有在 5GB 左右后再次执行相同的操作。所以似乎 mongorestore 加载了它恢复到内存中的所有条目。
所以我必须找到一些解决方案,并且:
- 每次崩溃时,只需 运行 mongorestore 命令,以便它从停止的地方继续。它可能应该工作,但我觉得这样做有点不安。
- 一次恢复数据库一个集合,但是最大的集合大于5GB,所以它也不能正常工作。
- 向容器添加交换内存或物理内存(临时),这样进程就不会在进程 运行s 耗尽物理内存后被终止。
- 其他问题,希望有更好的解决方案?
由于 mongorestore 在成功停止的地方继续运行,因此听起来您没有 运行 磁盘 space,关注内存问题是正确的响应。在 mongorestore 进程中,您肯定 运行 内存不足。
我强烈建议使用交换 space,因为这是最简单、最可靠、最少的 hacky,并且可以说是处理此问题最受官方支持的方法。
或者,如果您出于某种原因完全反对使用 swap space,您可以暂时使用具有更大内存的节点,在该节点上执行 mongorestore,允许其复制,然后将节点关闭并用分配给它的资源较少的节点替换它。此选项应该有效,但对于较大的数据集可能会变得非常困难,并且对于这样的事情来说是相当过分的。
无需启动新的副本集,甚至无需离线即可完成整个扩展和升级。
- 在主机 C 上启动 MongoDB 3.6
- 在主节点(目前是A或B)上,将节点C添加到副本集
- 节点C将进行数据的初始同步;这可能需要一些时间
- 完成后,关闭节点B;您的副本集仍有两个工作节点(A 和 C),因此将继续不间断
- 用 v3.6 替换节点 B 上的 v3.4 并重新开始备份
- 当节点B准备就绪时,取下节点A
- 用 v3.6 替换节点 A 上的 v3.4 并重新开始备份
您将得到与以前相同的副本集 运行,但现在三个节点都是 运行 v.3.4.
PS 请务必在开始前查看 Upgrade a Replica Set to 3.6 上的文档。
正如另一个答案指出的那样,增加交换大小对我来说很有效。此外,--numParallelCollections
选项控制集合的数量 mongodump
/mongorestore
应该 dump/restore 并行。默认为4,可能会占用大量内存。
我 运行 遇到了类似的问题 运行 一台机器上的 3 个节点(总共 8GB RAM)作为测试副本集的一部分。 default storage cache size 是 .5 *(总 RAM - 1GB)。 mongorestore 导致每个节点在恢复时使用完整的缓存大小并消耗所有可用的 RAM。
我正在使用 ansible 来模板化 mongod.conf
的这一部分,但您可以将 cacheSizeGB
设置为任何合理的数量,这样多个实例就不会消耗 RAM。
storage:
wiredTiger:
engineConfig:
cacheSizeGB: {{ ansible_memtotal_mb / 1024 * 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
只是在这里记录我在 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 集合。
我的场景类似于@qwertz,但为了能够将所有集合上传到我的数据库,创建了以下脚本来处理部分上传;上传每个集合 one-by-one 而不是尝试一次发送所有数据库是正确填充它的唯一方法。
populate.sh
:
#!/bin/bash
backupFiles=`ls ./backup/${DB_NAME}/*.bson.gz`
for file in $backupFiles
do
file="${file:1}"
collection=(${file//./ })
collection=(${collection//// })
collection=${collection[2]}
mongorestore \
$file \
--gzip \
--db=$DB_NAME \
--collection=$collection \
--drop \
--uri="${DB_URI}://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/"
done
Dockerfile.mongorestore
:
FROM alpine:3.12.4
RUN [ "apk", "add", "--no-cache", "bash", "mongodb-tools" ]
COPY populate.sh .
ENTRYPOINT [ "./populate.sh" ]
docker-compose.yml
:
...
mongorestore:
build:
context: .
dockerfile: Dockerfile.mongorestore
restart: on-failure
environment:
- DB_URI=${DB_URI}
- DB_NAME=${DB_NAME}
- DB_USERNAME=${DB_USERNAME}
- DB_PASSWORD=${DB_PASSWORD}
- DB_HOST=${DB_HOST}
- DB_PORT=${DB_PORT}
volumes:
- ${PWD}/backup:/backup
...