1.復制的角色
復制有三種角色:
primay:主庫,執行所有的寫操作,並把日志寫入oplog里。
secondary:復制主庫的所有操作。讀取主庫的oplog,並執行日志里的內容。默認情況下,客戶端不能讀取secondary的數據。
arbiter:仲裁者,在主庫失敗后選舉主庫。該角色是可選的角色。仲裁者不包含數據,客戶端不可連接。
2.主庫
primay:主庫,執行所有的讀寫操作,並
把日志
寫入oplog里。
3.備庫
secondary:復制主庫的所有操作。讀取主庫的oplog,並執行日志里的內容。在主庫宕機后,備庫可以切換為主庫
備庫可做以下配置:
1)設置成priority 0的備庫,使其不能成為主庫。其它特性不變。
2)設置成應該程序不能訪問
3)做主庫的延遲快照。即延遲復制。延遲的備庫必須是priority 0的,並且應該設置為hidden.
3.仲裁者
不包含數據,只負責極少工作,對機器的要求低,可以放在性能差一點的機器上。
每個arbiter可以投一票。
其實,每個主庫備庫都可以投一票
注意:不能在主庫或者備庫上建仲裁者.(不是不能建,但是會影響投票的准確性)。只在節點數為偶然的集群中加入仲裁者。

4.關於容災
節點數與可以宕機的節點的個數(否則會產生選舉不出primary的問題):

(foolr(N/2)+1) 至少一半成員狀態正常,否則不能選舉出primary(待驗證)
關於選舉:
http://www.itpub.net/thread-1740982-1-1.html
三台機器的兩種復制形式:


