Это руководство описывает пошаговую установку и настройку реплики из 3 узлов mongoDB на базе движка WiredTiger. А также несколько полезных мелочей для людей, впервые столкнувшихся с MongoDB.
Важное уточнение:
- До начала установки необходимо понимание конечной архитектуры.
- Некоторые приятности требуют Enterprise лицензию.
Немного о движке 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).
Итак, поехали:
- Для начала нам необходимо импортировать публичный GPG ключ.
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 0C49F3730359A14518585931BC711F9BA15703C6
- Далее добавляем репозиторий MongoDB.
Открываем файл со списком репозиториев
nano /etc/apt/sources.list
Копируем репозиторий и сохраняем изменения.
deb http://repo.mongodb.org/apt/debian jessie/mongodb-org/3.4 main
Обновляем список доступных пакетов
sudo apt-get update
- Устанавливаем MongoDB и зависимые пакеты.
sudo apt-get install -y mongodb-org
Повторяем процедуру для 3(трех) серверов,
На этом первоначальная настройка завершена.
Теперь переходим к настройке mongoDB.
Настройка и добавление серверов в Replica Set
Давайте для начала разберемся, что такое replica set.
Replica Set — это кластер серверов MongoDB, реализующий механизм репликации master-slave и автоматическое переключение между ними. Это рекомендуемый механизм репликации от разработчиков MongoDB. ссылка на офф. документацию.
Картинка:
Мы используем механизм репликации, приведенный на картинке:
мастер, два вторичных и арбитр.
Теперь по порядку:
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. Смена первичного узла и переназначение приоритетов
/var/lib/mongodb/ — Тут лежат файлы баз.
Восстановление из дампа:
Восстанавление базы в каталог по умолчанию. Если файл в с таким именем есть, то он перезаписывается:
Восстановление всех баз из указанного каталога:
Восстановление отдельной таблицы(коллекции):
Создание дампа
создание бэкапа всех баз в папку Backup:
создание бэкапа отдельной базы:
создание бэкапа отдельной таблицы:
Запуск от имени root, создание бэкапа указанной базы в указанный каталог + текущая дата:
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"'
Вот в общем-то и весь сказ о моем опыте разворачивания невиданной доселе системы в продакшен. Буду рад критике и дополнениям, если таковые появятся.