Репликация в MongoDB

Репликация в MongoDB

И так, сейчас стоит следующая задача — это настроить репликацию с MongoDB. Если брать во внимание mysql, то у нее есть master-master и master-slave репликация, но с монгой немного не так. MongoDB имеет 2 вида репликации:

  • Реплисеты (Replica Sets)
  • Ведущий-ведомый (Master-Slave)

Я в своей статье «Репликация в MongoDB» расскажу о них и приведу готовые реализации.

Установка MongoDB в Unix/Linux

По установке монги, я рекомендую использовать мою статью:

Установка MongoDB в Unix/Linux

Я постарался рассказать как можно больше информации о ней и собрал в одно место. Если есть необходимость, ознакомьтесь.

Репликация в MongoDB

Хочу сказать что репликация вида master-slave не рекомендуется разработчиками. Но для общего развития, я приведу ода варианта. Но начнем с правильного решения — с репликасет.

Репликация MongoDB с Replica set

Суть ReplicaSet заключается в том, что она в себе сохраняет одинаковые наборы данных. Один сервер, должен выступать в качестве основного сервера ( на него будут поступать все данные — он же ведущий, он же  PRIMARY), а все остальные — являются вторичными ( они сохраняют копии данных с  PRIMARY — они же ведомые, они же SECONDARYs).

Можно настроить данную РепликуСет несколькими способами:

  • Использовать 1 сервер и запустить 3 экземпляра самой mongoDB.
  • Использовать 3 сервера с mongoDB.

И так, для правильно работы ReplicaSet необходимо 3 запущенных экземпляра или сервера с монгой:

  • Одна нода будет выступать как арбитр и не будет принимать на себя никакие данные. Его работа, заключается в том, чтобы выбрать того, кто будет сервером PRIMARY (Выступает как балансировщик- это не совсем правильно, но похоже).
  • Один сервер выступает в качестве PRIMARY сервера.
  • Один сервер выступает в качестве SECONDARY сервера.

В дальнейшем, я РепликуСет обозначу как «РС» (от русс. — РепликуСет) или «RS» (от анг яз — ReplicaSet) и буду использовать данное обозначение в своей статье.

-===СПОСОБ 1 — используем один сервер===-

В целом, мой конфиг выглядит следующим образом:

systemLog:
  destination: file
  logAppend: true
  path: /var/log/mongodb/mongod.log
storage:
  dbPath: /var/lib/mongo
  journal:
    enabled: true
processManagement:
net:
  port: 27017

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

# mkdir /var/lib/mongo/{my_database_1,my_database_2,my_database_3}

Создание самих баз и установка необходимого владельца:

# chown mongod:mongod /var/lib/mongo/{my_database_1,my_database_2,my_database_3}

Запускаем сервер в качестве PRIMARY (Мастер):

# mongod --dbpath /var/lib/mongo/my_database_1 --port 27001 --replSet My_Replica_Set --fork --logpath /var/log/mongodb/my_database_1.log

about to fork child process, waiting until server is ready for connections.
forked process: 53147
child process started successfully, parent exiting

Запускаем сервер в качестве SECONDARY (слейв):

# mongod --dbpath /var/lib/mongo/my_database_2 --port 27002 --replSet My_Replica_Set --fork --logpath /var/log/mongodb/my_database_2.log

about to fork child process, waiting until server is ready for connections.
forked process: 53175
child process started successfully, parent exiting

Запускаем сервер в качестве арбитра (не принимающим данных):

# mongod --dbpath /var/lib/mongo/my_database_3 --port 27003 --replSet My_Replica_Set --fork --logpath /var/log/mongodb/my_database_3.log

about to fork child process, waiting until server is ready for connections.
forked process: 53207
child process started successfully, parent exiting

  • —dbpath — Данная опция указывает на папку где лежат ( будут лежать) базы данных.
  • —port — Данная опция задает порт для подключения клиентов.
  • —replSet — Данная опция служит в качестве названия самой РС и должно быть одинаково для всех нод/экземпляров mongod
  • —fork — Данная опция запускает mongod в режиме демона.
  • —logpath — Данная опция указывает в какой файл будет перенаправлятся вывод.

Проверяем, стартанули ли все экземпляры:

# ps aux | grep mongo| grep -Ev "grep"

И получаем:

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

Как видно с вывода, все четко запустилось.

Настройка PRIMARY сервера

Подключаемся к серверу:

# mongo --host 127.0.0.1 --port 27001

Проверяем статус RS:

> rs.status()