3.其它細節
心跳:節點之間每2秒檢查心跳,如果一個節點10秒內沒有響應就認為該節點失效。
優先級:各節點都有優先級,優先級越高的備庫越有希望成為轉換為主庫
無選舉權節點:一個復制群最多可以有50個節點,但是只有7個有選舉權,剩下的沒有選舉權但是可以復制數據
4.回滾
“回滾”:如果備庫沒有跟上主庫的節奏,而主庫又掛了,選舉了新的主庫,之前的主庫又加入到復制群中做為備庫,
此時之前
的主庫會做回滾操作。
MongoDB會把回滾數據寫入到rollback/目錄下,dba來決定是忽視還是使用這些數據。
避免回滾:
默認情況下
write concern {w: 1}
確保主庫寫完后就返回給client,可以改成
w: majority
,大多數據寫完后返回結果給客戶端。但顯示可能增加響應時間。
回滾的限制:
默認下,只能回滾300M以內的數據,如果大於300M,日志中有以一警告:
[replica set sync] replSet syncThread: 13410 replSet too much data to roll back
此時必須“
save the data directly
”(語義不明),或者執行初始化。執行初始化同步,必須刪除--dbpaht目錄下的內容。。。
詳情略。
5.設置默認的
write concern
db.products.insert(
{ writeConcern: { w: 2, wtimeout: 5000 } } #至少寫入一個從結點
)
{ w: "majority", wtimeout: 5000 }
6.設置復制的可讀性
默認下,應用只能讀主庫。
詳情略。
7.oplog的大小
默認以5%的磁盤空間做oplog。
詳情略。
8.數據同步
有兩種方式數據同步:initial sync和Replication
initical sync:初始化數據。
當集群新增加了成員,新成員沒有數據,從開始復制數據。
過程如下 :
1)從數據源復制所有數據庫,只復制有效的數據。這個步驟中,_id上的索引也被建立。從3.0開始如果發現無效數據,將會在日志中記錄:
Cloner: found corrupt document in <collection>
.
2)使用oplog同步數據。
3)在各集合上建立索引
replication:復制,即正常的數據同步。
支持多線程復制數據。
9.master-slave 復制
mongodb的復制分為兩種。舊的稱為master-slave復制,沒有自動failover功能。新的稱為replication sets,有
自動
failover功能。
這時介紹master-slave復制。
創建master:
mongod --master --dbpath /data/masterdb/
創建salve:
mongod
--
slave
--
source
<
masterhostname
><:<
port
>> --
dbpath
/
data
/
slavedb
/
這樣就創建了一個主備。
配置mster-slave:
slave上,master的信息保存在此處:
use local
db.sources.find()#包含了source信息.
db.sources.insert( { host: <masterhostname> <,only: databasename> } );
slave 無法同步數據
slave無法同步數據的原因:
備庫的復制進度落后太遠了。
一旦備庫的復制進度落后主庫太完,復制就會中斷。
解決辦法:
必須執行resync命令重新同步數據(應該是initical sync,即重0數據開始同步)。如果在啟動slave時加上--autoresync,則slave在復制中斷10秒后自動執行resync。
為了避免這種情況,在master啟動的時候,可以設置--oplogSize參數,設置較大的日志文件。默認使用磁盤的5%做為oplog,32位上最小是50M,64位上最小1G.
運行時檢查配置情況:
2.6以前,在master執行 db.printReplicationInfo() local庫。2.6以后,執行rs.
printReplicationInfo().
2.6以前,在slave執行 db.printSlaveReplicationInfo() local庫。2.6以后,執行rs.
printSlaveReplicationInfo
().
安全性:
如果master啟用了authorization,需要配置keyfile,slave通過keyfile與master通信。
在config文件里加入:
keyFile=/usr/local/mongo/
keyfile
keyFile的內容在各個節點上必須一樣。可以使用OpenSSL來生成一個keyfile.
master-slave的failover:
master-slave的角色切換:
從master的磁盤快照創建slave:
從slave的磁盤快照創建slave:
resync復制進度過慢(無法繼續復制)的salve:
use admin
db.runCommand( { resync: 1 } )
修改slave的配置信息然后重啟slave:
use local
db.sources.update( { host : "prod.mississippi" },
{ $set : { host : "prod.mississippi.example.net" } } )
10. replication sets
配置replication sets
1)以--replSet啟動mongod
mongod --replSet "rs0" -f /usr/local/mongodb-linux-x86_64-3.2.0/mongodb.conf
2)進入mong shell
>mongo
3)初始化復制集(沒有配置信息)
> rs.initiate();
{
"info2" : "no configuration specified. Using a default configuration for the set",
"me" : "node1:27017",
"ok" : 0,
"errmsg" : "No host described in new configuration 1 for replica set repl0 maps to this node",
"code" : 93
}
4)驗證初始配置
> rs.conf();
2015-12-27T11:04:15.763+0800 E QUERY [thread1] Error: Could not retrieve replica set config: {
"info" : "run rs.initiate(...) if not yet done for the set",
"ok" : 0,
"errmsg" : "no replset config has been received",
"code" : 94
} :
rs.conf@src/mongo/shell/utils.js:1090:11
@(shell):1:1
> cfg={"_id":"rs0","version":1,"members":[{"_id":1,"host":"192.168.75.10:27017"}]};
{
"_id" : "rs0",
"version" : 1,
"members" : [
{
"_id" : 1,
"host" : "192.168.75.10:27017"
}
]
}
> rs.initiate(cfg);
{ "ok" : 1 }
5)在復制集中加入節點
rs0:PRIMARY> rs.add("192.168.75.11:27017");
{ "ok" : 1 }
rs0:PRIMARY> rs.add("192.168.75.12:27017");
{ "ok" : 1 }
6)檢查復制集狀態
rs0:PRIMARY> rs.status();
{
"set" : "rs0",
"date" : ISODate("2015-12-27T03:13:26.970Z"),
"myState" : 1,
"term" : NumberLong(1),
"heartbeatIntervalMillis" : NumberLong(2000),
"members" : [
{
"_id" : 1,
"name" : "192.168.75.10:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 575,
"optime" : {
"ts" : Timestamp(1451185968, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2015-12-27T03:12:48Z"),
"electionTime" : Timestamp(1451185613, 2),
"electionDate" : ISODate("2015-12-27T03:06:53Z"),
"configVersion" : 3,
"self" : true
},
{
"_id" : 2,
"name" : "192.168.75.11:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 41,
"optime" : {
"ts" : Timestamp(1451185968, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2015-12-27T03:12:48Z"),
"lastHeartbeat" : ISODate("2015-12-27T03:13:24.973Z"),
"lastHeartbeatRecv" : ISODate("2015-12-27T03:13:26.011Z"),
"pingMs" : NumberLong(1),
"syncingTo" : "192.168.75.10:27017",
"configVersion" : 3
},
{
"_id" : 3,
"name" : "192.168.75.12:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 37,
"optime" : {
"ts" : Timestamp(1451185968, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2015-12-27T03:12:48Z"),
"lastHeartbeat" : ISODate("2015-12-27T03:13:25.028Z"),
"lastHeartbeatRecv" : ISODate("2015-12-27T03:13:25.128Z"),
"pingMs" : NumberLong(1),
"configVersion" : 3
}
],
"ok" : 1
}
7) 測試復制情況:
rs0:PRIMARY> use testdb
switched to db testdb
rs0:PRIMARY> db.test1231.insert({"name":"test repl"});
WriteResult({ "nInserted" : 1 })
rs0:SECONDARY> rs.slaveOk();
rs0:SECONDARY> use testdb
switched to db testdb
rs0:SECONDARY> show collections;
test1231
rs0:SECONDARY> db.test1231.find();
{ "_id" : ObjectId("567f58f221cb21ff2f187d33"), "name" : "test repl" }
節點重新同步resync:
如果一個節點沒有數據,將該結點加入到replication set中,則會自動的完全同步數據。
把一個有數據的結點加入到replication set中:清除--dbpath目錄中的內容重啟該實例即可。
8)replication set的一些設置
參照:
設置優先級,是否隱藏及延時
cfg = rs.conf()
cfg.members[0].priority = 0
cfg.members[0].hidden = true
cfg.members[0].slaveDelay = 3600
rs.reconfig(cfg)
設置選舉權:
cfg = rs.conf()
cfg.members[3].votes = 0
cfg.members[4].votes = 0
cfg.members[5].votes = 0
rs.reconfig(cfg)