Создание резервной копии БД
На сервере должно быть достаточно свободного места для того, чтобы контейнер с БД смог запуститься, и пользователь смог создать резервную копию.
Запрещается удалять файлы, которые находятся в /opt/wimark/volumes/mongo!
На платформе версии ниже 1.10 данные будут находится в /etc/wimark/volumes/mongo.
Для создания резервной копии следует выполнить следующие действия:
Зайти в БД:
docker exec -it $(docker ps | grep 'one-mongo-1\|one-mongo-ha-1' | \ awk '{ print $1;}') mongosh --port 30001 --host rs0/mongo-rs-1
--port 30001 --host rs0/mongo-rs-1 Данные параметры актуальны для платформы HA версии 1.10 и выше.
--host rs0/mongo-rs-1 Для платформы HA версии ниже 1.10 и платформы Standalone следует убрать этот параметр из команды.
При ситуации, где mongo-rs-1 недоступен, следует заменить его на mongo-rs-2.
2. Просмотреть сколько места на сервере занимает каждая коллекция в БД:
var collectionNames = db.getCollectionNames(),stats = [];collectionNames.forEach(function (n) {stats.push(db.getCollection(n).stats());});stats = stats.sort(function(a, b) {return b['storageSize'] - a['storageSize'];});stats.forEach(function(c) {print(`${c['ns']}: ${c['size']} (${(c['size'] / 1073741824).toFixed(2)} GB) | ${c['storageSize']} (${(c['storageSize'] / 1073741824).toFixed(2)} GB)`);});
Ниже приведены коллекции, которые часто занимают больше всего места на сервере. Самые тяжелые коллекции в БД - это коллекции со статистикой.
test.stats: NumberLong("138543878247") (129.03 GB) | NumberLong("34453618688") (32.09 GB) test.cpe_scan_data: NumberLong("67173999414") (62.56 GB) | NumberLong("12744724480") (11.87 GB) test.cpe_stat_info: NumberLong("3049385786") (2.84 GB) | 874041344 (0.81 GB) test.client_stats: 1314995013 (1.22 GB) | 513564672 (0.48 GB) test.client_addr: 1474389854 (1.37 GB) | 233897984 (0.22 GB) test.client_rf: 710458980 (0.66 GB) | 199856128 (0.19 GB) test.events: 645953888 (0.60 GB) | 178802688 (0.17 GB) test.client_session_info: 314861397 (0.29 GB) | 65781760 (0.06 GB)
3. Выйти из БД (команда exit) и зайти в контейнер с БД:
docker exec -it $(docker ps | grep 'one-mongo-1\|one-mongo-ha-1' | \ awk '{ print $1;}') bash
4. Сформировать команду, исходя из предыдущих результатов для частичного бэкапа данных:
mongodump --port 30001 --host rs0/mongo-rs-1 --db=test --gzip --archive=/tmp/backup_wimark.gz
Это базовая команда для создания резервной копии БД. Но учитывая то, что некоторые коллекции уже весят более 32 ГБ на сервере, а свободного места у пользователя нет, то необходимо исключить некоторые коллекции из резервной копии.
mongodump --port 30001 --host rs0/mongo-rs-1 --db=test --excludeCollection=stats --gzip --archive=/tmp/backup_wimark.gz
В команде добавлен параметр --excludeCollection=stats
Это значит, что исключена коллекция stats, и при запуске команды создания резервной копии, данная коллекция будет пропущена.
Тоже самое необходимо проделать для всех тех коллекций, которые занимают огромное кол-во места, и их следует ограничить.
Это следует делать только для тех коллекций, которые содержат только статистику или другую подобную информацию. Не рекомендуется ограничивать коллекции, которые содержат информацию о настройках, количестве ТД и т.п.
Можно использовать следующий параметр, в который включено большинство коллекций со статистикой:
mongodump --port 30001 --db=test --excludeCollection=client_addr --excludeCollection=cpe_scan_data --excludeCollection=cpe_stat_info --excludeCollection=client_stats --excludeCollection=client_rf --excludeCollection=events --excludeCollection=operations --excludeCollection=client_session_info --excludeCollection=bss_stat_info --excludeCollection=client_stat_info --excludeCollection=stats --excludeCollection=lbs_client_data --excludeCollection=license_log_daily --excludeCollection=lbs_client_coords --excludeCollection=lbs_cpe_info --excludeCollection=lbs_client_probes_testing --excludeCollection=lbs_client_probes --gzip --archive=/tmp/backup_wimark.gz
Если копировать преимущественно без статистики, то данный бэкап будет занимать 2~100 МБ, в зависимости от объема данных и выбранных коллекций.
5. Выйти из контейнера (команда exit) и копировать резервную копию на сервер:
sudo mkdir /opt/wimark_backup/ docker cp $(docker ps | grep 'one-mongo-1\|one-mongo-ha-1' | \ awk '{ print $1;}'):/tmp/backup_wimark.gz /opt/wimark_backup/
6. Копировать static файлы и скрипты в резервную папку:
cp -r /opt/wimark/static /opt/wimark_backup/static cp /opt/wimark/set_state.sh /opt/wimark_backup/set_state.sh cp /opt/wimark/checker.sh /opt/wimark_backup/checker.sh
Проверить, что все файлы и сам бэкап на месте. Если всё готово, необходимо выполнить действия в соответствии с разделом “Обновление ПО и перенос БД” инструкции по установке Wimark One: установка
При переустановки платформы лицензия на платформе - слетит!
Поэтому перед переустановкой необходимо обратиться в поддержку, где была куплена лицензия, для ее восстановления.
Ограничение размера коллекций в MongoDB
После того, как данные были восстановлены и новая платформа установлена, можно ограничить коллекции и создать индексы:
Создать скрипт для ограничения определенных коллекций:
// cappedLimit исчисляется в байтах (500МБ) var cappedLimit = 500000000 var cappedColls = { "lbs_client_data": cappedLimit, "lbs_client_probes": cappedLimit, "lbs_client_coords": cappedLimit, "client_addr": cappedLimit, "stats": cappedLimit, "events": cappedLimit, "cpe_scan_data": cappedLimit, }; for (var coll in cappedColls) { var isExist = db.getCollection(coll).exists(); if (isExist != null) { db.getCollection(coll).drop(); print("INFO: " + coll + " already exists and will be recreated."); } db.createCollection(coll); print("INFO: " + coll + " capped to " + cappedColls[coll]); db.runCommand({ "convertToCapped": coll, size: cappedColls[coll] }); }
var cappedColls = {}; - список коллекций, которые будут ограничены до 500 МБ.
Если коллекция уже существует, то она будет “удалена”, а затем создана с лимитом.
Именно поэтому данный лимит необходимо добавлять только для тех коллекций, которые не были восстановлены из резервной копии.
2. Создать скрипт для создания индексов в коллекциях, который необходим для поиска и автоматического очищения некоторых коллекций:
function createIndexIfNotExists(collectionName, indexSpec, options) { const collection = db.getCollection(collectionName); if (!collection.exists()) { print(`INFO: Collection ${collectionName} does not exist, skipping index creation.`); return; } const indexes = collection.getIndexes(); const indexExists = indexes.some(index => { return JSON.stringify(index.key) === JSON.stringify(indexSpec); }); if (!indexExists) { collection.createIndex(indexSpec, options); print(`INFO: Index created on ${collectionName} with spec: ${JSON.stringify(indexSpec)}`); } else { print(`INFO: Index already exists on ${collectionName} with spec: ${JSON.stringify(indexSpec)}`); } } createIndexIfNotExists("bss_stat_info", {"cpe_id":1, "timestamp":-1}, {"background":true}); createIndexIfNotExists("client_session_info", {"mac":1, "stop":1}, {"background":true}); createIndexIfNotExists("client_session_info", {"cpe_id":1, "mac":1}, {"background":true}); createIndexIfNotExists("client_session_info", {"stop":1, "start":1, "cpe_id":1}, {"background":true}); createIndexIfNotExists("client_session_info", {"stop":1}, {"background":true}); createIndexIfNotExists("client_stat_info", {"timestamp":-1, "_id":1, "mac":1}, {"background":true, partialFilterExpression: {timestamp: {$gte: 1622505600}}}); createIndexIfNotExists("client_stat_info", {"timestamp":1}, {"background":true}); createIndexIfNotExists("client_stats", {"timestamp":1}, {"expireAfterSeconds":259200, "background":true}); createIndexIfNotExists("client_stats", {"cpe_id":1, "timestamp":-1}, {"background":true}); createIndexIfNotExists("client_stats", {"macaddr":1}, {"background":true}); createIndexIfNotExists("clients", {"state":1, "last_connect":1}, {"background":true}); createIndexIfNotExists("clients", {"cpe_id":1, "timestamp":1}, {"background":true}); createIndexIfNotExists("clients", {"state":1, "cpe_id":1}, {"background":true}); createIndexIfNotExists("clients", {"cpe_id":"text", "ip":"text", "mac_addr":"text", "username":"text", "wlan_ssid":"text"}, { background: true, weights: {"$**": 1, "cpe_id": 9, "ip": 3, "mac_addr": 9, "username": 3, "wlan_ssid": 9}, default_language: "english" }); createIndexIfNotExists("clients", {"first_connect":-1}, {"background":true}); createIndexIfNotExists("cpe_scan_data", {"timestamp":-1, "cpe":1}, {"background":true}); createIndexIfNotExists("cpe_session_info", {"start":-1, "cpe_id":1}, {"background":true}); createIndexIfNotExists("cpe_stat_info", {"timestamp":-1, "cpe_id":1}, {"background":true, partialFilterExpression: {timestamp: {$gte: ISODate("2021-06-01T00:00:00.155Z")}}}); createIndexIfNotExists("events", {"timestamp":1}, {"expireAfterSeconds":259200, "background":true}); createIndexIfNotExists("lbs_client_coords", {"timestamp":1}, {"expireAfterSeconds":259200, "background":true}); createIndexIfNotExists("lbs_client_coords", {"group":1, "timestamp":-1, "_id":1}, {"background":true, partialFilterExpression: {timestamp: {$gte: 1619827200}}}); createIndexIfNotExists("lbs_client_coords", {"bestcpe":1, "timestamp":-1}, {"background":true}); createIndexIfNotExists("lbs_client_data", {"timestamp":1}, {"background":true}); createIndexIfNotExists("lbs_client_data", {"cpe":1, "timestamp":1}, {"background":true}); createIndexIfNotExists("lbs_client_probes", {"cpe":1}, {"background":true}); createIndexIfNotExists("lbs_client_probes", {"timestamp":-1}, {"background":true}); createIndexIfNotExists("lbs_client_probes", {"mac":1}, {"background":true}); createIndexIfNotExists("lbs_client_probes_testing", {"cpe":1, "ts":1}, {"background":true}); createIndexIfNotExists("operation", {"insert_time":-1}, {"background":true}); createIndexIfNotExists("radar_export_result", {"create_at":1}, {"background":true}); createIndexIfNotExists("radar_probes_raw", {"cpe":1, "ts":1}, {"background":true, "expireAfterSeconds":172800}); createIndexIfNotExists("radar_probes_real", {"cpe":1, "ts":1}, {"background":true, "expireAfterSeconds":172800}); createIndexIfNotExists("radar_probes_real", {"ts":-1, "cpe":1}, {"background":true, partialFilterExpression: {ts: {$gte: 1633046400}}}); createIndexIfNotExists("radar_visits", {"cpe":1, "start":1}, {"background":true}); createIndexIfNotExists("radar_visits", {"cpe":1, "duration":1, "stop":1, "start":1}, {"background":true}); createIndexIfNotExists("radar_visits_first", {"date":1}, {"expireAfterSeconds":2678400}); createIndexIfNotExists("redirect_sessions", {"mac":1}, {"background":true}); createIndexIfNotExists("stats", {"timestamp":1}, {"expireAfterSeconds":259200, "background":true}); createIndexIfNotExists("wlan_stat_info", {"wlan_id":1, "timestamp":-1}, {"background":true}); createIndexIfNotExists("snmp_point_state", {"cpe":1, "time_stamp":-1}, {"background":true}); createIndexIfNotExists("snmp_walker", {"cpe":1, "base_location":1}, {"background":true});
3. Затем необходимо скопировать данные скрипты в контейнер с БД:
docker cp /opt/wimark_backup/indexes.js wimark-one-mongo-ha-1:/tmp/indexes.js docker cp /opt/wimark_backup/capped.js wimark-one-mongo-ha-1:/tmp/capped.js
Пути до файлов и контейнера приведены для примера и могут отличатся.
4. Запустить скрипты в следующем порядке:
docker exec -it $(docker ps | grep 'one-mongo-1\|one-mongo-ha-1' | \ awk '{ print $1;}') mongosh --port 30001 --host rs0/mongo-rs-1 /tmp/capped.js
Не забываем о предупреждении про --port и --host для HA версии.
docker exec -it $(docker ps | grep 'one-mongo-1\|one-mongo-ha-1' | \ awk '{ print $1;}') mongosh --port 30001 --host rs0/mongo-rs-1 /tmp/indexes.js
5. После выполнения скриптов, можно проверить ограничены ли выбранные коллекции или нет. Для этого необходимо зайти в БД и выполнить команду:
db.getCollection("stats").stats()
Если коллекция ограничена, то в выводе будет строка capped: true и размер MaxSize, равный ранее заданному максимальному размеру 128 байт.