Получаем ошибку:

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"
}

Так как РС еще не настроена, получили ошибку. Сейчас настроим ее:

> 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} ] });

И, проверяем статус Replica_Set сново:

My_Replica_Set:PRIMARY> rs.status()
{
	"set" : "My_Replica_Set",
	"date" : ISODate("2017-04-16T11:29:03.858Z"),
	"myState" : 1,
	"term" : NumberLong(1),
	"heartbeatIntervalMillis" : NumberLong(2000),
	"optimes" : {
		"lastCommittedOpTime" : {
			"ts" : Timestamp(1492342138, 1),
			"t" : NumberLong(1)
		},
		"appliedOpTime" : {
			"ts" : Timestamp(1492342138, 1),
			"t" : NumberLong(1)
		},
		"durableOpTime" : {
			"ts" : Timestamp(1492342138, 1),
			"t" : NumberLong(1)
		}
	},
	"members" : [
		{
			"_id" : 0,
			"name" : "127.0.0.1:27001",
			"health" : 1,
			"state" : 1,
			"stateStr" : "PRIMARY",
			"uptime" : 874,
			"optime" : {
				"ts" : Timestamp(1492342138, 1),
				"t" : NumberLong(1)
			},
			"optimeDate" : ISODate("2017-04-16T11:28:58Z"),
			"electionTime" : Timestamp(1492342007, 1),
			"electionDate" : ISODate("2017-04-16T11:26:47Z"),
			"configVersion" : 1,
			"self" : true
		},
		{
			"_id" : 1,
			"name" : "127.0.0.1:27002",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",
			"uptime" : 147,
			"optime" : {
				"ts" : Timestamp(1492342138, 1),
				"t" : NumberLong(1)
			},
			"optimeDurable" : {
				"ts" : Timestamp(1492342138, 1),
				"t" : NumberLong(1)
			},
			"optimeDate" : ISODate("2017-04-16T11:28:58Z"),
			"optimeDurableDate" : ISODate("2017-04-16T11:28:58Z"),
			"lastHeartbeat" : ISODate("2017-04-16T11:29:01.893Z"),
			"lastHeartbeatRecv" : ISODate("2017-04-16T11:29:03.585Z"),
			"pingMs" : NumberLong(0),
			"syncingTo" : "127.0.0.1:27001",
			"configVersion" : 1
		},
		{
			"_id" : 2,
			"name" : "127.0.0.1:27003",
			"health" : 1,
			"state" : 7,
			"stateStr" : "ARBITER",
			"uptime" : 147,
			"lastHeartbeat" : ISODate("2017-04-16T11:29:01.893Z"),
			"lastHeartbeatRecv" : ISODate("2017-04-16T11:29:03.361Z"),
			"pingMs" : NumberLong(0),
			"configVersion" : 1
		}
	],
	"ok" : 1
}
My_Replica_Set:PRIMARY> 

Чтобы выйти, используйте:

> quit()

проверяем остальные ноды. Подключаемся к SECONDARY серверу:

# mongo --host 127.0.0.1 --port 27002

Вывод:

MongoDB shell version v3.4.3
connecting to: mongodb://127.0.0.1:27002/
MongoDB server version: 3.4.3
My_Replica_Set:SECONDARY> 

Собственно, видно что все в порядке на сервере.

Проверяем статус:

> rs.status()

Получаем одинаковый вывод. Можно с него выйти уже.

Подключаемся к арбитру серверу:

# mongo --host 127.0.0.1 --port 27003

Вывод:

MongoDB shell version v3.4.3
connecting to: mongodb://127.0.0.1:27003/
MongoDB server version: 3.4.3
My_Replica_Set:ARBITER> 

Аналогично с арбитром. Видим что каждый из 3-х экземпляров, выступает как часть My_Replica_Set репликасет-а.

Но а сейчас, потестируем падение (отказ от работы) PRIMARY сервера. Для начала, смотрим какие соединения открыты:

# netstat -lntpu | grep mongod

Получаем:

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

Видим, что PRIMARY сервер использует 53147 PID, завершим его:

# kill -9 53147

И так, процесс завершен. Подключаемся к арбитру:

# mongo --host 127.0.0.1 --port 27003

И, проверяем статус репликасета:

