Установка и настройка MongoDB на Debian, а также ReplicaSet и пара других мелочей +7


image

Это руководство описывает пошаговую установку и настройку реплики из 3 узлов mongoDB на базе движка WiredTiger. А также несколько полезных мелочей для людей, впервые столкнувшихся с MongoDB.

Важное уточнение:

  1. До начала установки необходимо понимание конечной архитектуры.
  2. Некоторые приятности требуют Enterprise лицензию.
В моем случае это коснулось In-Memory Storage Engine, который я хотел добавить для тестирования производительности базы, находящейся в RAM.

Немного о движке WiredTiger


Engine WiredTiger — новый движок mongoDB, использующийся по умолчанию вместо MMAP, начиная с версии 3.4. Хорош тем, что работает с данными на уровне коллекций и отдельных документов, а не полностью базой. Также устраняет проблему Global lock по вышеуказанной причине, из-за чего и был выбран в продакшен.

Сказ о том, как WiredTiger хранит данные:
… находится по этому адресу на английском языке
Попытки внятно перевести механизм на русский язык провалились. Увы.

Установка OS и компонентов


Ставим Debian любой удобной вам версии, у меня использовался 8.6.0.
Для упрощения масштабирования узлов и баз данных, рекомендую использовать lvm.
Из компонентов понадобится только ssh для более удобного доступа к серверу.

Установка MongoDB.


У меня используется бесплатная Community Edition, руководство будет на её основе.
По необходимости допишу Enterpise версию, т.к. она тоже крутилась и разбиралась.

Данное руководство описывается для варианта 3-х серверов (master, slave, arbiter).

Итак, поехали:

  1. Для начала нам необходимо импортировать публичный GPG ключ.

    sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 0C49F3730359A14518585931BC711F9BA15703C6
  2. Далее добавляем репозиторий MongoDB.
    Открываем файл со списком репозиториев

    nano /etc/apt/sources.list

    Копируем репозиторий и сохраняем изменения.

    deb http://repo.mongodb.org/apt/debian jessie/mongodb-org/3.4 main

    Обновляем список доступных пакетов

    sudo apt-get update
  3. Устанавливаем MongoDB и зависимые пакеты.

    sudo apt-get install -y mongodb-org

Повторяем процедуру для 3(трех) серверов,
На этом первоначальная настройка завершена.
Теперь переходим к настройке mongoDB.

Настройка и добавление серверов в Replica Set


В начале было слово
Давайте для начала разберемся, что такое replica set.
Replica Set — это кластер серверов MongoDB, реализующий механизм репликации master-slave и автоматическое переключение между ними. Это рекомендуемый механизм репликации от разработчиков MongoDB. ссылка на офф. документацию.

Картинка:

image

Мы используем механизм репликации, приведенный на картинке:
мастер, два вторичных и арбитр.

Теперь по порядку:

Primary — основной сервер mongoDB.
Secondary — точные копии баз(ы) данных с real-time синхронизацией.
Arbiter — сервер выбора вторичной реплики с высшим приоритетом, которая станет главной в случае падения сервера.

ОЧЕНЬ ВАЖНО:
Arbiter отвечает только за выборы преемника, сам стать преемником он не может, поэтому рекомендуется отдавать под арбитра минимальные ресурсы.

ЕЩЁ БОЛЕЕ ВАЖНО:
Технически можно вообще жить без арбитра, однако с ним выборы будут происходить в разы быстрее, соответственно время простоя будет минимизировано. Плюс есть ненулевая вероятность потерять ReplicaSet целиком.

Primary
Настройки пишем в файл /etc/mongod.conf У меня файл выглядит следующим образом:

storage:
  engine: wiredTiger
  dbPath: /var/lib/mongodb

  journal:
    enabled: true

systemLog:
  destination: file
  logAppend: true
  path: /var/log/mongodb/mongod.log

  replSetName: replicaname

net:
  port: 27017
  bindIp:0.0.0.0

Указываемые значения переменных:
dbPath — путь к базе данных. При указании на пустое место, создаст там базы. При разворачивании бэкапа подцепит существующую.
journal — включает журналирование.
replSetName — название реплики. Должно быть идентичным у всех узлов внутри реплики.
bindIp — список адресов, с которых можно принимать соединения по порту 27017.

Далее для конфигурирования я использовал саму mongoDB:

mongo 

попадаем внутрь и первым делом проверяем статус:

rs.status()

Начальный статус должен быть 0 — startup. Означает что узел не является членом ни одной реплики.

Инициализируем реплику.
Выполняем в MongoShell на первичном узле

rs.initiate(
   {
      _id: "rs0",
      version: 1
members: [ { _id : 0, host : "<Primary server ip>:27017" } ]   
})

Проверяем конфигурацию:

rs.conf()

Сразу после добавления в реплику узел будет в статусе 5 — Startup2, это означает что он присоединился к реплике и в данный момент синхронизируется. Может занять продолжительное время.

Добавляем следующие узлы:

rs.add("<Secondary server ip>:27017")

