注:mongodb當前版本是3.4.3
1.准備三個虛擬機做服務器
192.168.168.129:27017
192.168.168.130:27017
192.168.168.131:27017
2.在三台服務器上安裝mongodb服務
詳細請見linux安裝mongodb(設置非root用戶和開機啟動)
3.修改配置,在mongodb.conf增加replSet配置,然后啟動服務即可
三個服務器的mongodb.conf中都需要加入replSet的指定,它們都屬於repl1復制集;
replSet中的S一定要大寫!
4.初始化復制集
登入任意一台機器的mongodb執行,因為是全新的復制集,所以可以任意進入一台執行;要是一台有數據,則需要在有數據上執行;要多台有數據則不能初始化。
rs.initiate({_id:'repl1',members:[{_id:1,host:'192.168.168.129:27017'}]})
初始化參數說明:
_id:復制集名稱(第一個_id)
members:復制集服務器列表
_id:服務器的唯一ID(數組里_id)
host:服務器主機
我們操作的是192.168.168.129服務器,其中repl1即是復制集名稱,和mongodb.conf中保持一致,初始化復制集的第一個服務器將會成為主復制集
通過rs.status()查看復制集狀態可以看到,192.168.168.129:27017已被自動分配為primary主復制集了
5.由主復制集添加從復制集
rs.add('192.168.168.130:27017'),增加192.168.168.130為從節點,第一次執行add時報了一個錯,這個錯說的是找到192.168.168.130服務,是因為防火牆的原因,我們把192.168.168.130防火牆關掉(service iptables stop),當第二次執行add的時候就成功了。
注:為了保證復制集中三個服務器之間正常連接,請保證三個服務器的防火牆都已關閉!
可以看到192.168.168.130:27017成為了secondary節點
6.由主復制集添加仲裁復制集
rs.addArb('192.168.168.131:27017')
可以看到192.168.168.131:27017成為了arbiter節點
7.測試復制集secondary節點數據復制功能
在primary(192.168.168.129:27017)上插入數據:
repl1:PRIMARY> db
test
repl1:PRIMARY> show collections
repl1:PRIMARY>for(var i =0; i <4; i ++){db.user.insert({userName:'gxt'+i,age:i})}
WriteResult({"nInserted":1})
repl1:PRIMARY> show collections
user
repl1:PRIMARY> db.user.find()
{"_id":ObjectId("5912e308e5c3987e4a8131e2"),"userName":"gxt0","age":0}
{"_id":ObjectId("5912e308e5c3987e4a8131e3"),"userName":"gxt1","age":1}
{"_id":ObjectId("5912e308e5c3987e4a8131e4"),"userName":"gxt2","age":2}
{"_id":ObjectId("5912e308e5c3987e4a8131e5"),"userName":"gxt3","age":3}
repl1:PRIMARY>
在secondary上查看是否已經同步:
repl1:SECONDARY> db
test
repl1:SECONDARY> show collections
2017-05-10T03:14:54.665-0700 E QUERY [thread1]Error: listCollections failed:{
"ok":0,
"errmsg":"not master and slaveOk=false",
"code":13435,
"codeName":"NotMasterNoSlaveOk"
}:
_getErrorWithCode@src/mongo/shell/utils.js:25:13
DB.prototype._getCollectionInfosCommand@src/mongo/shell/db.js:805:1
DB.prototype.getCollectionInfos@src/mongo/shell/db.js:817:19
DB.prototype.getCollectionNames@src/mongo/shell/db.js:828:16
shellHelper.show@src/mongo/shell/utils.js:762:9
shellHelper@src/mongo/shell/utils.js:659:15
@(shellhelp2):1:1
repl1:SECONDARY> rs.slaveOk()
repl1:SECONDARY> show collections
user
repl1:SECONDARY> db.user.find()
{"_id":ObjectId("5912e308e5c3987e4a8131e2"),"userName":"gxt0","age":0}
{"_id":ObjectId("5912e308e5c3987e4a8131e3"),"userName":"gxt1","age":1}
{"_id":ObjectId("5912e308e5c3987e4a8131e4"),"userName":"gxt2","age":2}
{"_id":ObjectId("5912e308e5c3987e4a8131e5"),"userName":"gxt3","age":3}
repl1:SECONDARY>
通過db.user.find()查詢到和主復制集上一樣的數據,表示數據同步成功!
"errmsg" : "not master and slaveOk=false"錯誤說明:因為secondary是不允許讀寫的,如果非要解決,則執行:rs.slaveOk()
在arbiter上查看是否會有數據同步:
repl1:ARBITER> db
test
repl1:ARBITER> show collections
2017-05-10T03:22:02.554-0700 E QUERY [thread1]Error: listCollections failed:{
"ok":0,
"errmsg":"not master and slaveOk=false",
"code":13435,
"codeName":"NotMasterNoSlaveOk"
}:
_getErrorWithCode@src/mongo/shell/utils.js:25:13
DB.prototype._getCollectionInfosCommand@src/mongo/shell/db.js:805:1
DB.prototype.getCollectionInfos@src/mongo/shell/db.js:817:19
DB.prototype.getCollectionNames@src/mongo/shell/db.js:828:16
shellHelper.show@src/mongo/shell/utils.js:762:9
shellHelper@src/mongo/shell/utils.js:659:15
@(shellhelp2):1:1
repl1:ARBITER> rs.slaveOk()
repl1:ARBITER> show collections
repl1:ARBITER> db.user.find()
Error: error:{
"ok":0,
"errmsg":"node is not in primary or recovering state",
"code":13436,
"codeName":"NotMasterOrSecondary"
}
repl1:ARBITER>
我們可以看到,arbiter並沒有進行數據同步,因為仲裁節點只參與投票,不接收數據!
8.測試復制集主從節點故障轉移功能
關閉primary節點,查看其它兩個節點的情況:
repl1:PRIMARY>use admin
switched to db admin
repl1:PRIMARY> db.shutdownServer()
server should be down...
2017-05-10T03:27:04.162-0700 I NETWORK [thread1] trying reconnect to 127.0.0.1:27017(127.0.0.1) failed
2017-05-10T03:27:04.207-0700 I NETWORK [thread1]Socket recv()Connection reset by peer 127.0.0.1:27017
2017-05-10T03:27:04.208-0700 I NETWORK [thread1]SocketException: remote:(NONE):0 error:9001 socket exception [RECV_ERROR] server [127.0.0.1:27017]
2017-05-10T03:27:04.208-0700 I NETWORK [thread1] reconnect 127.0.0.1:27017(127.0.0.1) failed failed
>
我們可以看到192.168.168.130:27017從secondary變成了primary,故障轉移成功!不過現在這個復制集已沒有可以同步數據的從節點了,但我們可以把192.168.168.129:27017重新啟動,這時129會變成secondary,這樣這個復制集就可以正常工作了。
9.復制集常用方法總結
rs.initiate():復制集初始化,例如:rs.initiate({_id:'repl1',members:[{_id:1,host:'192.168.168.129:27017'}]})
rs.reconfig():重新加載配置文件,例如:
rs.reconfig({_id:'repl1',members:[{_id:1,host:'192.168.168.129:27017'}]},{force:true})當只剩下一個secondary節點時,復制集變得不可用,則可以指定force屬性強制將節點變成primary,然后再添加secondary節點
rs.status():查看復制集狀態
db.printSlaveReplicationInfo():查看復制情況
rs.conf()/rs.config():查看復制集配置
rs.slaveOk():在當前連接讓secondary可以提供讀操作
rs.add():增加復制集節點,例如:
rs.add('192.168.168.130:27017')
rs.add({"_id":3,"host":"192.168.168.130:27017","priority":0,"hidden":true})指定hidden屬性添加備份節點
rs.add({"_id":3,"host":"192.168.168.130:27017","priority":0,"slaveDelay":60})指定slaveDelay屬性添加延遲節點
priority:是優先級,默認為1,如果想手動指定某個節點為primary節點,則把對應節點的priority屬性設置為所有節點中最大的一個即可
rs.remove():刪除復制集節點,例如:rs.remove('192.168.168.130:27017')
rs.addArb():添加仲裁節點,例如:
rs.addArb('192.168.168.131:27017')或者rs.add({"_id":3,"host":"192.168.168.130:27017","arbiterOnly":true}),仲裁節點,只參與投票,不接收數據
屬性說明: