Thank you for reading this post, don't forget to subscribe!
MongoDB — это система управления базами данных (СУБД) NoSQL с большим количеством встроенных функций, среди которых репликация и сегментирование. Благодаря этим функциям БД можно масштабировать на необходимое количество серверов путём распространения контента между ними.
Прежде чем приступить к установке MongoDB и её зависимостей, нужно убедиться, что сервер и установленное на нём ПО подготовлены и корректно настроены.
Жесткие диски
Если у вас есть возможность выбрать жёсткий диск, выбирайте SSD корпоративного уровня RAID 1, поскольку они экономны и высокопроизводительны.
Отредактируйте файл /etc/fstab системы Linux и отключите ведение журнала времени доступа. Добавьте noatime в четвертый столбец. Повторно смонтируйте раздел:
[root@mongodb1 ~]# mount -o remount /
Убедитесь, что новые настройки вступили в исполнение:
[[root@mongodb1 ~]# mount
/dev/sda on / type ext4 (rw,noatime)
Оптимизация
На данном этапе нужно оптимизировать запросы к базе данных:
- Добавьте индексы для наиболее часто искомых или распределенных запросов.
- Используйте команду MongoDB explain().
- Ограничьте вывод результатов и полей поиска.
===============================
MongoDB в отличии от MySQL поддерживает 2 формы репликации:
— реплисеты (Replica Sets)
— ведущий-ведомый (Master-Slave)
Настройка репликации базы данных по типу Master-Slave
ПРИМЕЧАНИЕ
MongoDB начиная с версии 4.0 убирает поддержку репликации master-slave.
Изменим домашнюю директорию для хранения баз, для этого создадим директорию:
mkdir /home/mongodb
chown mongod:mongod /home/mongodb/
Стандартная папка где хранятся базы — /var/lib/mongo и можно использовать именно ее.
Я в самом конфиге ничего не менял, оставил как и было.
Запуск Master
Запускаем Mongo демон как мастер:
# mongod --master·--dbpath /home/mongodb --bind_ip 192.168.13.161 --port 27001·--fork --logpath /var/log/mongodb/Master.log --pidfilepath /var/run/mongodb/Master.pid
Подключаемся на слейв:
Вот и все.
Запуск Slave
Проверяем доступность master-а со slave:
Останавливаем сервер с монгой:
Запускаем slave сервер:
Replica Set
Replica Set – это набор/группа серверов, которые обслуживают один и тот же набор данных
В такой группе содержится один мастер(первичный) и несколько слейв(вторичный) серверов.
Также в Replica Set может использоваться арбитр. Это сервер, на котором нет базы данных, а его назначение – участвовать в голосовании при выборе нового мастера, создавать кворум необходимый для голосования.
Первичный/мастер сервер обслуживает все запросы на запись, а также записывает эти запросы в свой лог-файл(oplog).
Вторичные/слейв сервера реплицируют oplog первичного сервера и применяют операции к своим наборам данных. Репликация является асинхронной.
Если первичный сервер не общается с другими членами реплики в течение времени ,определенного параметром electionTimeoutMillis (по умолчанию 10 секунд), то в результате голосования выбирается новый первичный сервер из состава текущих вторичных серверов.
Replica set не может обслуживать запросы на запись, до тех пор, пока выборы и назначение нового мастера не закончатся успешно.
С настройками по умолчанию среднее время на выбор нового мастера составляет 12 секунд
Это включает обнаружение недоступности мастера(10 секунд по умолчанию) и выбор нового мастера.
При необходимости можно изменить значение параметра electionTimeoutMillis.
По умолчанию запросы на чтения от клиентов обрабатываются только мастером, но можно настроить, чтобы запросы на чтение посылались и обрабатывались вторичными серверами.
Т.к. используется асинхронная репликация между первичным и вторичными серверами, то вторичные сервера могут отдавать клиентам устаревшие данные по сравнению с теми данными, которые содержатся на мастере в данный момент
Суть ReplicaSet заключается в том, что она в себе сохраняет одинаковые наборы данных. Один сервер, должен выступать в качестве основного сервера ( на него будут поступать все данные — он же ведущий, он же PRIMARY), а все остальные — являются вторичными ( они сохраняют копии данных с PRIMARY — они же ведомые, они же SECONDARYs).
Можно настроить данную РепликуСет несколькими способами:
- Использовать 1 сервер и запустить 3 экземпляра самой mongoDB.
- Использовать 3 сервера с mongoDB.
И так, для правильно работы ReplicaSet необходимо 3 запущенных экземпляра или сервера с монгой:
- Одна нода будет выступать как арбитр и не будет принимать на себя никакие данные. Его работа, заключается в том, чтобы выбрать того, кто будет сервером PRIMARY (Выступает как балансировщик- это не совсем правильно, но похоже).
- Один сервер выступает в качестве PRIMARY сервера.
- Один сервер выступает в качестве SECONDARY сервера.
СПОСОБ 1 — используем один сервер
В целом, мой конфиг выглядит следующим образом:
cat /etc/mongod.conf
[codesyntax lang="php" blockstate="collapsed"]
1 2 3 4 5 6 7 8 9 10 11 |
systemLog: destination: file logAppend: true path: /var/log/mongodb/mongod.log storage: dbPath: /var/lib/mongo journal: enabled: true processManagement: net: port: 27017 |
[/codesyntax]
Каждый экземпляр монги, будет создаваться со своим процессом, выделенным портом и своей базой. Начнем с БД, создаем папки:
Запускаем сервер в качестве SECONDARY (слейв):
mongod --dbpath /var/lib/mongo/my_database_2 --port 27002 --replSet My_Replica_Set --fork --logpath /var/log/mongodb/my_database_2.log
- —dbpath — Данная опция указывает на папку где лежат ( будут лежать) базы данных.
- —port — Данная опция задает порт для подключения клиентов.
- —replSet — Данная опция служит в качестве названия самой РС и должно быть одинаково для всех нод/экземпляров mongod
- —fork — Данная опция запускает mongod в режиме демона.
- —logpath — Данная опция указывает в какой файл будет перенаправлятся вывод.
Проверяем, стартанули ли все экземпляры:
ps aux | grep mongo| grep -Ev "grep"
[codesyntax lang="php" blockstate="collapsed"]
1 2 3 4 5 6 |
root 14469 0.0 0.1 121296 1220 pts/0 Sl+ 08:41 0:00 mongo mongod 52795 0.7 3.8 353404 38612 ? Sl 14:07 0:06 /usr/bin/mongod -f /etc/mongod.conf root 53147 0.5 4.1 406144 41688 ? Sl 14:14 0:01 mongod --dbpath /var/lib/mongo/my_database_1 --port 27001 --replSet My_Replica_Set --fork --logpath /var/log/mongodb/my_database_1.log root 53175 0.5 4.1 406140 41216 ? Sl 14:14 0:01 mongod --dbpath /var/lib/mongo/my_database_2 --port 27002 --replSet My_Replica_Set --fork --logpath /var/log/mongodb/my_database_2.log root 53207 0.5 4.3 406140 43724 ? Sl 14:15 0:01 mongod --dbpath /var/lib/mongo/my_database_3 --port 27003 --replSet My_Replica_Set --fork --logpath /var/log/mongodb/my_database_3.log |
[/codesyntax]
Как видно с вывода, все четко запустилось.
Настройка PRIMARY сервера
Подключаемся к серверу:
mongo --host 127.0.0.1 --port 27001
Проверяем статус RS:
> rs.status()
[codesyntax lang="php" blockstate="collapsed"]
1 2 3 4 5 6 7 8 9 |
rs.status() { "info" : "run rs.initiate(…) if not yet done for the set", "ok" : 0, "errmsg" : "no replset config has been received", "code" : 94, "codeName" : "NotYetInitialized" } |
[/codesyntax]
> rs.initiate({"_id" : "My_Replica_Set", members : [ {"_id" : 0, priority : 3, host : "127.0.0.1:27001"}, {"_id" : 1, host : "127.0.0.1:27002"},
{"_id" : 2, host : "127.0.0.1:27003", arbiterOnly : true} ] });
[codesyntax lang="php" blockstate="collapsed"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
My_Replica_Set:PRIMARY> rs.status() { "set" : "My_Replica_Set", "date" : ISODate("2019-12-01T08:10:02.573Z"), "myState" : 1, "term" : NumberLong(1), "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "heartbeatIntervalMillis" : NumberLong(2000), "majorityVoteCount" : 2, "writeMajorityCount" : 2, "optimes" : { "lastCommittedOpTime" : { "ts" : Timestamp(1575187796, 1), "t" : NumberLong(1) }, "lastCommittedWallTime" : ISODate("2019-12-01T08:09:56.232Z"), "readConcernMajorityOpTime" : { "ts" : Timestamp(1575187796, 1), "t" : NumberLong(1) }, "readConcernMajorityWallTime" : ISODate("2019-12-01T08:09:56.232Z"), "appliedOpTime" : { "ts" : Timestamp(1575187796, 1), "t" : NumberLong(1) }, "durableOpTime" : { "ts" : Timestamp(1575187796, 1), "t" : NumberLong(1) }, "lastAppliedWallTime" : ISODate("2019-12-01T08:09:56.232Z"), "lastDurableWallTime" : ISODate("2019-12-01T08:09:56.232Z") }, "lastStableRecoveryTimestamp" : Timestamp(1575187796, 1), "lastStableCheckpointTimestamp" : Timestamp(1575187796, 1), "electionCandidateMetrics" : { "lastElectionReason" : "electionTimeout", "lastElectionDate" : ISODate("2019-12-01T08:08:55.782Z"), "termAtElection" : NumberLong(1), "lastCommittedOpTimeAtElection" : { "ts" : Timestamp(0, 0), "t" : NumberLong(-1) }, "lastSeenOpTimeAtElection" : { "ts" : Timestamp(1575187725, 1), "t" : NumberLong(-1) }, "numVotesNeeded" : 2, "priorityAtElection" : 3, "electionTimeoutMillis" : NumberLong(10000), "numCatchUpOps" : NumberLong(-368855360), "newTermStartDate" : ISODate("2019-12-01T08:08:56.224Z"), "wMajorityWriteAvailabilityDate" : ISODate("2019-12-01T08:08:56.731Z") }, "members" : [ { "_id" : 0, "name" : "127.0.0.1:27001", "ip" : "127.0.0.1", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 378, "optime" : { "ts" : Timestamp(1575187796, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2019-12-01T08:09:56Z"), "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "could not find member to sync from", "electionTime" : Timestamp(1575187735, 1), "electionDate" : ISODate("2019-12-01T08:08:55Z"), "configVersion" : 1, "self" : true, "lastHeartbeatMessage" : "" }, { "_id" : 1, "name" : "127.0.0.1:27002", "ip" : "127.0.0.1", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 77, "optime" : { "ts" : Timestamp(1575187796, 1), "t" : NumberLong(1) }, "optimeDurable" : { "ts" : Timestamp(1575187796, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2019-12-01T08:09:56Z"), "optimeDurableDate" : ISODate("2019-12-01T08:09:56Z"), "lastHeartbeat" : ISODate("2019-12-01T08:10:01.839Z"), "lastHeartbeatRecv" : ISODate("2019-12-01T08:10:00.788Z"), "pingMs" : NumberLong(0), "lastHeartbeatMessage" : "", "syncingTo" : "127.0.0.1:27001", "syncSourceHost" : "127.0.0.1:27001", "syncSourceId" : 0, "infoMessage" : "", "configVersion" : 1 }, { "_id" : 2, "name" : "127.0.0.1:27003", "ip" : "127.0.0.1", "health" : 1, "state" : 7, "stateStr" : "ARBITER", "uptime" : 77, "lastHeartbeat" : ISODate("2019-12-01T08:10:01.842Z"), "lastHeartbeatRecv" : ISODate("2019-12-01T08:10:01.655Z"), "pingMs" : NumberLong(0), "lastHeartbeatMessage" : "", "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "", "configVersion" : 1 } ], "ok" : 1, "$clusterTime" : { "clusterTime" : Timestamp(1575187796, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } }, "operationTime" : Timestamp(1575187796, 1) } My_Replica_Set:PRIMARY> |
[/codesyntax]
Чтобы выйти, используйте:
>·quit()
connecting to: mongodb://127.0.0.1:27002/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("ddfc569c-2e26-4e3e-a60d-3051fffe44a7") }
MongoDB server version: 4.2.1
Проверяем статус:
rs.status()Получаем одинаковый вывод. Можно с него выйти уже.
Подключаемся к арбитру серверу:
# mongo --host 127.0.0.1 --port 27003
connecting to: mongodb://127.0.0.1:27003/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("9866925c-04d8-4307-b45a-7c2f740a6726") }
MongoDB server version: 4.2.1
My_Replica_Set:ARBITER>
Аналогично с арбитром. Видим что каждый из 3-х экземпляров, выступает как часть My_Replica_Set репликасет-а.
Но сейчас, протестируем падение (отказ от работы) PRIMARY сервера. Для начала, смотрим какие соединения открыты:
netstat -lntpu | grep mongod
[codesyntax lang="php" blockstate="collapsed"]
1 2 3 4 |
tcp 0 0 127.0.0.1:27017 0.0.0.0:* LISTEN 52795/mongod tcp 0 0 0.0.0.0:27001 0.0.0.0:* LISTEN 53147/mongod tcp 0 0 0.0.0.0:27002 0.0.0.0:* LISTEN 53175/mongod tcp 0 0 0.0.0.0:27003 0.0.0.0:* LISTEN 53207/mongod |
[/codesyntax]
Видим, что PRIMARY сервер использует 53147 PID, завершим его:
[codesyntax lang="php" blockstate="collapsed"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
My_Replica_Set:ARBITER> rs.status() { "set" : "My_Replica_Set", "date" : ISODate("2019-12-01T08:16:48.928Z"), "myState" : 7, "term" : NumberLong(2), "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "heartbeatIntervalMillis" : NumberLong(2000), "majorityVoteCount" : 2, "writeMajorityCount" : 2, "optimes" : { "lastCommittedOpTime" : { "ts" : Timestamp(1575188176, 1), "t" : NumberLong(1) }, "lastCommittedWallTime" : ISODate("2019-12-01T08:16:16.282Z"), "readConcernMajorityOpTime" : { "ts" : Timestamp(1575188176, 1), "t" : NumberLong(1) }, "readConcernMajorityWallTime" : ISODate("2019-12-01T08:16:16.282Z"), "appliedOpTime" : { "ts" : Timestamp(1575188176, 1), "t" : NumberLong(1) }, "durableOpTime" : { "ts" : Timestamp(0, 0), "t" : NumberLong(-1) }, "lastAppliedWallTime" : ISODate("2019-12-01T08:16:16.282Z"), "lastDurableWallTime" : ISODate("1970-01-01T00:00:00Z") }, "lastStableRecoveryTimestamp" : Timestamp(0, 0), "lastStableCheckpointTimestamp" : Timestamp(0, 0), "members" : [ { "_id" : 0, "name" : "127.0.0.1:27001", "ip" : "127.0.0.1", "health" : 0, "state" : 8, "stateStr" : "(not reachable/healthy)", "uptime" : 0, "optime" : { "ts" : Timestamp(0, 0), "t" : NumberLong(-1) }, "optimeDurable" : { "ts" : Timestamp(0, 0), "t" : NumberLong(-1) }, "optimeDate" : ISODate("1970-01-01T00:00:00Z"), "optimeDurableDate" : ISODate("1970-01-01T00:00:00Z"), "lastHeartbeat" : ISODate("2019-12-01T08:16:48.059Z"), "lastHeartbeatRecv" : ISODate("2019-12-01T08:16:24.197Z"), "pingMs" : NumberLong(0), "lastHeartbeatMessage" : "Error connecting to 127.0.0.1:27001 :: caused by :: Connection refused", "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "", "configVersion" : -1 }, { "_id" : 1, "name" : "127.0.0.1:27002", "ip" : "127.0.0.1", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 483, "optime" : { "ts" : Timestamp(1575188205, 1), "t" : NumberLong(2) }, "optimeDurable" : { "ts" : Timestamp(1575188205, 1), "t" : NumberLong(2) }, "optimeDate" : ISODate("2019-12-01T08:16:45Z"), "optimeDurableDate" : ISODate("2019-12-01T08:16:45Z"), "lastHeartbeat" : ISODate("2019-12-01T08:16:48.018Z"), "lastHeartbeatRecv" : ISODate("2019-12-01T08:16:48.646Z"), "pingMs" : NumberLong(0), "lastHeartbeatMessage" : "", "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "", "electionTime" : Timestamp(1575188194, 1), "electionDate" : ISODate("2019-12-01T08:16:34Z"), "configVersion" : 1 }, { "_id" : 2, "name" : "127.0.0.1:27003", "ip" : "127.0.0.1", "health" : 1, "state" : 7, "stateStr" : "ARBITER", "uptime" : 743, "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "", "configVersion" : 1, "self" : true, "lastHeartbeatMessage" : "" } ], "ok" : 1 } |
[/codesyntax]
mongod --dbpath /var/lib/mongo/my_database_1 --port 27001 --replSet My_Replica_Set --fork --logpath /var/log/mongodb/my_database_1.log
[codesyntax lang="php" blockstate="collapsed"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
My_Replica_Set:ARBITER> rs.status() { "set" : "My_Replica_Set", "date" : ISODate("2019-12-01T08:18:33.942Z"), "myState" : 7, "term" : NumberLong(2), "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "heartbeatIntervalMillis" : NumberLong(2000), "majorityVoteCount" : 2, "writeMajorityCount" : 2, "optimes" : { "lastCommittedOpTime" : { "ts" : Timestamp(1575188305, 1), "t" : NumberLong(2) }, "lastCommittedWallTime" : ISODate("2019-12-01T08:18:25.321Z"), "readConcernMajorityOpTime" : { "ts" : Timestamp(1575188305, 1), "t" : NumberLong(2) }, "readConcernMajorityWallTime" : ISODate("2019-12-01T08:18:25.321Z"), "appliedOpTime" : { "ts" : Timestamp(1575188305, 1), "t" : NumberLong(2) }, "durableOpTime" : { "ts" : Timestamp(0, 0), "t" : NumberLong(-1) }, "lastAppliedWallTime" : ISODate("2019-12-01T08:18:25.321Z"), "lastDurableWallTime" : ISODate("1970-01-01T00:00:00Z") }, "lastStableRecoveryTimestamp" : Timestamp(0, 0), "lastStableCheckpointTimestamp" : Timestamp(0, 0), "members" : [ { "_id" : 0, "name" : "127.0.0.1:27001", "ip" : "127.0.0.1", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 5, "optime" : { "ts" : Timestamp(1575188305, 1), "t" : NumberLong(2) }, "optimeDurable" : { "ts" : Timestamp(1575188305, 1), "t" : NumberLong(2) }, "optimeDate" : ISODate("2019-12-01T08:18:25Z"), "optimeDurableDate" : ISODate("2019-12-01T08:18:25Z"), "lastHeartbeat" : ISODate("2019-12-01T08:18:32.310Z"), "lastHeartbeatRecv" : ISODate("2019-12-01T08:18:32.709Z"), "pingMs" : NumberLong(0), "lastHeartbeatMessage" : "", "syncingTo" : "127.0.0.1:27002", "syncSourceHost" : "127.0.0.1:27002", "syncSourceId" : 1, "infoMessage" : "", "configVersion" : 1 }, { "_id" : 1, "name" : "127.0.0.1:27002", "ip" : "127.0.0.1", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 588, "optime" : { "ts" : Timestamp(1575188305, 1), "t" : NumberLong(2) }, "optimeDurable" : { "ts" : Timestamp(1575188305, 1), "t" : NumberLong(2) }, "optimeDate" : ISODate("2019-12-01T08:18:25Z"), "optimeDurableDate" : ISODate("2019-12-01T08:18:25Z"), "lastHeartbeat" : ISODate("2019-12-01T08:18:32.097Z"), "lastHeartbeatRecv" : ISODate("2019-12-01T08:18:32.746Z"), "pingMs" : NumberLong(0), "lastHeartbeatMessage" : "", "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "", "electionTime" : Timestamp(1575188194, 1), "electionDate" : ISODate("2019-12-01T08:16:34Z"), "configVersion" : 1 }, { "_id" : 2, "name" : "127.0.0.1:27003", "ip" : "127.0.0.1", "health" : 1, "state" : 7, "stateStr" : "ARBITER", "uptime" : 848, "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "", "configVersion" : 1, "self" : true, "lastHeartbeatMessage" : "" } ], "ok" : 1 } |
[/codesyntax]
[codesyntax lang="php" blockstate="collapsed"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
My_Replica_Set:ARBITER> rs.config() { "_id" : "My_Replica_Set", "version" : 1, "protocolVersion" : NumberLong(1), "writeConcernMajorityJournalDefault" : true, "members" : [ { "_id" : 0, "host" : "127.0.0.1:27001", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 3, "tags" : { }, "slaveDelay" : NumberLong(0), "votes" : 1 }, { "_id" : 1, "host" : "127.0.0.1:27002", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 1, "tags" : { }, "slaveDelay" : NumberLong(0), "votes" : 1 }, { "_id" : 2, "host" : "127.0.0.1:27003", "arbiterOnly" : true, "buildIndexes" : true, "hidden" : false, "priority" : 0, "tags" : { }, "slaveDelay" : NumberLong(0), "votes" : 1 } ], "settings" : { "chainingAllowed" : true, "heartbeatIntervalMillis" : 2000, "heartbeatTimeoutSecs" : 10, "electionTimeoutMillis" : 10000, "catchUpTimeoutMillis" : -1, "catchUpTakeoverDelayMillis" : 30000, "getLastErrorModes" : { }, "getLastErrorDefaults" : { "w" : 1, "wtimeout" : 0 }, "replicaSetId" : ObjectId("5de3750db33af2d9538b8b48") } } |
[/codesyntax]
switched to db admin
My_Replica_Set:PRIMARY> db.shutdownServer()
Завершится 1-й сервер. Аналогичные действия выполняем с остальными.
PS: Необходимо потушить арбитра,а потом 2-й сервер!
mongo --host 127.0.0.1 --port 27003
MongoDB shell version v4.2.1
connecting to: mongodb://127.0.0.1:27003/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("dc67e627-051c-4276-9338-bbece1282199") }
MongoDB server version: 4.2.1
My_Replica_Set:ARBITER> use admin
switched to db admin
My_Replica_Set:ARBITER> db.shutdownServer()
2019-12-01T14:23:15.457+0600 I NETWORK [js] DBClientConnection failed to receive message from 127.0.0.1:27003 - HostUnreachable: Connection closed by peer
server should be down…
2019-12-01T14:23:15.460+0600 I NETWORK [js] trying reconnect to 127.0.0.1:27003 failed
2019-12-01T14:23:15.460+0600 I NETWORK [js] reconnect 127.0.0.1:27003 failed failed
2019-12-01T14:23:15.462+0600 I NETWORK [js] trying reconnect to 127.0.0.1:27003 failed
2019-12-01T14:23:15.462+0600 I NETWORK [js] reconnect 127.0.0.1:27003 failed failed
теперь тушим второй сервер:
mongo --host 127.0.0.1 --port 27002
MongoDB shell version v4.2.1
connecting to: mongodb://127.0.0.1:27002/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("66eae0aa-1390-4f99-bc89-9f9f05685ec1") }
MongoDB server version: 4.2.1
My_Replica_Set:SECONDARY> use admin
switched to db admin
My_Replica_Set:SECONDARY> db.shutdownServer()
2019-12-01T14:24:39.601+0600 I NETWORK [js] DBClientConnection failed to receive message from 127.0.0.1:27002 - HostUnreachable: Connection closed by peer
server should be down…
2019-12-01T14:24:39.605+0600 I NETWORK [js] trying reconnect to 127.0.0.1:27002 failed
2019-12-01T14:24:39.606+0600 I NETWORK [js] reconnect 127.0.0.1:27002 failed failed
2019-12-01T14:24:39.608+0600 I NETWORK [js] trying reconnect to 127.0.0.1:27002 failed
2019-12-01T14:24:39.609+0600 I NETWORK [js] reconnect 127.0.0.1:27002 failed failed
Выполняем проверку:
ps aux | grep mongod | grep -Ev "grep"
должно быть пусто
удаляем созданные базы:
rm -rf /var/lib/mongo/{my_database_1,my_database_2,my_database_3}
СПОСОБ 2 — используем мульти-ноды
У меня, в качестве примера, используется:
- PRIMARY — 192.168.13.161 mongodb0
- SECONDARY — 192.168.13.147 mongodb1
- ARBITER — 192.168.13.142 mongodb2
Выполняем установку монги на каждой из нод и приступаем к настройке.
Создаем папку где будут лежать базы:
mkdir /home/mongodb
PS: Стандартная папка где хранятся базы — /var/lib/mongo и можно использовать именно ее.
Я в самом конфиге ничего не менял, оставил как и было.
Запускаем сервер:
systemctl restart mongod
PS: на каждой ноде!
Запуск PRIMARY сервера
И так, запускаем экземпляр:
Смотрим чтобы данный экземпляр, запустился:
ps uax | grep -E "mongod" | grep -Ev "grep"
Как видно с вывода, все четко работает.
Запуск SECONDARY сервера
И так, запускаем экземпляр:
mongod --dbpath /home/mongodb --bind_ip 192.168.13.147 --port 27001 --replSet My_Replica_Set --fork --logpath /var/log/mongodb/My_Replica_Set_SECONDARY.log --pidfilepath /var/run/mongodb/My_Replica_Set_SECONDARY.pid
Запуск ARBITER сервера
И так, запускаем экземпляр:
Настройка реплики
Подключаемся к серверу:
Так как РС еще не настроена, получили ошибку. Сейчас настроим ее:
инициализируем только один сервер:
Проверка SECONDARY сервера
Подключаемся снова и проверяем статус. У меня все заработало. Осталось проверить на остальных серверах
mongo --host 192.168.13.147 --port 27001
Подключаемся снова и проверяем статус. У меня все заработало. Осталось проверить на остальных серверах
mongo --host 192.168.13.142 --port 27001
При такой настройке имеется и недостатки — например, когда сервер упадет, то он не подымится автоматически. Есть костыльное решение — создать bash скрипт, который будет проверять PID файл процесса. Если его не окажется, то он будет запускать экземпляр монги.
==================================================
Обновление MongoDB на нодах,которые находятся в Replica Set
Обновление Secondary-нод
1.На одной из Secondary-нод останавливаем mongodb-службу
|
use admin
|
db.shutdownServer()
|
2. Обновляем пакеты Mongodb
# yum update
|
3.Запускаем mongodb-службу
# systemctl start mongod
|
Проверяем корректность запуска
# systemctl status mongod
|
4. На Primary-ноде проверяем,что обновленная Secondary-нода добавлена в Replica Set
rs.status()
|
Аналогично обновляем все остальные Secondary-ноды
Обновление Primary Node
На Primary-ноде выполняем
1.Принудительный перевод Primary-ноды в Secondary
rs.stepDown()
|
2.Проверяем,что была выбрана новая Primary-нода и все Secondary-ноды сейчас реплицируются с новой Primary-нодой.
Дождаться окончания процесса синхронизации всех Secondary-нод с новой Primary-нодой
rs.status()
|
3.Выполняем на бывшей Primary-ноде(сейчас она уже Secondary-нода) те же команды,что выполнялись для обновления Secondary-нод
4. На Primary-ноде проверяем,что обновленная Secondary-нода добавлена в Replica Set
rs.status()
|
Таким образом все ноды в Replica Set были обновлены
Полезные команды Репликация/Replica Set в MongoDB
> rs.[TAB] — для просмотра существующих команд по реликации
|
Просмотр конфигурации репликации
rs.conf()
|
Просмотр состояния репликации
> rs.status()
|
Просмотр членов репликации
> rs.status()['members']
|
Keep an eye on the configVersion key of each member. Every
change in the replica set’s configuration increments the value of
configVersion by one. This can be handy for a members’s current
configuration state.
Проверка,выступает ли нода мастером репликации
> rs.isMaster()['ismaster']
|
Принудительный перевод роли мастера между нодами, например, перевести роль мастера с 1-й ноды на 3-ю ноду
Например, есть 3 ноды
|
1-нода-primary
2-нода-secondary
3-нода-secondary
|
Алгоритм работы
1. На второй ноде(secondary) выполняем команду, которая вынуждает эту ноду принудительно оставаться в статусе secondary и не принимать участие в выборе нового мастера в течение 120 секунд
rs.freeze(120)
|
2. На текущем мастере(нода 1) выполняем команду, переводя ее принудительно в статус secondary
rs.stepDown()
|
Проверяем,что нода-1 стала сейчас secondary
rs.isMaster()['ismaster']
|
3.Проверить на ноде-3,что она стала primary
rs.isMaster()['ismaster']
|
Изменение параметров репликации(все команды должны выполнятся на текущем мастере)
Сохраняем состояние репликации в переменную cfg
rs0:PRIMARY>cfg = rs.conf()
|
Изменяем интересующий нас параметр
rs0:PRIMARY>cfg.settings.heartbeatTimeoutSecs=4
|
Загружаем параметры репликации из переменной cfg
|
rs0:PRIMARY>rs.reconfig(cfg)
|
Проверяем состояние репликации
rs0:PRIMARY>rs.conf()
|
Как работает репликация MongoDB?
Primary записывает все свои операции(только по добавлению/удалению/изменению) в Oplog,который представляет собой коллекцию(таблицу) в базе данных с именем local и эта коллекция реплицируется на все Secondary-ноды, и применяется на этих Secondary-нодах
Отчет о состоянии репликации с точки зрения Primary-сервера
rs0:PRIMARY> rs.printReplicationInfo()
|
1
2
3
4
5
|
configured oplog size: 990MB
log length start to end: 4047058secs (1124.18hrs)
oplog first event time: Fri Jul 06 2019 22:37:08 GMT+0100 (BST)
oplog last event time: Wed Aug 22 2019 18:48:06 GMT+0100 (BST)
now: Wed Aug 22 2019 18:48:15 GMT+0100 (BST)
|
Отчет о состоянии репликации с точки зрения Secondary-сервера
rs0:SECONDARY> rs.printSlaveReplicationInfo()
|
source: db01:27017
syncedTo: Wed Aug 22 2019 18:48:06 GMT+0100 (BST)
0 secs (0 hrs) behind the primary
|
Как определяется отставание/ между первичной и вторичной нодами?
MongoDВ знает временную метку последней записи в oplog на мастере
oplog last event time: Wed Aug 22 2019 18:48:06 GMT+0100 (BST)
|
и сверяет ее с временной меткой oplog на вторичном сервере
syncedTo: Wed Aug 22 2019 18:48:06 GMT+0100 (BST)
|