Mongorestore, кажется, исчерпал память и убивает процесс Монго
В текущей настройке есть два контейнера Mongo Docker, работающих на хостах A и B, с версией Mongo 3.4 и работающих в наборе реплик. Я хотел бы обновить их до 3,6 и увеличить членство, чтобы контейнеры работали на хостах A, B и C. Контейнеры имеют ограничение в 8 ГБ памяти и не выделены подкачки (в настоящее время), и администрируются в Rancher. Таким образом, я планировал загрузить три новых контейнера, инициализировать набор реплик для них, взять дамп из контейнера 3.4 и восстановить его как новый мастер набора реплик.
Взятие дампа прошло нормально, а его размер составил около 16Гб. Когда я попытался восстановить его на новом главном 3.6, восстановление началось нормально, но после того, как он восстановил примерно 5 ГБ данных, процесс mongo, похоже, был убит OS/Rancher, и хотя сам контейнер не перезапускается, процесс MongoDB просто падает и перезагружается снова. Если я снова запускаю mongorestore в той же базе данных, он сообщает об ошибке уникального ключа для всех уже вставленных записей, а затем продолжает с того места, на котором остановился, только чтобы повторить то же самое после 5 ГБ или около того. Таким образом, кажется, что mongorestore загружает все записи, которые он восстанавливает, в память.
Так что я должен найти какое-то решение для этого, и:
- Каждый раз, когда происходит сбой, просто запускайте команду mongorestore, чтобы она продолжала с того места, где остановилась. Это, вероятно, должно работать, но я чувствую себя немного неловко, делая это.
- Восстановите базу данных по одной коллекции за раз, но самая большая коллекция превышает 5 ГБ, поэтому она также не будет работать должным образом.
- Добавьте подкачку или физическую память (временно) в контейнер, чтобы процесс не был убит после того, как процесс исчерпал физическую память.
- Что-то еще, надеюсь, лучшее решение?
7 ответов
Так как кажется, что у вас не хватает места на диске из-за того, что mongorestore продолжает работу там, где он успешно остановился, сосредоточение внимания на проблемах с памятью является правильным ответом. Вам определенно не хватает памяти во время процесса mongorestore.
Я настоятельно рекомендую использовать пространство подкачки, так как это самый простой, самый надежный, наименее хакерский и, возможно, наиболее официально поддерживаемый способ решения этой проблемы.
В качестве альтернативы, если вы по какой-то причине категорически не согласны с использованием пространства подкачки, вы можете временно использовать узел с большим объемом памяти, создать хранилище mongorestore на этом узле, разрешить его репликацию, затем снять узел и заменить его на узел, которому выделено меньше ресурсов. Эта опция должна работать, но может стать довольно трудной для больших наборов данных и довольно излишней для чего-то подобного.
Увеличение размера свопа, как указал другой ответ, сработало для меня. Так же --numParallelCollections
опция контролирует количество коллекций mongodump
/mongorestore
должен сбрасывать / восстанавливать параллельно. По умолчанию установлено значение 4, которое может занимать много памяти.
Просто документирую здесь свой опыт использования mongodb 4.4 в 2020 году:
Я столкнулся с этой проблемой при восстановлении коллекции размером 5 ГБ на машине с памятью 4 ГБ. Я добавил подкачку на 4 ГБ, которая, похоже, сработала, я больше не видел
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.
В моем случае мне потребовалось 4 ГБ памяти + 8 ГБ подкачки, чтобы импортировать коллекцию GridFS размером 5 ГБ.
Я решил проблему OOM, используя --wiredTigerCacheSizeGB
параметр mongod. Отрывок из моего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 узлов на одной машине (всего 8 ГБ ОЗУ) в рамках тестирования набора реплик. Размер кеш-памяти по умолчанию составляет 0,5 * (общий объем ОЗУ - 1 ГБ). Mongorestore заставил каждый узел использовать полный размер кеша при восстановлении и использовать всю доступную оперативную память.
Я использую ansible для создания шаблона этой части mongod.conf
, но вы можете установить cacheSizeGB
на любое разумное количество, чтобы несколько экземпляров не потребляли ОЗУ.
storage:
wiredTiger:
engineConfig:
cacheSizeGB: {{ ansible_memtotal_mb / 1024 * 0.2 }}
Вместо запуска нового набора реплик можно выполнить полное расширение и обновление, даже не переходя в автономный режим.
- Запустите MongoDB 3.6 на хосте C
- На первичном (в настоящее время A или B) добавьте узел C в набор реплик
- Узел C выполнит начальную синхронизацию данных; Это может занять некоторое время
- Как только это закончено, снимите узел B; ваш набор реплик еще имеет два рабочих узла (A и C), поэтому будет работать непрерывно
- Замените v3.4 на узле B на v3.6 и начните заново
- Когда узел B будет готов, снимите узел A
- Замените v3.4 на узле A на v3.6 и начните заново
Вы останетесь с тем же набором реплик, что и раньше, но теперь с тремя узлами, работающими v.3.4.
PS Перед началом работы обязательно ознакомьтесь с документацией по обновлению набора реплик до 3.6.
Мой сценарий похож на @qwertz, но чтобы иметь возможность загружать всю коллекцию в мою базу данных, был создан следующий скрипт для обработки частичных загрузок; загрузка каждой отдельной коллекции по одной вместо того, чтобы пытаться отправить всю базу данных сразу, была единственным способом правильно заполнить ее.
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
...