My_Replica_Set:ARBITER> rs.status()
{
	"set" : "My_Replica_Set",
	"date" : ISODate("2017-04-16T11:44:58.979Z"),
	"myState" : 7,
	"term" : NumberLong(2),
	"heartbeatIntervalMillis" : NumberLong(2000),
	"optimes" : {
		"lastCommittedOpTime" : {
			"ts" : Timestamp(1492343008, 1),
			"t" : NumberLong(1)
		},
		"appliedOpTime" : {
			"ts" : Timestamp(1492343008, 1),
			"t" : NumberLong(1)
		},
		"durableOpTime" : {
			"ts" : Timestamp(0, 0),
			"t" : NumberLong(-1)
		}
	},
	"members" : [
		{
			"_id" : 0,
			"name" : "127.0.0.1:27001",
			"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("2017-04-16T11:44:58.574Z"),
			"lastHeartbeatRecv" : ISODate("2017-04-16T11:43:34.344Z"),
			"pingMs" : NumberLong(0),
			"lastHeartbeatMessage" : "Connection refused",
			"configVersion" : -1
		},
		{
			"_id" : 1,
			"name" : "127.0.0.1:27002",
			"health" : 1,
			"state" : 1,
			"stateStr" : "PRIMARY",
			"uptime" : 1100,
			"optime" : {
				"ts" : Timestamp(1492343094, 1),
				"t" : NumberLong(2)
			},
			"optimeDurable" : {
				"ts" : Timestamp(1492343094, 1),
				"t" : NumberLong(2)
			},
			"optimeDate" : ISODate("2017-04-16T11:44:54Z"),
			"optimeDurableDate" : ISODate("2017-04-16T11:44:54Z"),
			"lastHeartbeat" : ISODate("2017-04-16T11:44:58.562Z"),
			"lastHeartbeatRecv" : ISODate("2017-04-16T11:44:58.598Z"),
			"pingMs" : NumberLong(0),
			"electionTime" : Timestamp(1492343024, 1),
			"electionDate" : ISODate("2017-04-16T11:43:44Z"),
			"configVersion" : 1
		},
		{
			"_id" : 2,
			"name" : "127.0.0.1:27003",
			"health" : 1,
			"state" : 7,
			"stateStr" : "ARBITER",
			"uptime" : 1765,
			"configVersion" : 1,
			"self" : true
		}
	],
	"ok" : 1
}
My_Replica_Set:ARBITER> 

Наглядно видно, что  основной сервер в дауне  («stateStr» : «(not reachable/healthy)»), а сервер с id 1 стал PRIMARY. Снова запускаем упавший сервак ( экземпляр):

# mongod --dbpath /var/lib/mongo/my_database_1 --port 27001 --replSet My_Replica_Set --fork --logpath /var/log/mongodb/my_database_1.log

И смотрим что говорит нам арбитр:

# mongo --host 127.0.0.1 --port 27003

Получаем вывод:

My_Replica_Set:ARBITER> rs.status()
{
	"set" : "My_Replica_Set",
	"date" : ISODate("2017-04-16T11:49:03.284Z"),
	"myState" : 7,
	"term" : NumberLong(3),
	"heartbeatIntervalMillis" : NumberLong(2000),
	"optimes" : {
		"lastCommittedOpTime" : {
			"ts" : Timestamp(1492343331, 1),
			"t" : NumberLong(3)
		},
		"appliedOpTime" : {
			"ts" : Timestamp(1492343331, 1),
			"t" : NumberLong(3)
		},
		"durableOpTime" : {
			"ts" : Timestamp(0, 0),
			"t" : NumberLong(-1)
		}
	},
	"members" : [
		{
			"_id" : 0,
			"name" : "127.0.0.1:27001",
			"health" : 1,
			"state" : 1,
			"stateStr" : "PRIMARY",
			"uptime" : 49,
			"optime" : {
				"ts" : Timestamp(1492343331, 1),
				"t" : NumberLong(3)
			},
			"optimeDurable" : {
				"ts" : Timestamp(1492343331, 1),
				"t" : NumberLong(3)
			},
			"optimeDate" : ISODate("2017-04-16T11:48:51Z"),
			"optimeDurableDate" : ISODate("2017-04-16T11:48:51Z"),
			"lastHeartbeat" : ISODate("2017-04-16T11:48:58.649Z"),
			"lastHeartbeatRecv" : ISODate("2017-04-16T11:49:01.667Z"),
			"pingMs" : NumberLong(0),
			"electionTime" : Timestamp(1492343301, 1),
			"electionDate" : ISODate("2017-04-16T11:48:21Z"),
			"configVersion" : 1
		},
		{
			"_id" : 1,
			"name" : "127.0.0.1:27002",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",
			"uptime" : 1344,
			"optime" : {
				"ts" : Timestamp(1492343331, 1),
				"t" : NumberLong(3)
			},
			"optimeDurable" : {
				"ts" : Timestamp(1492343331, 1),
				"t" : NumberLong(3)
			},
			"optimeDate" : ISODate("2017-04-16T11:48:51Z"),
			"optimeDurableDate" : ISODate("2017-04-16T11:48:51Z"),
			"lastHeartbeat" : ISODate("2017-04-16T11:48:58.599Z"),
			"lastHeartbeatRecv" : ISODate("2017-04-16T11:49:01.715Z"),
			"pingMs" : NumberLong(0),
			"syncingTo" : "127.0.0.1:27001",
			"configVersion" : 1
		},
		{
			"_id" : 2,
			"name" : "127.0.0.1:27003",
			"health" : 1,
			"state" : 7,
			"stateStr" : "ARBITER",
			"uptime" : 2010,
			"configVersion" : 1,
			"self" : true
		}
	],
	"ok" : 1
}
My_Replica_Set:ARBITER> 

