## mongodb复制(副本集)
mongodb副本集的好处:  
1. 保证数据的安全性  
2. 数据高可用  
3. 灾难恢复  
4. 无需停机维护  
5. 分布式读取数据  
###副本集的配置
需要准备至少三个节点来测试,本次为了方便使用同一台机器上的不同端口号启动三个节点:  
~~~
192.168.226.130:27017 node1
192.168.226.130:27018 node2
192.168.226.130:27019 node3
~~~
在/data/文件夹下创建三个数据库node1,node2,node3
```shell script
[root@moggledb data]# mkdir node1
[root@moggledb data]# mkdir node2
[root@moggledb data]# mkdir node3
[root@moggledb data]# mkdir log
[root@moggledb data]# ll
total 16
drwxr-xr-x. 2 root root 4096 May  5 20:12 log
drwxr-xr-x. 2 root root 4096 May  5 20:12 node1
drwxr-xr-x. 2 root root 4096 May  5 20:12 node2
drwxr-xr-x. 2 root root 4096 May  5 20:12 node3
```
使用配置文件启动方式,在node1下创建配置文件并复制到另外两个节点
```shell script
[root@moggledb data]# cd node1
[root@moggledb node1]# vi mongodb-node1.conf
dbpath=/data/node1
logpath=/data/log/mongodb-node1.log
logappend=true
fork=true
bind_ip=192.168.226.130
port=27017
replSet=rs0
```
保存退出,复制到另外连个节点中,并修改dbpath,logpath及port
```shell script
[root@moggledb node1]# cp mongodb-node1.conf ../node2/mongodb-node2.conf
[root@moggledb node1]# cp mongodb-node1.conf ../node3/mongodb-node3.conf
[root@moggledb node1]# vi ../node2/mongodb-node2.conf
dbpath=/data/node2
logpath=/data/log/mongodb-node2.log
logappend=true
fork=true
bind_ip=192.168.226.130
port=27018
replSet=rs0
[root@moggledb node2]# vi ../node3/mongodb-node3.conf
dbpath=/data/node3
logpath=/data/log/mongodb-node3.log
logappend=true
fork=true
bind_ip=192.168.226.130
port=27019
replSet=rs0
```
replSet为副本集名称,同一个副本集内的节点,值要一样。  
配置完毕,启动三个节点:
```shell script
[root@moggledb node2]# cd /usr/local/mongodb/bin/
[root@moggledb bin]# ./mongod -f /data/node1/mongodb-node1.conf
about to fork child process, waiting until server is ready for connections.
forked process: 2633
child process started successfully, parent exiting
[root@moggledb bin]# ./mongod -f /data/node2/mongodb-node2.conf
about to fork child process, waiting until server is ready for connections.
forked process: 2649
child process started successfully, parent exiting
[root@moggledb bin]# ./mongod -f /data/node3/mongodb-node3.conf
about to fork child process, waiting until server is ready for connections.
forked process: 2665
child process started successfully, parent exiting
[root@moggledb bin]# ps -ef |grep mongod
root       2633      1  1 20:23 ?        00:00:00 ./mongod -f /data/node1/mongodb-node1.conf
root       2649      1  2 20:24 ?        00:00:00 ./mongod -f /data/node2/mongodb-node2.conf
root       2665      1  3 20:24 ?        00:00:00 ./mongod -f /data/node3/mongodb-node3.conf
root       2680   2581  0 20:24 pts/0    00:00:00 grep mongod
[root@moggledb bin]#
```
三台节点启动成功。下面配置三个节点为副本集:
```shell script
[root@moggledb bin]# ./mongo --host 192.168.226.130 --port 27017
...
2020-05-05T20:23:43.992-0700 I CONTROL  [initandlisten]
> conf = {"_id":"rs0","members":[{"_id":0,"host":"192.168.226.130:27017"},{"_id":1,"host":"192.168.226.130:27018"},{"_id":2,"host":"192.168.226.130:27019"}]}
{
       "_id" : "rs0",
       "members" : [
               {
                       "_id" : 0,
                       "host" : "192.168.226.130:27017"
               },
               {
                       "_id" : 1,
                       "host" : "192.168.226.130:27018"
               },
               {
                       "_id" : 2,
                       "host" : "192.168.226.130:27019"
               }
       ]
}
> rs.initiate(conf)
{ "ok" : 1 }
rs0:OTHER> rs.isMaster()
{
       "setName" : "rs0",
       "setVersion" : 1,
       "ismaster" : true,
       "secondary" : false,
       "hosts" : [
               "192.168.226.130:27017",
               "192.168.226.130:27018",
               "192.168.226.130:27019"
       ],
       "primary" : "192.168.226.130:27017",
       "me" : "192.168.226.130:27017",
       "electionId" : ObjectId("5eb22f9c0520bca5e5033db3"),
       "maxBsonObjectSize" : 16777216,
       "maxMessageSizeBytes" : 48000000,
       "maxWriteBatchSize" : 1000,
       "localTime" : ISODate("2020-05-06T03:32:16.019Z"),
       "maxWireVersion" : 3,
       "minWireVersion" : 0,
       "ok" : 1
}
rs0:PRIMARY> rs.status()
{
       "set" : "rs0",
       "date" : ISODate("2020-05-06T03:33:29.129Z"),
       "myState" : 1,
       "members" : [
               {
                       "_id" : 0,
                       "name" : "192.168.226.130:27017",
                       "health" : 1,
                       "state" : 1,
                       "stateStr" : "PRIMARY",
                       "uptime" : 586,
                       "optime" : Timestamp(1588735898, 1),
                       "optimeDate" : ISODate("2020-05-06T03:31:38Z"),
                       "electionTime" : Timestamp(1588735900, 1),
                       "electionDate" : ISODate("2020-05-06T03:31:40Z"),
                       "configVersion" : 1,
                       "self" : true
               },
               {
                       "_id" : 1,
                       "name" : "192.168.226.130:27018",
                       "health" : 1,
                       "state" : 2,
                       "stateStr" : "SECONDARY",
                       "uptime" : 110,
                       "optime" : Timestamp(1588735898, 1),
                       "optimeDate" : ISODate("2020-05-06T03:31:38Z"),
                       "lastHeartbeat" : ISODate("2020-05-06T03:33:29.013Z"),
                       "lastHeartbeatRecv" : ISODate("2020-05-06T03:33:29.078Z"),
                       "pingMs" : 0,
                       "configVersion" : 1
               },
               {
                       "_id" : 2,
                       "name" : "192.168.226.130:27019",
                       "health" : 1,
                       "state" : 2,
                       "stateStr" : "SECONDARY",
                       "uptime" : 110,
                       "optime" : Timestamp(1588735898, 1),
                       "optimeDate" : ISODate("2020-05-06T03:31:38Z"),
                       "lastHeartbeat" : ISODate("2020-05-06T03:33:29.013Z"),
                       "lastHeartbeatRecv" : ISODate("2020-05-06T03:33:29.078Z"),
                       "pingMs" : 0,
                       "configVersion" : 1
               }
       ],
       "ok" : 1
}
```
当前节点为主节点PRIMARY,上面可以看出节点的详细信息。
副本集的主节点负责与客户端交互,进行读和写。从节点复制主机点数据,监听主节点 的心跳。
####副本集主从复制测试。
在主节点插入数据
```shell script
rs0:PRIMARY> show dbs
local  1.078GB
rs0:PRIMARY> use test
switched to db test
rs0:PRIMARY> db.coll.insert({"name":"zhangsan"})
WriteResult({ "nInserted" : 1 })
rs0:PRIMARY> db.coll.insert({"name":"lisi"})
WriteResult({ "nInserted" : 1 })
rs0:PRIMARY> db.coll.find()
{ "_id" : ObjectId("5eb230a80a6d7da784ff2c83"), "name" : "zhangsan" }
{ "_id" : ObjectId("5eb230ad0a6d7da784ff2c84"), "name" : "lisi" }
```
连接从节点:  
```shell script
[root@moggledb bin]# ./mongo --host 192.168.226.130 --port 27018
...
2020-05-05T20:24:21.584-0700 I CONTROL  [initandlisten]
rs0:SECONDARY> rs.slaveOk()
rs0:SECONDARY> show dbs
local  1.078GB
test   0.078GB
rs0:SECONDARY> use test
switched to db test
rs0:SECONDARY> db.coll.find()
{ "_id" : ObjectId("5eb230a80a6d7da784ff2c83"), "name" : "zhangsan" }
{ "_id" : ObjectId("5eb230ad0a6d7da784ff2c84"), "name" : "lisi" }
rs0:SECONDARY> rs.status()
{
       "set" : "rs0",
       "date" : ISODate("2020-05-06T03:45:56.163Z"),
       "myState" : 2,
       "syncingTo" : "192.168.226.130:27017",
       "members" : [
               {
                       "_id" : 0,
                       "name" : "192.168.226.130:27017",
                       "health" : 1,
                       "state" : 1,
                       "stateStr" : "PRIMARY",
                       "uptime" : 857,
                       "optime" : Timestamp(1588736173, 1),
                       "optimeDate" : ISODate("2020-05-06T03:36:13Z"),
                       "lastHeartbeat" : ISODate("2020-05-06T03:45:54.692Z"),
                       "lastHeartbeatRecv" : ISODate("2020-05-06T03:45:54.665Z"),
                       "pingMs" : 0,
                       "electionTime" : Timestamp(1588735900, 1),
                       "electionDate" : ISODate("2020-05-06T03:31:40Z"),
                       "configVersion" : 1
               },
               {
                       "_id" : 1,
                       "name" : "192.168.226.130:27018",
                       "health" : 1,
                       "state" : 2,
                       "stateStr" : "SECONDARY",
                       "uptime" : 1295,
                       "optime" : Timestamp(1588736173, 1),
                       "optimeDate" : ISODate("2020-05-06T03:36:13Z"),
                       "syncingTo" : "192.168.226.130:27017",
                       "configVersion" : 1,
                       "self" : true
               },
               {
                       "_id" : 2,
                       "name" : "192.168.226.130:27019",
                       "health" : 1,
                       "state" : 2,
                       "stateStr" : "SECONDARY",
                       "uptime" : 857,
                       "optime" : Timestamp(1588736173, 1),
                       "optimeDate" : ISODate("2020-05-06T03:36:13Z"),
                       "lastHeartbeat" : ISODate("2020-05-06T03:45:54.677Z"),
                       "lastHeartbeatRecv" : ISODate("2020-05-06T03:45:54.677Z"),
                       "pingMs" : 0,
                       "syncingTo" : "192.168.226.130:27017",
                       "configVersion" : 1
               }
       ],
       "ok" : 1
}
rs0:SECONDARY>
```
可以看出主节点插入数据,在从节点中也有数据,从节点只能读数据,不能写数据,主节点可以读写数据。
####故障转移
模拟主节点宕机,关闭主节点服务:
```shell script
[root@moggledb bin]# ./mongod --shutdown --dbpath=/data/node1
killing process with pid: 2633
[root@moggledb bin]#
```
再次查看从节点状态:  
```shell script
[root@moggledb bin]# mongo --host 192.168.226.130 --port 27018
...
2020-05-05T20:24:21.584-0700 I CONTROL  [initandlisten]
rs0:PRIMARY> rs.status()
{
       "set" : "rs0",
       "date" : ISODate("2020-05-06T03:52:08.238Z"),
       "myState" : 1,
       "members" : [
               {
                       "_id" : 0,
                       "name" : "192.168.226.130:27017",
                       "health" : 0,
                       "state" : 8,
                       "stateStr" : "(not reachable/healthy)",
                       "uptime" : 0,
                       "optime" : Timestamp(0, 0),
                       "optimeDate" : ISODate("1970-01-01T00:00:00Z"),
                       "lastHeartbeat" : ISODate("2020-05-06T03:52:07.354Z"),
                       "lastHeartbeatRecv" : ISODate("2020-05-06T03:50:23.111Z"),
                       "pingMs" : 0,
                       "lastHeartbeatMessage" : "Failed attempt to connect to 192.168.226.130:27017; couldn't connect to server 192.168.226.130:27017 (192.168.226.130), connection attem
pt failed",
                       "configVersion" : -1
               },
               {
                       "_id" : 1,
                       "name" : "192.168.226.130:27018",
                       "health" : 1,
                       "state" : 1,
                       "stateStr" : "PRIMARY",
                       "uptime" : 1667,
                       "optime" : Timestamp(1588736173, 1),
                       "optimeDate" : ISODate("2020-05-06T03:36:13Z"),
                       "electionTime" : Timestamp(1588737026, 1),
                       "electionDate" : ISODate("2020-05-06T03:50:26Z"),
                       "configVersion" : 1,
                       "self" : true
               },
               {
                       "_id" : 2,
                       "name" : "192.168.226.130:27019",
                       "health" : 1,
                       "state" : 2,
                       "stateStr" : "SECONDARY",
                       "uptime" : 1229,
                       "optime" : Timestamp(1588736173, 1),
                       "optimeDate" : ISODate("2020-05-06T03:36:13Z"),
                       "lastHeartbeat" : ISODate("2020-05-06T03:52:07.216Z"),
                       "lastHeartbeatRecv" : ISODate("2020-05-06T03:52:07.197Z"),
                       "pingMs" : 0,
                       "configVersion" : 1
               }
       ],
       "ok" : 1
}
```
从上面状态信息可以看出,27017节点无心跳,27018节点变为主节点:`{"stateStr":"PRIMARY"}`  
如果此时重启27017节点:
```shell script
[root@moggledb bin]# ./mongod -f /data/node1/mongodb-node1.conf
rs0:SECONDARY> rs.status()
{
       "set" : "rs0",
       "date" : ISODate("2020-05-06T03:54:46.892Z"),
       "myState" : 1,
       "members" : [
               {
                       "_id" : 0,
                       "name" : "192.168.226.130:27017",
                       "health" : 1,
                       "state" : 2,
                       "stateStr" : "SECONDARY",
                       "uptime" : 17,
                       "optime" : Timestamp(1588736173, 1),
                       "optimeDate" : ISODate("2020-05-06T03:36:13Z"),
                       "lastHeartbeat" : ISODate("2020-05-06T03:54:45.678Z"),
                       "lastHeartbeatRecv" : ISODate("2020-05-06T03:54:45.725Z"),
                       "pingMs" : 0,
                       "configVersion" : 1
               },
               {
                       "_id" : 1,
                       "name" : "192.168.226.130:27018",
                       "health" : 1,
                       "state" : 1,
                       "stateStr" : "PRIMARY",
                       "uptime" : 1825,
                       "optime" : Timestamp(1588736173, 1),
                       "optimeDate" : ISODate("2020-05-06T03:36:13Z"),
                       "electionTime" : Timestamp(1588737026, 1),
                       "electionDate" : ISODate("2020-05-06T03:50:26Z"),
                       "configVersion" : 1,
                       "self" : true
               },
               {
                       "_id" : 2,
                       "name" : "192.168.226.130:27019",
                       "health" : 1,
                       "state" : 2,
                       "stateStr" : "SECONDARY",
                       "uptime" : 1387,
                       "optime" : Timestamp(1588736173, 1),
                       "optimeDate" : ISODate("2020-05-06T03:36:13Z"),
                       "lastHeartbeat" : ISODate("2020-05-06T03:54:45.517Z"),
                       "lastHeartbeatRecv" : ISODate("2020-05-06T03:54:45.517Z"),
                       "pingMs" : 0,
                       "configVersion" : 1
               }
       ],
       "ok" : 1
}
```
27017节点仍为从节点,27018为主节点。可以为节点配置优先级,这样主节点重启后仍是主节点。
**只有主节点才可以设置副本集配置**
所以先进入主节点的shell命令行:
```shell script
rs0:PRIMARY> rs.conf()
{
       "_id" : "rs0",
       "version" : 1,
       "members" : [
               {
                       "_id" : 0,
                       "host" : "192.168.226.130:27017",
                       "arbiterOnly" : false,
                       "buildIndexes" : true,
                       "hidden" : false,
                       "priority" : 1,
                       "tags" : {
                       },
                       "slaveDelay" : 0,
                       "votes" : 1
               },
               {
                       "_id" : 1,
                       "host" : "192.168.226.130:27018",
                       "arbiterOnly" : false,
                       "buildIndexes" : true,
                       "hidden" : false,
                       "priority" : 1,
                       "tags" : {
                       },
                       "slaveDelay" : 0,
                       "votes" : 1
               },
               {
                       "_id" : 2,
                       "host" : "192.168.226.130:27019",
                       "arbiterOnly" : false,
                       "buildIndexes" : true,
                       "hidden" : false,
                       "priority" : 1,
                       "tags" : {
                       },
                       "slaveDelay" : 0,
                       "votes" : 1
               }
       ],
       "settings" : {
               "chainingAllowed" : true,
               "heartbeatTimeoutSecs" : 10,
               "getLastErrorModes" : {
               },
               "getLastErrorDefaults" : {
                       "w" : 1,
                       "wtimeout" : 0
               }
       }
}
```
将27017优先级设为三个节点的最高值:
```shell script
rs0:PRIMARY> var conf=rs.conf()
rs0:PRIMARY> conf.members[0].priority=5
5
rs0:PRIMARY> rs.reconfig(conf)
```
然后重新启动27017节点
```shell script
[root@moggledb bin]# ./mongod --shutdown --dbpath=/data/node1
killing process with pid: 4252
[root@moggledb bin]# ./mongod -f /data/node1/mongodb-node1.conf
about to fork child process, waiting until server is ready for connections.
forked process: 5614
child process started successfully, parent exiting
[root@moggledb bin]# ./mongo --host 192.168.226.130 --port 27017
...
rs0:SECONDARY> rs.isMaster()
rs0:SECONDARY> rs.isMaster()
{
       "setName" : "rs0",
       "setVersion" : 2,
       "ismaster" : true,
       "secondary" : false,
       "hosts" : [
               "192.168.226.130:27017",
               "192.168.226.130:27018",
               "192.168.226.130:27019"
       ],
       "primary" : "192.168.226.130:27017",
       "me" : "192.168.226.130:27017",
       "electionId" : ObjectId("5eb23de4b1aea8240124474b"),
       "maxBsonObjectSize" : 16777216,
       "maxMessageSizeBytes" : 48000000,
       "maxWriteBatchSize" : 1000,
       "localTime" : ISODate("2020-05-06T04:32:49.878Z"),
       "maxWireVersion" : 3,
       "minWireVersion" : 0,
       "ok" : 1
}
rs0:PRIMARY> rs.status()
{
       "set" : "rs0",
       "date" : ISODate("2020-05-06T04:33:55.150Z"),
       "myState" : 1,
       "members" : [
               {
                       "_id" : 0,
                       "name" : "192.168.226.130:27017",
                       "health" : 1,
                       "state" : 1,
                       "stateStr" : "PRIMARY",
                       "uptime" : 106,
                       "optime" : Timestamp(1588739463, 1),
                       "optimeDate" : ISODate("2020-05-06T04:31:03Z"),
                       "electionTime" : Timestamp(1588739556, 1),
                       "electionDate" : ISODate("2020-05-06T04:32:36Z"),
                       "configVersion" : 2,
                       "self" : true
               },
               {
                       "_id" : 1,
                       "name" : "192.168.226.130:27018",
                       "health" : 1,
                       "state" : 2,
                       "stateStr" : "SECONDARY",
                       "uptime" : 105,
                       "optime" : Timestamp(1588739463, 1),
                       "optimeDate" : ISODate("2020-05-06T04:31:03Z"),
                       "lastHeartbeat" : ISODate("2020-05-06T04:33:53.661Z"),
                       "lastHeartbeatRecv" : ISODate("2020-05-06T04:33:54.069Z"),
                       "pingMs" : 23,
                       "configVersion" : 2
               },
               {
                       "_id" : 2,
                       "name" : "192.168.226.130:27019",
                       "health" : 1,
                       "state" : 2,
                       "stateStr" : "SECONDARY",
                       "uptime" : 105,
                       "optime" : Timestamp(1588739463, 1),
                       "optimeDate" : ISODate("2020-05-06T04:31:03Z"),
                       "lastHeartbeat" : ISODate("2020-05-06T04:33:53.661Z"),
                       "lastHeartbeatRecv" : ISODate("2020-05-06T04:33:55.124Z"),
                       "pingMs" : 23,
                       "configVersion" : 2
               }
       ],
       "ok" : 1
}
```
可以看出27017重新成为主节点










