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 загружает все записи, которые он восстанавливает, в память.

Так что я должен найти какое-то решение для этого, и:

  1. Каждый раз, когда происходит сбой, просто запускайте команду mongorestore, чтобы она продолжала с того места, где остановилась. Это, вероятно, должно работать, но я чувствую себя немного неловко, делая это.
  2. Восстановите базу данных по одной коллекции за раз, но самая большая коллекция превышает 5 ГБ, поэтому она также не будет работать должным образом.
  3. Добавьте подкачку или физическую память (временно) в контейнер, чтобы процесс не был убит после того, как процесс исчерпал физическую память.
  4. Что-то еще, надеюсь, лучшее решение?

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 }}

Вместо запуска нового набора реплик можно выполнить полное расширение и обновление, даже не переходя в автономный режим.

  1. Запустите MongoDB 3.6 на хосте C
  2. На первичном (в настоящее время A или B) добавьте узел C в набор реплик
  3. Узел C выполнит начальную синхронизацию данных; Это может занять некоторое время
  4. Как только это закончено, снимите узел B; ваш набор реплик еще имеет два рабочих узла (A и C), поэтому будет работать непрерывно
  5. Замените v3.4 на узле B на v3.6 и начните заново
  6. Когда узел B будет готов, снимите узел A
  7. Замените 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

...
Другие вопросы по тегам