Смотрим какой конфиг имеет наша репликасет:

My_Replica_Set:ARBITER> rs.config()
{
	"_id" : "My_Replica_Set",
	"version" : 1,
	"protocolVersion" : NumberLong(1),
	"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" : 1,
			"tags" : {
				
			},
			"slaveDelay" : NumberLong(0),
			"votes" : 1
		}
	],
	"settings" : {
		"chainingAllowed" : true,
		"heartbeatIntervalMillis" : 2000,
		"heartbeatTimeoutSecs" : 10,
		"electionTimeoutMillis" : 10000,
		"catchUpTimeoutMillis" : 2000,
		"getLastErrorModes" : {
			
		},
		"getLastErrorDefaults" : {
			"w" : 1,
			"wtimeout" : 0
		},
		"replicaSetId" : ObjectId("58f354ec1c699206c06ee2c0")
	}
}
My_Replica_Set:ARBITER> 

С выводом уже становится понятным, что все возвратилось восвояси. Т.к я использовал одну машину и запустил 3 экземпляра с mongoDB, то я очищу. Для этого — подключаемся к основному серверу:

# mongo --host 127.0.0.1 --port 27001

И, выполняем:

My_Replica_Set:PRIMARY> use admin
switched to db admin
My_Replica_Set:PRIMARY> db.shutdownServer()

Завершится 1-й сервер. Аналогичные действия выполняем с остальными.

PS: Необходимо потушить арбитра,а потом 2-й сервер!

My_Replica_Set:ARBITER> use admin
switched to db admin
My_Replica_Set:ARBITER> db.shutdownServer()
server should be down...
2017-04-16T14:59:14.361+0300 I NETWORK  [thread1] trying reconnect to 127.0.0.1:27003 (127.0.0.1) failed
2017-04-16T14:59:14.361+0300 W NETWORK  [thread1] Failed to connect to 127.0.0.1:27003, in(checking socket for error after poll), reason: Connection refused
2017-04-16T14:59:14.361+0300 I NETWORK  [thread1] reconnect 127.0.0.1:27003 (127.0.0.1) failed failed 
2017-04-16T14:59:14.364+0300 I NETWORK  [thread1] trying reconnect to 127.0.0.1:27003 (127.0.0.1) failed
2017-04-16T14:59:14.364+0300 W NETWORK  [thread1] Failed to connect to 127.0.0.1:27003, in(checking socket for error after poll), reason: Connection refused
2017-04-16T14:59:14.364+0300 I NETWORK  [thread1] reconnect 127.0.0.1:27003 (127.0.0.1) failed failed 
> quit ()

И, последний экземпляр:

# mongo --host 127.0.0.1 --port 27002
MongoDB shell version v3.4.3
connecting to: mongodb://127.0.0.1:27002/
MongoDB server version: 3.4.3

My_Replica_Set:SECONDARY> use admin
switched to db admin
My_Replica_Set:SECONDARY> db.shutdownServer()
server should be down...
2017-04-16T15:00:03.140+0300 I NETWORK  [thread1] trying reconnect to 127.0.0.1:27002 (127.0.0.1) failed
2017-04-16T15:00:03.140+0300 W NETWORK  [thread1] Failed to connect to 127.0.0.1:27002, in(checking socket for error after poll), reason: Connection refused
2017-04-16T15:00:03.140+0300 I NETWORK  [thread1] reconnect 127.0.0.1:27002 (127.0.0.1) failed failed 
2017-04-16T15:00:03.142+0300 I NETWORK  [thread1] trying reconnect to 127.0.0.1:27002 (127.0.0.1) failed
2017-04-16T15:00:03.142+0300 W NETWORK  [thread1] Failed to connect to 127.0.0.1:27002, in(checking socket for error after poll), reason: Connection refused
2017-04-16T15:00:03.142+0300 I NETWORK  [thread1] reconnect 127.0.0.1:27002 (127.0.0.1) failed failed 
> quit()
[root@localhost ~]# 

