複製集(Replication Set
),也叫副本集;做用是把一份數據同時保存在多臺服務器上,保證數據的安全,不發生丟失;算法
經過指定 replSet
選項啓動三臺Mongo
服務器,端口號是 27017, 27018, 27019;指定加入的複製集名稱爲 demo
;mongodb
./bin/mongod --dbpath master/data --logpath master/log/0923.log --port 27017 --fork --replSet demo ./bin/mongod --dbpath slave1/data --logpath slave1/log/0923.log --port 27018 --fork --replSet demo ./bin/mongod --dbpath slave2/data --logpath slave2/log/0923.log --port 27019 --fork --replSet demo
此時,在三臺服務器上分別鍵入rs.status()
命令,均報「未初始化」的錯誤;數據庫
啓動服務器的另一種方式是經過配置文件啓動;舉個例子,這裏的27018
以配置文件啓動;安全
配置文件以下所示:服務器
dbpath=/home/mongodb/slave1/data # 數據存放目錄 logpath=/home/mongodb/slave1/log/0923.log # 日誌存放路徑 pidfilepath=/home/mongodb/slave1/slave1.pid # 進程文件,方便中止mongodb directoryperdb=false # 爲每個數據庫按照數據庫名創建文件夾存放 logappend=true # 以追加的方式記錄日誌 replSet=demo # Replication Set 的名稱 #bind_ip=127.0.0.1 # 限制只容許某一特定IP來訪問,逗號隔開 port=27018 # 進程所使用的端口號,默認爲27017 oplogSize=10000 # mongodb操做日誌文件的最大大小。單位爲Mb,默認爲硬盤剩餘空間的5% fork=true # 之後臺方式運行進程 noprealloc=false # 不預先分配存儲 smallfiles=false # 當提示空間不夠時添加此參數
登入任意一臺機器的 MongoDB
執行,由於是全新的複製集,因此能夠任意進入一臺執行;要是一臺有數據,則須要在有數據上執行;要多臺有數據則不能初始化。app
筆者選擇在27017
這臺MongoDB
服務器進行初始化spa
rs.initiate({ _id:'demo', // 複製集名稱 members: // 複製集服務器列表 [ { _id:0, // 服務器的惟一 ID host:'192.168.1.168:27017' // 服務器的地址 }, { _id:1, host:'192.168.1.168:27018' }, { _id:2, host:'192.168.1.168:27019' }, ] });
這樣,三臺服務器都加入了demo
複製集;此時主節點27017
能夠進行讀寫,從節點27018
和27019
不能夠讀寫;全部的寫操做只能在主節點上進行;.net
那如何才能在從節點27018
上讀數據呢?在27018
上鍵入rs.slaveOk()
, 這樣就能夠進行讀操做;命令行
注:能夠經過rs.status()
查看複製集狀態;經過rs.config()
查看複製集的配置信息;經過db.isMaster()
查看是不是主節點信息;unix
先啓動想要添加的從節點服務器,筆者是本地的27020
服務器,同時指定相要加入的複製集名稱;
./bin/mongod --dbpath slave3/data --logpath slave3/log/0923.log --port 27020 --fork --replSet demo
主節點27017
配置添加:
rs.add('192.168.1.168:27020');
此時,經過鍵入rs.status()
能夠看到members
成員有四位,包括這臺新的27020
從節點服務器;
若是想要移除27020
從節點服務器,便可成功從demon
複製集中移除該服務器;
rs.remove('192.168.1.168:27020');
目前環境:
27017
: Primary
主服務器27018
: SECONDARY
從服務器27019
: SECONDARY
從服務器在系統命令行上,手動drop
掉主服務器
lsof -i:27017 | sed '1d' | while read line do echo $line | awk '{print $2}' | xargs kill -9 done
或者在主服務器上執行下面的語句
db.shutdownServer()
此時,在經過rs.status()
查看環境
27017
: 離線(not reachable/healthy
)27018
: SECONDARY
從服務器27019
: Primary
主服務器這裏,爲何在主服務器27017
服務器掛了以後,會選擇27019
作新的主服務器呢,這是由MongoDB
服務器內部的多數投票算法,即每臺服務器會爲secondary
從節點服務器進行投票,票數多的從節點服務器會成爲新的Primary
服務器;
筆者這裏很幸運,兩臺從節點服務器27018
和27019
都選擇了27019
做爲新的從節點服務器;另一種多是 27018
和27019
各得一票,這樣會致使沒法選舉出新Primary
服務器; 因此建議複製集的服務器數目爲奇數,若是碰巧是偶數,能夠添加一臺仲裁節點服務器;
仲裁節點是一種特殊的節點,它自己並不存儲數據,主要的做用是決定哪個從節點在主節點掛掉以後提高爲主節點,因此客戶端不須要鏈接此節點。
仲裁節點服務器啓動,
./bin/mongod --dbpath arbiter/data --logpath arbiter/log/0923.log --port 27021 --fork --replSet demo
主服務器的配置上添加仲裁節點信息:
demo:PRIMARY> rs.addArb('192.168.1.168:27021')
Primay
服務器將27017
服務器重啓;
此時,在經過rs.status()
查看環境
27017
: SECONDARY
從服務器27018
: SECONDARY
從服務器27019
: Primary
主服務器27021
: Arbiter
仲裁服務器如何能將當前的服務器從27019
切換回27017
服務器呢?
經過修改priority
的值來實現(默認的優先級是1(0-100),priority
的值設的越大,就優先成爲主);
在27019
主節點上執行
Primary > config=rs.conf() Primary > config.members[0].priority = 3 Primary > rs.reconfig(config)
注意:第2步members
大括號裏面的成員和_id
是沒有關係的,而是rs.conf
查出來節點的數值的順序;
主節點的操做記錄成爲oplog
(operation log
)。 oplog
存儲在一個系統數據庫local
的集合oplog.rs
中,這個集合的每一個文檔都表明主節點上執行的一個操做。咱們從新向主數據庫服務器中插入一條數據,而後查看這個集合能夠看到:
use local db.getCollection('oplog.rs').find({})
文檔中的字段含義:
ts
:8字節的時間戳,由4字節unix timestamp
+ 4字節自增計數表示h
: 未知v
: 未知op
:操做類型,i
表示insert
;u
表示update
;d
表示delete
;c
表示db cmd
;n
表示no op
, 空操做,其會按期執行以確保時效性;ns
:操做所在的namespace
o
:操做所對應的document,即當前操做的內容(好比更新操做時要更新的的字段和值)
從服務器會按期從主服務器中獲取oplog記錄,而後在本機上執行!
對於存儲oplog
的集合,MongoDB
採用的是固定集合,也就是說隨着操做過多,新的操做會覆蓋舊的操做!這樣作也是有道理的,否則,這個集合佔用的空間就沒法估算了!咱們在啓動服務時,能夠經過選項--oplogSize
來指定這個集合的大小,單位是MB
,在Windows
平臺下,默認MongoDB
會使用數據庫安裝分區可用空間的5%做爲這個集合的大小!
' | 成爲Primary |
對客戶端可見 | 參與同步 | 延遲同步 | 複製數據 |
---|---|---|---|---|---|
Primary |
√ | √ | √ | ' | √ |
Secondary |
' | √ | √ | ' | √ |
Hidden |
' | ' | √ | ' | √ |
Delayed |
' | √ | √ | √ | √ |
Arbiters |
' | ' | √ | ' | ' |
Non-Voting |
√ | √ | ' | ' | √ |