mongodb副本集搭建流程

一、準備

準備三臺服務器,或者在一臺服務器上啓動三個不同端口的mongodb服務

防火牆,開放對應的端口,否則會報錯

selinux設置關閉

二、mongodb搭建

#!/bin/bash
#This is a script to install mongidb, the version of mongodb is 3.4.0

#Download the installation package

wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.4.0.tgz


tar zxvf mongodb-linux-x86_64-3.4.0.tgz -C /opt

cd /opt

mv mongodb-linux-x86_64-3.4.0   mongodb

Cat>>/etc/profile<<EOF
export MONGODB_HOME=/usr/local/mongodb
export PATH=$PATH:$MONGODB_HOME/bin
EOF

source /etc/profile

mkdir -p /opt/mongodb/data
mkdir -p /opt/mongodb/data/db
mkdir -p /opt/mongodb/data/logs

cd /opt/mongodb/data/logs

touch mongodb.log
cat>>/opt/mongodb/data1/mongodb.conf<<EOF
#端口號
port=27017
#數據目錄
dbpath=/opt/mongodb/data/db
#日誌目錄
logpath=/opt/mongodb/data/logs/mongodb.log
#以後臺方式運行
fork=true
#日誌輸出方式
logappend=true
#開啓認證
#auth=true
#副本集名稱
replSet=test
#本機IP
bind_ip=127.0.0.1

#操作文件最大值,單位 mb,默認硬盤百分之 5
oplogSize=10000

#不預先分配內存
noprealloc=true

EOF