Выполняем проверку:

[root@localhost ~]# ps aux | grep mongod | grep -Ev "grep"
mongod    52795  0.5  3.6 353404 36456 ?        Sl   14:07   0:18 /usr/bin/mongod -f /etc/mongod.conf
[root@localhost ~]# 

Ну, удаляем созданные базы:

# rm -rf /var/lib/mongo/{my_database_1,my_database_2,my_database_3}

Как-то так.

-===СПОСОБ 2 — используем мульти-ноды===-

У меня, в качестве примера, используется:

  • PRIMARY       — 192.168.13.161    mongodb0.linux-notes.org
  • SECONDARY — 192.168.13.147      mongodb1.linux-notes.org
  • ARBITER        — 192.168.13.142    mongodb2.linux-notes.org

Выполняем установку монги на каждой из нод и приступаем к настройке.

Создаем папку где будут лежать базы:

# mkdir /home/mongodb

На созданную папку выставляем необходимого владельца:

Debian:

# chown mongodb. /home/mongodb

Так же, создаем папку:

# mkdir /var/run/mongodb && chown mongodb. /var/run/mongodb

CenOS:

# chown mongod:mongod /home/mongodb

PS: Стандартная папка где хранятся базы — /var/lib/mongo и можно использовать именно ее.

Я в самом конфиге ничего не менял, оставил как и было.

Запускаем сервер:

# service mongod restart

PS: на каждой ноде!

Запуск PRIMARY сервера

И так, запускаем экземпляр:

# mongod --dbpath /home/mongodb --bind_ip 192.168.13.161 --port 27001 --replSet My_Replica_Set --fork --logpath /var/log/mongodb/My_Replica_Set_PRIMARY.log --pidfilepath /var/run/mongodb/My_Replica_Set_PRIMARY.pid
about to fork child process, waiting until server is ready for connections.
forked process: 50619
child process started successfully, parent exiting

Смотрим чтобы данный экземпляр, запустился:

# ps uax | grep -E "mongod" | grep -Ev "grep"

Получаем:

root      50619  2.6  4.1 406696 41800 ?        Sl   12:20   0:00 mongod --dbpath /home/mongodb --bind_ip 192.168.13.161 --port 27001 --replSet My_Replica_Set --fork --logpath /var/log/mongodb/My_Replica_Set_PRIMARY.log --pidfilepath /var/run/mongodb/My_Replica_Set_PRIMARY.pid

Как видно с вывода, все четко работает.

Запуск 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 сервера

И так, запускаем экземпляр:

# mongod --dbpath /home/mongodb --bind_ip 192.168.13.142 --port 27001 --replSet My_Replica_Set --fork --logpath /var/log/mongodb/My_Replica_Set_ARBITER.log

Если необходимо, выполняем проверку.

Настройка реплики

Подключаемся к серверу:

# mongo --host 192.168.13.161 --port 27001

Проверяем статус RS:

> rs.status()

-=== СПОСОБ 1 — прописать сразу все хосты===-

Так как РС еще не настроена, получили ошибку. Сейчас настроим ее:

> rs.initiate({"_id" : "My_Replica_Set", members : [ {"_id" : 0, priority : 3, host : "192.168.13.161:27001"}, {"_id" : 1, host : "192.168.13.147:27001"},
 {"_id" : 2, host : "192.168.13.142:27001", arbiterOnly : true} ] });

-=== СПОСОБ 1 — прописать хосты постепенно===-

ИЛИ, инициализируем только один сервер:

> rs.initiate( {
   _id : "My_Replica_Set",
   members: [ { _id : 0, host : "192.168.13.161:27001" } ]
})

Потом, прописываем еще один хост:

> rs.add("192.168.13.147:27001")

PS: Если нужно удалить, используем:

> rs.remove("192.168.13.147:27001")

И, нам нужен еще арбитр, по этому, прописываем:

> rs.addArb("192.168.13.142:27001")

Ничего сложного.