Добавляем арбитра:

rs.addArb(“<arbiter server ip>:27017”)

либо

rs.add(“<arbiter server ip>:27017”, true)

Статусы в rs.status() будут:
1 — Primary
2 — Secondary
7 — Arbiter

Приоритеты


Варианты исполнения

Первый:
Необходимо проставить приоритеты (цифры member id берем из статуса):

cfg = rs.conf()
cfg.members[0].priority = 2 
cfg.members[1].priority = 3       
cfg.members[2].priority = 1 
rs.reconfig(cfg, {force : true})

Чем выше цифра приоритета, тем ниже сам приоритет при выборе Primary узла.

Второй:
Добавляем узлы с заранее прописанным приоритетом:

rs.add({host: “<secondary server ip:27017”, priority: 1})

Проверяем что все узлы доступны и выставлены с правильными приоритетами:

rs.status()

В моем случае конфиги и статусы приобрели следующий вид:

rs.status()

{
        "set" : "<имя вашей реплики>",
        "date" : ISODate("2017-05-05T13:57:01.538Z"),
        "myState" : 2,
        "term" : NumberLong(1021),
        "syncingTo" : "<secondary server ip>:27017",
        "heartbeatIntervalMillis" : NumberLong(2000),
        "members" : [
                {
                        "_id" : 0,
                        "name" : "<Secondary server ip>:27017",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 1908285,
                        "optime" : {
                                "ts" : Timestamp(1493992502, 1),
                                "t" : NumberLong(1021)
                        },
                        "optimeDate" : ISODate("2017-05-05T13:55:02Z"),
                        "syncingTo" : ":27017",
                        "configVersion" : 373058,
                        "self" : true
                },
                {
                        "_id" : 1,
                        "name" : "<Primary server ip>:27017",
                        "health" : 1,
                        "state" : 1,
                        "stateStr" : "PRIMARY",
                        "uptime" : 1688032,
                        "optime" : {
                                "ts" : Timestamp(1493992502, 1),
                                "t" : NumberLong(1021)
                        },
                        "optimeDate" : ISODate("2017-05-05T13:55:02Z"),
                        "lastHeartbeat" : ISODate("2017-05-05T13:57:00.108Z"),
                        "lastHeartbeatRecv" : ISODate("2017-05-05T13:57:00.895Z"),
                        "pingMs" : NumberLong(0),
                        "electionTime" : Timestamp(1492304555, 1),
                        "electionDate" : ISODate("2017-04-16T01:02:35Z"),
                        "configVersion" : 373058
                },
                {
                        "_id" : 2,
                        "name" : "<Arbiter server ip>:27017",
                        "health" : 1,
                        "state" : 7,
                        "stateStr" : "ARBITER",
                        "uptime" : 1680982,
                        "lastHeartbeat" : ISODate("2017-05-05T13:56:59.812Z"),
                        "lastHeartbeatRecv" : ISODate("2017-05-05T13:56:59.062Z"),
                        "pingMs" : NumberLong(0),
                        "configVersion" : 373058
                }
        ],
        "ok" : 1
}

При добавлении узла в уже существующую реплику она какое-то время будет недоступна в связи с синхронизацией.

На этом установка и настройка MongoDB в режиме ReplicaSet завершена и можно с чистой совестью наполнять базу данными.

Другие полезные команды


Команды
Сбрасывание PRIMARY. Смена первичного узла и переназначение приоритетов

rs.stepDown(60,40)
60 секунд — время, в течение которого сервер, с которого запущено выполнение команды, не может стать Primary; 40 секунд — время перевыборов нового Primary.

db.adminCommand({replSetStepDown: 30, force: 1})
30 секунд — время отключения Primary и перевыборы. Выполнение команды допустимо с любого из серверов mongoDB.

rs.stepDown(60)
Узел, с которого запущена команда, в течение 60 секунд не сможет стать Primary.

/var/lib/mongodb/ — Тут лежат файлы баз.

Восстановление из дампа:
Восстанавление базы в каталог по умолчанию. Если файл в с таким именем есть, то он перезаписывается:
mongorestore <Имя БД>

Восстановление всех баз из указанного каталога:

mongorestore ./Backup

Восстановление отдельной таблицы(коллекции):

mongorestore --collection <коллекция> --db <Имя БД> dump/


Создание дампа
создание бэкапа всех баз в папку Backup:

mongodump --out /Backup

создание бэкапа отдельной базы:

mongodump  --db <Имя БД> --out /Backup

создание бэкапа отдельной таблицы:

mongodump  --db <Имя БД> --collection <Имя коллекции>--out /Backup

Запуск от имени root, создание бэкапа указанной базы в указанный каталог + текущая дата:

sudo mongodump --db newdb --out /var/backups/mongobackups/'date +"%m-%d-%y"'

Вот в общем-то и весь сказ о моем опыте разворачивания невиданной доселе системы в продакшен. Буду рад критике и дополнениям, если таковые появятся.




К сожалению, не доступен сервер mySQL