備注:
MongoDB 4.2 版本
文章目錄
- 一.複制簡介
-
- 1.1 主動成員與被動成員
- 1.2 master
- 1.3 secondary
- 1.4 arbiter
- 1.5 oplog
- 二.副本集維護
-
- 2.1 建立副本集
-
- 2.1.1 啟動副本內建員
- 2.1.2 初始化副本集
- 2.2 向副本集添加伺服器
- 2.3 設定輔助伺服器
- 2.4 向副本集添加仲裁伺服器
- 2.5 設定被動伺服器
- 2.6 管理副本集
- FAQ
-
- 1.重新初始化
- 2.删除副本集
- 參考
一.複制簡介
我們使用的是單台伺服器 ,一個 mongod 伺服器程序 。如果隻 是用作學習和開發,這是可以的,但是如果用到生産環境中,風險會很高:如果伺服器崩潰了或者不可通路了怎麼辦 ?資料庫至少會有 一段時間不可用 。如果是硬體出了問題,可能需要将資料轉移到另一個機器上。在最壞的情況下,磁盤或者網絡 問題可能會導緻資料損壞或者資料不可通路 。
使用複制可以将資料副本儲存到多台伺服器上,建議在所有的生産環境中都要使用 。使用 MongoDB 的複制功能 ,即使一台或多台伺服器出錯 ,也可以保證應用程式 正 常運作和資料安全 。
在MongoDB中,建立一個副本集之後就可以使用複制功能了。副本集是一組伺服器 ,其中有一個主伺服器 (primary) ,用于處理用戶端請求, 還有多個備份伺服器 ( secondary ),用于儲存主伺服器 的資料副本。如果主伺服器崩潰了 ,備份伺服器會自動将其中一個成員更新為新的主伺服器 。
使用複制功能時 ,如果有一台伺服器當機了 ,仍然可以從副本集的其他伺服器上通路資料。如果伺服器上的資料損壞或者不可通路,可以從副本集的某個成員中建立 一份新的資料副本 。
副本集是一種建立多個MongoDB執行個體的方式,這些執行個體将擁有相同的資料(備援)和其它相關設定。主從複制、主主複制、複制對等方法都被副本集的概念所取代。在MongoDB中,副本集由一個主節點以及多個輔助或仲裁節點組成,一個副本集最少應該有3個成員。在MongoDB 3.0中,副本集最多可以有50個被動成員和7個主動成員。通常建議副本集有奇數個成員,這條規則主要是為了避免“腦裂”(split brain)問題,也就是說當網絡出現問題時,有兩台伺服器成為主伺服器的情況。
1.1 主動成員與被動成員
副本集提供了主動成員與被動成員。目前的主伺服器不可用時,被動伺服器不會參與新的主伺服器的選舉,但它們可投票否決某個成員的主伺服器資格。
1.2 master
在副本集術語中,主伺服器是在特定時間内副本集的資料來源。它是副本集中唯一可以寫入的節點。所有其它節點都将從主伺服器複制出它們的資料。主伺服器由所有主動成員中的大多數投票産生,這被稱為法定人數(quorum)。
主伺服器的概念是(并且應該是)短暫的。理想情況下不應該固定地認為哪個節點是主伺服器。
1.3 secondary
輔助伺服器成員是具有資料的非主伺服器成員,理論上它可以成為主伺服器。它是一個隻讀節點,同時它将以盡可能接近于實時的方式從主伺服器複制資料。預設情況下,如果連接配接到輔助伺服器但不使用任何讀偏好,就不能執行讀操作。這是因為讀取非主伺服器時,如果複制過程中存在延遲,讀取的可能是舊資料。可以使用rs.slaveOk()将目前連接配接設定為可從輔助伺服器讀取資料。或者如果使用的是某種語言的MongoDB驅動,那麼也可以設定讀偏好。
MongoDB的讀偏好是它選擇從哪個副本內建員讀取資料的方式。通過為驅動指定一個讀偏好,它将知道應該在副本集的哪個成員上執行查詢。如果設定了讀偏好,就意味着可能從輔助伺服器讀取資料。必須注意,得到的資料可能不是最新的。
1.4 arbiter
仲裁伺服器是不含資料的節點,如果副本集中的主動成員是偶數,它就用于提供額外的主動成員,決定哪個節點成為主伺服器。仲裁伺服器用于幫助避免“腦裂”。
1.5 oplog
oplog(記錄檔)是一個固定大小的集合,儲存主伺服器執行個體對資料庫做出修改的記錄,目的是在輔助伺服器重做這些操作,保證資料庫處于一緻狀态。副本集的每個成員維護自己的oplog,并且輔助伺服器将查詢主伺服器(或者用過複制鍊進行其它資料更新的輔助伺服器)的oplog,進而獲得新條目,并應用到自己的資料庫副本中。
oplog将為每個條目建立一個時間戳。通過這種方式,輔助伺服器可以記錄從上一次讀取開始過去了多久,以及有多少oplog需要讀取。可将oplog看成主伺服器執行個體最近活動的視窗:如果視窗太小,那麼記錄中的某些操作可能在被應用到輔助伺服器之前丢失。如果目前執行個體的oplog尚未建立,那麼使用–oplogSize啟動選項可以設定oplog的大小(以MB為機關)。在64位Linux系統中,oplogSize預設設定為可以磁盤空間的5%,最小為1GB,最大為50GB。
二.副本集維護
環境如下:
IP | 主機名 | 類别 |
---|---|---|
10.31.1.126 | 10-31-1-126 | 主動成員1 |
10.31.1.125 | 10-31-1-125 | 主動成員2 |
10.31.1.124 | 10-31-1-124 | 被動成員1 |
10.31.1.123 | 10-31-1-123 | 仲裁 |
vi /etc/hosts
10.31.1.123 10-31-1-123
10.31.1.124 10-31-1-124
10.31.1.125 10-31-1-125
10.31.1.126 10-31-1-126
2.1 建立副本集
2.1.1 啟動副本內建員
以下指令在126上執行:
# 建立autokey檔案
mkdir -p /usr/local/mongodb/
cd /usr/local/mongodb/
openssl rand -base64 756 > autokey
# 修改讀寫模式
chmod 400 autokey
# 複制到副本內建員節點
scp autokey 10.31.1.125:/usr/local/mongodb/
scp autokey 10.31.1.124:/usr/local/mongodb/
scp autokey 10.31.1.123:/usr/local/mongodb/
修改配置檔案
mkdir -p /usr/local/mongodb/data/db
mkdir -p /usr/local/mongodb/data/logs
-- 清空配置檔案
>/etc/mongod.conf
vi /etc/mongod.conf
如下為配置檔案内容:
processManagement:
fork: true
storage:
dbPath: "/usr/local/mongodb/data/db"
systemLog:
destination: file
path: "/usr/local/mongodb/data/logs/mongodb.log"
logAppend: true
net:
port: 27017
bindIp: 0.0.0.0
security:
authorization: enabled
keyFile: /usr/local/mongodb/autokey
replication:
replSetName: rs
重新開機mongod服務
pkill mongod
mongod -f /etc/mongod.conf
2.1.2 初始化副本集
在126執行個體中執行:
-- root使用者才有權限進行下列操作,其它使用者會報錯
use admin
db.auth("root","123456")
-- 添加叢集使用者
db.getSiblingDB("admin").createUser(
{
"user" : "clusteradmin",
"pwd" : "123456",
roles: [ { "role" : "clusterAdmin", "db" : "admin" },{ role: "userAdminAnyDatabase", db: "admin" } ]
}
)
> rs.initiate();
{
"info2" : "no configuration specified. Using a default configuration for the set",
"me" : "10-31-1-126:27017",
"ok" : 1
}
rs:SECONDARY>
2.2 向副本集添加伺服器
在126執行個體中執行:
rs.add("10.31.1.125:27017");
rs.add("10.31.1.124:27017");
測試記錄:
rs:PRIMARY> rs.add("10.31.1.125:27017");
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1604991804, 1),
"signature" : {
"hash" : BinData(0,"i5uD9w9i5OH20FxMY9+ZXv2fe8Q="),
"keyId" : NumberLong("6893333011551485956")
}
},
"operationTime" : Timestamp(1604991804, 1)
}
rs:PRIMARY>
rs:PRIMARY> rs.add("10.31.1.124:27017");
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1604992027, 1),
"signature" : {
"hash" : BinData(0,"eF7nAViPRSGL8QMOpX0PZJS1gek="),
"keyId" : NumberLong("6893333011551485956")
}
},
"operationTime" : Timestamp(1604992027, 1)
}
rs:PRIMARY>
2.3 設定輔助伺服器
在126執行個體中執行以下指令,将124設定為隐藏,并且優先級為0:
rs:PRIMARY> conf = rs.conf();
{
"_id" : "rs",
"version" : 3,
"protocolVersion" : NumberLong(1),
"writeConcernMajorityJournalDefault" : true,
"members" : [
{
"_id" : 0,
"host" : "10-31-1-126:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 1,
"host" : "10.31.1.125:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 2,
"host" : "10.31.1.124:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
}
],
"settings" : {
"chainingAllowed" : true,
"heartbeatIntervalMillis" : 2000,
"heartbeatTimeoutSecs" : 10,
"electionTimeoutMillis" : 10000,
"catchUpTimeoutMillis" : -1,
"catchUpTakeoverDelayMillis" : 30000,
"getLastErrorModes" : {
},
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
},
"replicaSetId" : ObjectId("5faa09da100d84a061f33286")
}
}
rs:PRIMARY> conf.members[2].hidden = true
true
rs:PRIMARY> conf.members[2].priority = 0
0
rs:PRIMARY> rs.reconfig(conf);
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1604992141, 1),
"signature" : {
"hash" : BinData(0,"C7QDx9sWsMwGSeZYMZUf+8hWFL0="),
"keyId" : NumberLong("6893333011551485956")
}
},
"operationTime" : Timestamp(1604992141, 1)
}
rs:PRIMARY>
這樣124不會被選舉為主伺服器。
2.4 向副本集添加仲裁伺服器
在126執行個體中執行:
rs:PRIMARY> rs.addArb("10.31.1.123:27017");
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1604992252, 1),
"signature" : {
"hash" : BinData(0,"BLF8bW3Ug2/g6Cjz8W+j9Yf95AI="),
"keyId" : NumberLong("6893333011551485956")
}
},
"operationTime" : Timestamp(1604992252, 1)
}
rs:PRIMARY>
2.5 設定被動伺服器
現在副本集中有4個節點,需要使主動成員數為奇數,在126執行個體中執行:
rs:PRIMARY> conf = rs.conf()
{
"_id" : "rs",
"version" : 5,
"protocolVersion" : NumberLong(1),
"writeConcernMajorityJournalDefault" : true,
"members" : [
{
"_id" : 0,
"host" : "10-31-1-126:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 1,
"host" : "10.31.1.125:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 2,
"host" : "10.31.1.124:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : true,
"priority" : 0,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 3,
"host" : "10.31.1.123:27017",
"arbiterOnly" : true,
"buildIndexes" : true,
"hidden" : false,
"priority" : 0,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
}
],
"settings" : {
"chainingAllowed" : true,
"heartbeatIntervalMillis" : 2000,
"heartbeatTimeoutSecs" : 10,
"electionTimeoutMillis" : 10000,
"catchUpTimeoutMillis" : -1,
"catchUpTakeoverDelayMillis" : 30000,
"getLastErrorModes" : {
},
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
},
"replicaSetId" : ObjectId("5faa09da100d84a061f33286")
}
}
rs:PRIMARY> conf.members[2].votes = 0
0
rs:PRIMARY> rs.reconfig(conf)
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1604992330, 1),
"signature" : {
"hash" : BinData(0,"k8bFCCLaGDXGQmBIgN7r2VFobjA="),
"keyId" : NumberLong("6893333011551485956")
}
},
"operationTime" : Timestamp(1604992330, 1)
}
rs:PRIMARY>
124的votes值設定為0,現在hdp2完全變成被動伺服器,它被用戶端看成副本集的一部分,并且不會參與選舉,也永遠不會變成主伺服器。
2.6 管理副本集
指令 | 描述 |
---|---|
rs.help() | 傳回指令清單。 |
rs.status() | 傳回副本集目前的狀态資訊。該指令列出了每個成員伺服器及其狀态資訊,包括最後聯系時間。該調用可被用于提供整個叢集的簡單健康檢查。 |
rs.initiate() | 使用預設參數初始化副本集。 |
rs.initiate(replSetcfg) | 使用配置描述初始化副本集。 |
rs.add(“host:port”) | 使用含有主機名和特定端口(可選)的簡單字元串向副本集中添加成員伺服器。 |
rs.add(membercfg) | 使用配置描述向副本集中添加成員伺服器。如果希望指定特定的屬性(如設定新成員伺服器的優先級),那麼必須使用這種方法。 |
rs.addArb(“host:port”) | 添加新的成員伺服器作為仲裁者。該成員不需要使用—replSet選項:任何運作在可達機器上的mongod執行個體都可以執行該任務。注意該伺服器必須對副本集中的所有成員可達。 |
rs.stepDown() | 在副本集的主伺服器成員中使用該指令時,将使主伺服器放棄它的角色,并且在叢集中重新選舉新的主伺服器。注意隻有主動輔助伺服器可用作主伺服器的候選,并且在60秒(預設)之内如果沒有出現其它可用的成員,那麼原有的主伺服器将重新成為主伺服器。 |
rs.syncFrom(“host:port”) | 使輔助伺服器從指定的成員同步資料,可用于組成同步鍊。 |
rs.freeze(secs) | 當機指定的成員,并使它在指定秒數内無法成為主伺服器。 |
rs.remove(“host:port”) | 從副本集中删除指定成員。 |
rs.secondaryOk()() | 通過該選項,可以允許從輔助伺服器讀取資料。 |
rs.conf() | 重新顯示目前副本集的配置結構。改配置結構可以被修改,然後用作rs.reconfig()的參數,進而修改結構的配置。 |
db.isMaster() | 該函數不隻可作用于副本集:它是一個通用的複制支援函數。通過它,應用或驅動可以判斷出被連接配接的特定執行個體在複制拓撲結構中是否是主伺服器。 |
rs.status字段的值:
值 | 描述 |
---|---|
_id | 副本集中該成員的ID |
Name | 該成員的主機名 |
Health | replSet的健康值 |
State | 狀态數值 |
StateStr | 副本集狀态的字元串表示 |
Uptime | 該成員的運作時間 |
optime | 應用在該成員上最後一個操作的時間,格式為一個時間戳和一個整數值 |
optimeDate | 最後一個被應用操作的日期 |
lastHeartbeat | 最後一次發送心跳的日期 |
lastHeartbeatRecv | 最後一次收到心跳的日期 |
configVersion | 這個成員使用的副本集配置的版本 |
syncingTo | 使用哪個副本內建員同步資料 |
FAQ
1.重新初始化
cfg = rs.conf()
cfg.members[0].host = "你的IP 或者域名"
rs.reconfig(cfg)
測試記錄:
rs:PRIMARY> cfg = rs.conf()
{
"_id" : "rs",
"version" : 9,
"protocolVersion" : NumberLong(1),
"writeConcernMajorityJournalDefault" : true,
"members" : [
{
"_id" : 0,
"host" : "10-31-1-126:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
}
],
"settings" : {
"chainingAllowed" : true,
"heartbeatIntervalMillis" : 2000,
"heartbeatTimeoutSecs" : 10,
"electionTimeoutMillis" : 10000,
"catchUpTimeoutMillis" : -1,
"catchUpTakeoverDelayMillis" : 30000,
"getLastErrorModes" : {
},
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
},
"replicaSetId" : ObjectId("5faa09da100d84a061f33286")
}
}
rs:PRIMARY> cfg.members[0].host = "10.31.1.126"
10.31.1.126
rs:PRIMARY> rs.reconfig(cfg)
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1605085418, 1),
"signature" : {
"hash" : BinData(0,"hSupkyIZ07GWPVflfMd4M4iHV6c="),
"keyId" : NumberLong("6893333011551485956")
}
},
"operationTime" : Timestamp(1605085418, 1)
}
2.删除副本集
主節點是删除不了的,至少要有一個主節點要存在。
另外,其它節點雖然從副本集退出了,但是舊的配置依舊存在,如果要配置其它的,會影響到
-- 125 被清理出副本集之後,重新配置分片無法成功,清理這個表之後成功
-- 如果有授權問題,先忽略授權,删除了之後,再調整配置檔案
> use local
switched to db local
>
>
> db.dropDatabase();
{ "dropped" : "local", "ok" : 1 }
>
參考
1.MongoDB權威指南(第二版)
2.https://blog.csdn.net/wzy0623/article/details/83113823
3.https://www.cnblogs.com/s6-b/p/11288583.html
4.https://blog.csdn.net/yuanwei1144/article/details/103840914