Проверка SECONDARY сервера

Подключаемся снова и проверяем статус. У меня все заработало. Осталось проверить на остальных серверах…

# mongo --host 192.168.13.147 --port 27001

Проверяем статус RS:

> rs.status()

Проверка ARBITER сервера

Подключаемся снова и проверяем статус. У меня все заработало. Осталось проверить на остальных серверах…

# mongo --host 192.168.13.142 --port 27001

Проверяем статус RS:

> rs.status()

И, проверяем статус Replica_Set сново.

При такой настройке имеется и недостатки — например, когда сервер упадет, то он не подымиться автоматически. Я придумал решение — создать bash скрипт, который будут проверять PID файл процесса. Если его не окажется, то запустить экземпляр монги.

Репликация MongoDB вида Master-Slave (Ведущий-ведомый )

Я уже говорил что данная идеология не очень хороша для решения репликации. Но как по мне, можно немного затюнить и использовать именно такой метод (использовать балансировщик, например HAproxy).

У меня имеется:

  • 192.168.13.161 — master.linux-notes.org
  • 192.168.13.147 — slave.linux-notes.org

Создаем папку где будут лежать базы:

# mkdir /home/mongodb

На созданную папку выставляем необходимого владельца:

Debian:

# chown mongodb. /home/mongodb

Так же, создаем папку:

# mkdir /var/run/mongodb && chown mongodb. /var/run/mongodb

CenOS:

# chown mongod:mongod /home/mongodb

PS: Стандартная папка где хранятся базы — /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

Проверяем что все стартануло:

# ps uax | grep -E "mongod" | grep -Ev "grep"

root 51599 1.8 4.2 394848 42468 ? Sl 18:01 0:00 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

Видим, что все запустилось отлично.

Подключаемся на слейв:

# mongo --host 192.168.13.161 --port 27001

Проверяем статус Master-а:

> rs.printReplicationInfo()

configured oplog size:   990MB
log length start to end: 0secs (0hrs)
oplog first event time:  Mon Apr 17 2017 12:47:07 GMT+0300 (EEST)
oplog last event time:   Mon Apr 17 2017 12:47:07 GMT+0300 (EEST)
now:                     Mon Apr 17 2017 19:14:07 GMT+0300 (EEST)
> 

И:

> db.serverStatus()

Вот и все.

Запуск Slave 

Проверяем доступность master-а со slave:

$  telnet 192.168.13.161 27001

Видно что имеется подключение. Идем далее……

Останавливаем сервер с монгой:

# service mongod stop 
# ps -aux | grep mongod| grep -Ev "grep"

Запускаем slave сервер:

# mongod --slave --dbpath /home/mongodb --bind_ip 192.168.13.147 --port 27001 --fork --logpath /var/log/mongodb/Slave.log --pidfilepath /var/run/mongodb/Slave.pid --source 192.168.13.161:27001

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

# ps -aux | grep mongo | grep -Ev "grep"

Вывод:

root       4967  5.5  4.6 301064 46696 ?        Sl   18:34   0:00 mongod --slave --dbpath /home/mongodb --bind_ip 192.168.13.147 --port 27001 --fork --logpath /var/log/mongodb/Slave.log --pidfilepath /var/run/mongodb/Slave.pid

Все отлично, осталось немного. Подключаемся на слейв:

# mongo --host 192.168.13.147 --port 27001

Настраиваем репликацию master-slave:

> use local
> db.sources.find()
> db.sources.insert( { host:"192.168.13.161:27001" } );
WriteResult({ "nInserted" : 1 })
>

И, смотрим что получилось:

> show dbs

Проверяем статус Slave:

> rs.printSlaveReplicationInfo()


source: 192.168.13.161:27001
 syncedTo: Mon Apr 17 2017 19:21:21 GMT+0300 (EEST)
 25 secs (0.01 hrs) behind the freshest member (no primary available at the moment)
source: 192.168.13.161:27001
 doing initial sync

Можно еще:

> rs.printReplicationInfo()

И:

> db.serverStatus()

Вам может потребоваться запустить синхронизацию для восстановления репликации:

> use admin
> db.runCommand( { resync: 1 } )

Чтобы потушить ноду, используйте:

> db.adminCommand({shutdown : 1, force : true})

А на этом, у меня все. Статья «Репликация в MongoDB» завершена.

One thought on “Репликация в MongoDB

  1. Спасибо! Монументальный сайт. Стиль очень нравится, чувствуется что написано профессионалом для профессионалов.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.