cd /opt/mongodb/bin
./mongod --config /opt/mongodb/data/mongodb.conf
ln -s /opt/mongodb/bin/* /usr/bin/

按照這個安裝也可以,路徑改成自己想要安裝的路徑。

安裝完成

查看進程
ps -aux |grep mongod

我這個上面啓動了兩個mongo

是指定路徑,端口,配置文件啓動

啓動命令是

sudo mongod -f /opt/mongodb/data/mongodb.conf -dbpath /opt/mongodb/data/db -replSet LZAPP --bind_ip=10.10.100.186 --port=27017 &

設置開機啓動

vim  /etc/rc.d/rc.local

添加

sudo mongod -f /opt/mongodb/data/mongodb.conf -dbpath /opt/mongodb/data/db -replSet test --bind_ip=10.10.100.186 --port=27017

修改 rc.local文件的的權限

chmod +x rc.local

重啓機器,測試看看

三、修改配置文件

port=27017            #啓動端口
#數據目錄
dbpath=/opt/mongodb/data/db     #數據目錄
logpath=/opt/mongodb/data/logs/mongodb.log    #日誌文件
#設置後臺運行
fork=true          
#日誌輸出方式
logappend=true
#開啓認證
#auth=true
bind_ip=10.10.100.186             #本機IP,這個一定要寫
replSet=test                        #副本集名稱

四、初始化副本集

在三個節點中的任意一個節點機上操作(比如在10.10.100.186節點機)

登錄mongodb

mongo 10.10.100.177:27017

登錄admin數據庫

>use admin

switched to db admin

#定義副本集配置變量,這裏的 _id:”repset” 和上面命令參數“ –replSet repset” 要保持一樣。

> config={_id:"test",members:[{_id:0,host:"10.10.100.186:27018"},{_id:1,host:"10.10.100.187:27018"},{_id:2,host:"10.10.100.188:27018"}]}
{
	"_id" : "test",
	"members" : [
		{
			"_id" : 0,
			"host" : "10.10.100.186:27018"
		},
		{
			"_id" : 1,
			"host" : "10.10.100.187:27018"
		},
		{
			"_id" : 2,
			"host" : "10.10.100.188:27018"
		}
	]
}

初始化副本集配置

> rs.initiate(config)
{ "ok" : 1 }
返回1,是正常,返回0,就是失敗

查看副本集配置

test:OTHER> rs.conf()
{
	"_id" : "test",
	"version" : 1,
	"protocolVersion" : NumberLong(1),
	"members" : [
		{
			"_id" : 0,
			"host" : "10.10.100.186:27018",
			"arbiterOnly" : false,
			"buildIndexes" : true,
			"hidden" : false,
			"priority" : 1,
			"tags" : {
				
			},
			"slaveDelay" : NumberLong(0),
			"votes" : 1
		},
		{
			"_id" : 1,
			"host" : "10.10.100.187:27018",
			"arbiterOnly" : false,
			"buildIndexes" : true,
			"hidden" : false,
			"priority" : 1,
			"tags" : {
				
			},
			"slaveDelay" : NumberLong(0),
			"votes" : 1
		},
		{
			"_id" : 2,
			"host" : "10.10.100.188:27018",
			"arbiterOnly" : false,
			"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("5d6db54279053540497f68c8")
	}
}

#查看集羣節點的狀態

test:PRIMARY> rs.status();
{
	"set" : "test",
	"date" : ISODate("2019-09-03T00:36:45.238Z"),
	"myState" : 1,
	"term" : NumberLong(1),
	"heartbeatIntervalMillis" : NumberLong(2000),
	"optimes" : {
		"lastCommittedOpTime" : {
			"ts" : Timestamp(1567470995, 1),
			"t" : NumberLong(1)
		},
		"appliedOpTime" : {
			"ts" : Timestamp(1567470995, 1),
			"t" : NumberLong(1)
		},
		"durableOpTime" : {
			"ts" : Timestamp(1567470995, 1),
			"t" : NumberLong(1)
		}
	},
	"members" : [
		{
			"_id" : 0,
			"name" : "10.10.100.186:27018",
			"health" : 1,
			"state" : 1,
			"stateStr" : "PRIMARY",
			"uptime" : 213,
			"optime" : {
				"ts" : Timestamp(1567470995, 1),
				"t" : NumberLong(1)
			},
			"optimeDate" : ISODate("2019-09-03T00:36:35Z"),
			"infoMessage" : "could not find member to sync from",
			"electionTime" : Timestamp(1567470924, 1),
			"electionDate" : ISODate("2019-09-03T00:35:24Z"),
			"configVersion" : 1,
			"self" : true
		},
		{
			"_id" : 1,
			"name" : "10.10.100.187:27018",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",
			"uptime" : 90,
			"optime" : {
				"ts" : Timestamp(1567470995, 1),
				"t" : NumberLong(1)
			},
			"optimeDurable" : {
				"ts" : Timestamp(1567470995, 1),
				"t" : NumberLong(1)
			},
			"optimeDate" : ISODate("2019-09-03T00:36:35Z"),
			"optimeDurableDate" : ISODate("2019-09-03T00:36:35Z"),
			"lastHeartbeat" : ISODate("2019-09-03T00:36:45.077Z"),
			"lastHeartbeatRecv" : ISODate("2019-09-03T00:36:43.544Z"),
			"pingMs" : NumberLong(0),
			"syncingTo" : "10.10.100.186:27018",
			"configVersion" : 1
		},
		{
			"_id" : 2,
			"name" : "10.10.100.188:27018",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",
			"uptime" : 90,
			"optime" : {
				"ts" : Timestamp(1567470995, 1),
				"t" : NumberLong(1)
			},
			"optimeDurable" : {
				"ts" : Timestamp(1567470995, 1),
				"t" : NumberLong(1)
			},
			"optimeDate" : ISODate("2019-09-03T00:36:35Z"),
			"optimeDurableDate" : ISODate("2019-09-03T00:36:35Z"),
			"lastHeartbeat" : ISODate("2019-09-03T00:36:45.077Z"),
			"lastHeartbeatRecv" : ISODate("2019-09-03T00:36:43.543Z"),
			"pingMs" : NumberLong(0),
			"syncingTo" : "10.10.100.186:27018",
			"configVersion" : 1
		}
	],
	"ok" : 1
}

五、測試Mongodb副本集數據複製功能 <mongodb默認是從主節點讀寫數據的,副本節點上不允許讀,需要設置副本節點可以讀>

1)在主節點建立數據庫,插入測試數據

test:PRIMARY> use test;
switched to db test
test:PRIMARY> db.testdb.insert({"test1":"testval1"})
WriteResult({ "nInserted" : 1 })

2)在從節點查看數據是否複製過來

登錄數據庫

mongo 10.10.100.187:27017
test:SECONDARY> use test;
switched to db test
test:SECONDARY> show tables;
2019-09-03T08:40:09.371+0800 E QUERY    [main] 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:748:9
shellHelper@src/mongo/shell/utils.js:645:15
@(shellhelp2):1:1

上面出現了報錯!

這是因爲mongodb默認是從主節點讀寫數據的,副本節點上不允許讀,需要設置副本節點可以讀

test:SECONDARY> db.getMongo().setSlaveOk();  設置一下
test:SECONDARY> show tables;    就可以讀出來了,兩臺都需要設置一下
testdb

現在,把主節點宕掉,登錄另外的節點,查看副本集的狀態

test:PRIMARY> rs.status();
{
	"set" : "test",
	"date" : ISODate("2019-09-03T00:46:21.057Z"),
	"myState" : 1,
	"term" : NumberLong(2),
	"heartbeatIntervalMillis" : NumberLong(2000),
	"optimes" : {
		"lastCommittedOpTime" : {
			"ts" : Timestamp(1567471577, 1),
			"t" : NumberLong(2)
		},
		"appliedOpTime" : {
			"ts" : Timestamp(1567471577, 1),
			"t" : NumberLong(2)
		},
		"durableOpTime" : {
			"ts" : Timestamp(1567471577, 1),
			"t" : NumberLong(2)
		}
	},
	"members" : [
		{
			"_id" : 0,
			"name" : "10.10.100.186:27018",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",
			"uptime" : 34,
			"optime" : {
				"ts" : Timestamp(1567471577, 1),
				"t" : NumberLong(2)
			},
			"optimeDurable" : {
				"ts" : Timestamp(1567471577, 1),
				"t" : NumberLong(2)
			},
			"optimeDate" : ISODate("2019-09-03T00:46:17Z"),
			"optimeDurableDate" : ISODate("2019-09-03T00:46:17Z"),
			"lastHeartbeat" : ISODate("2019-09-03T00:46:20.494Z"),
			"lastHeartbeatRecv" : ISODate("2019-09-03T00:46:19.899Z"),
			"pingMs" : NumberLong(0),
			"syncingTo" : "10.10.100.188:27018",
			"configVersion" : 1
		},
		{
			"_id" : 1,
			"name" : "10.10.100.187:27018",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",
			"uptime" : 664,
			"optime" : {
				"ts" : Timestamp(1567471577, 1),
				"t" : NumberLong(2)
			},
			"optimeDurable" : {
				"ts" : Timestamp(1567471577, 1),
				"t" : NumberLong(2)
			},
			"optimeDate" : ISODate("2019-09-03T00:46:17Z"),
			"optimeDurableDate" : ISODate("2019-09-03T00:46:17Z"),
			"lastHeartbeat" : ISODate("2019-09-03T00:46:20.462Z"),
			"lastHeartbeatRecv" : ISODate("2019-09-03T00:46:19.161Z"),
			"pingMs" : NumberLong(0),
			"syncingTo" : "10.10.100.188:27018",
			"configVersion" : 1
		},
		{
			"_id" : 2,
			"name" : "10.10.100.188:27018",
			"health" : 1,
			"state" : 1,
			"stateStr" : "PRIMARY",
			"uptime" : 724,
			"optime" : {
				"ts" : Timestamp(1567471577, 1),
				"t" : NumberLong(2)
			},
			"optimeDate" : ISODate("2019-09-03T00:46:17Z"),
			"infoMessage" : "could not find member to sync from",
			"electionTime" : Timestamp(1567471486, 1),
			"electionDate" : ISODate("2019-09-03T00:44:46Z"),
			"configVersion" : 1,
			"self" : true
		}
	],
	"ok" : 1
}

發現當原來的主節點10.10.100.186宕掉後,經過選舉,原來的從節點10.10.100.188被推舉爲新的主節點。

然後在新的節點插入數據

test:PRIMARY> for(var i=0;i<10000;i++){db.test.insert({"name":"test"+i,"age":123})}

WriteResult({ "nInserted" : 1 })
test:PRIMARY> 

登錄從節點查看數據是否同步

test:SECONDARY> db.test.find()
{ "_id" : ObjectId("5d6db9ce460b07bcce150716"), "name" : "test0", "age" : 123 }
{ "_id" : ObjectId("5d6db9ce460b07bcce150718"), "name" : "test2", "age" : 123 }
{ "_id" : ObjectId("5d6db9ce460b07bcce150717"), "name" : "test1", "age" : 123 }
{ "_id" : ObjectId("5d6db9ce460b07bcce15071b"), "name" : "test5", "age" : 123 }
{ "_id" : ObjectId("5d6db9ce460b07bcce15071e"), "name" : "test8", "age" : 123 }
{ "_id" : ObjectId("5d6db9ce460b07bcce150719"), "name" : "test3", "age" : 123 }
{ "_id" : ObjectId("5d6db9ce460b07bcce15071c"), "name" : "test6", "age" : 123 }
{ "_id" : ObjectId("5d6db9ce460b07bcce15071d"), "name" : "test7", "age" : 123 }
{ "_id" : ObjectId("5d6db9ce460b07bcce15071a"), "name" : "test4", "age" : 123 }
{ "_id" : ObjectId("5d6db9ce460b07bcce150720"), "name" : "test10", "age" : 123 }
{ "_id" : ObjectId("5d6db9ce460b07bcce15071f"), "name" : "test9", "age" : 123 }
{ "_id" : ObjectId("5d6db9ce460b07bcce150721"), "name" : "test11", "age" : 123 }
{ "_id" : ObjectId("5d6db9ce460b07bcce150722"), "name" : "test12", "age" : 123 }
{ "_id" : ObjectId("5d6db9ce460b07bcce15072b"), "name" : "test21", "age" : 123 }
{ "_id" : ObjectId("5d6db9ce460b07bcce150725"), "name" : "test15", "age" : 123 }
{ "_id" : ObjectId("5d6db9ce460b07bcce150728"), "name" : "test18", "age" : 123 }
{ "_id" : ObjectId("5d6db9ce460b07bcce15072a"), "name" : "test20", "age" : 123 }
{ "_id" : ObjectId("5d6db9ce460b07bcce150726"), "name" : "test16", "age" : 123 }
{ "_id" : ObjectId("5d6db9ce460b07bcce150729"), "name" : "test19", "age" : 123 }
{ "_id" : ObjectId("5d6db9ce460b07bcce150727"), "name" : "test17", "age" : 123 }

發現數據已經同步

六、Mongodb讀寫分離

目前來看。Mongodb副本集可以完美支持故障轉移。至於主節點的讀寫壓力過大如何解決?常見的解決方案是讀寫分離。

一般情況下,常規寫操作來說並沒有讀操作多,所以在Mongodb副本集中,一臺主節點負責寫操作,兩臺副本節點負責讀操作。
1)設置讀寫分離需要先在副本節點SECONDARY 設置 setSlaveOk。
2)在程序中設置副本節點負責讀操作,如下代碼:<br>
public class TestMongoDBReplSetReadSplit {
public static void main(String[] args) {
try {
List<ServerAddress> addresses = new ArrayList<ServerAddress>();
ServerAddress address1 = new ServerAddress("10.10.100.186" , 27017);
ServerAddress address2 = new ServerAddress("10.10.100.187" , 27017);
ServerAddress address3 = new ServerAddress("10.10.100.188" , 27017);
addresses.add(address1);
addresses.add(address2);
addresses.add(address3);
MongoClient client = new MongoClient(addresses);
DB db = client.getDB( "test" );
DBCollection coll = db.getCollection( "testdb" );
BasicDBObject object = new BasicDBObject();
object.append( "test2" , "testval2" );
 
//讀操作從副本節點讀取
ReadPreference preference = ReadPreference. secondary();
DBObject dbObject = coll.findOne(object, null , preference);
System. out .println(dbObject);
} catch (Exception e) {
e.printStackTrace();
}
}
}

讀參數除了secondary一共還有五個參數:primary、primaryPreferred、secondary、secondaryPreferred、nearest。
primary:默認參數,只從主節點上進行讀取操作;
primaryPreferred:大部分從主節點上讀取數據,只有主節點不可用時從secondary節點讀取數據。
secondary:只從secondary節點上進行讀取操作,存在的問題是secondary節點的數據會比primary節點數據“舊”。
secondaryPreferred:優先從secondary節點進行讀取操作,secondary節點不可用時從主節點讀取數據;
nearest:不管是主節點、secondary節點,從網絡延遲最低的節點上讀取數據。

讀寫分離做好後,就可以進行數據分流,減輕壓力,解決了"主節點的讀寫壓力過大如何解決?"這個問題。不過當副本節點增多時,主節點的複製壓力會加大有什麼辦法解決嗎?基於這個問題,Mongodb已有了相應的解決方案 - 引用仲裁節點:
在Mongodb副本集中,仲裁節點不存儲數據,只是負責故障轉移的羣體投票,這樣就少了數據複製的壓力。看起來想的很周到啊,其實不只是主節點、副本節點、仲裁節點,還有Secondary-Only、Hidden、Delayed、Non-Voting,其中:
Secondary-Only:不能成爲primary節點,只能作爲secondary副本節點,防止一些性能不高的節點成爲主節點。
Hidden:這類節點是不能夠被客戶端制定IP引用,也不能被設置爲主節點,但是可以投票,一般用於備份數據。
Delayed:可以指定一個時間延遲從primary節點同步數據。主要用於備份數據,如果實時同步,誤刪除數據馬上同步到從節點,恢復又恢復不了。
Non-Voting:沒有選舉權的secondary節點,純粹的備份數據節點。


 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章