Создание резервной копии БД

На сервере должно быть достаточно свободного места для того, чтобы контейнер с БД смог запуститься, и пользователь смог создать резервную копию.

Запрещается удалять файлы, которые находятся в /opt/wimark/volumes/mongo!

На платформе версии ниже 1.10 данные будут находится в /etc/wimark/volumes/mongo.


Для создания резервной копии следует выполнить следующие действия:

  1. Зайти в БД:

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

После того, как данные были восстановлены и новая платформа установлена, можно ограничить коллекции и создать индексы:

  1. Создать скрипт для ограничения определенных коллекций:

// 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 байт.

  • No labels