安卓軟件開發(fā)app/優(yōu)化關鍵詞的方法包括
一、副本集 Replica Sets
1.1 簡介
????????MongoDB 中的副本集(Replica Set)是一組維護相同數(shù)據(jù)集的 mongod 服務。 副本集可提供冗余和高可用性,是所有生產部署的基礎。
????????也可以說,副本集類似于有自動故障恢復功能的主從集群。通俗的講就是用多臺機器進行同一數(shù)據(jù)的異步同步,從而使多臺機器擁有同一數(shù)據(jù)的多個副本,并且當主庫 down 掉時在不需要用戶干預的情況下自動切換其他備份服務器做主庫。而且還可以利用副本服務器做只讀服務器,實現(xiàn)讀寫分離,提高負載。
1):冗余和數(shù)據(jù)可用性
????????復制提供冗余并提高數(shù)據(jù)可用性。 通過在不同數(shù)據(jù)庫服務器上提供多個數(shù)據(jù)副本,復制可提供一定級別的容錯功能,以防止丟失單個數(shù)據(jù)庫服務器。
????????在某些情況下,復制可以提供增加的讀取性能,因為客戶端可以將讀取操作發(fā)送到不同的服務上, 在不同數(shù)據(jù)中心維護數(shù)據(jù)副本可以增加分布式應用程序的數(shù)據(jù)位置和可用性。 您還可以為專用目的維護其他副本,例如災難恢復,報告或備份。
2):MongoDB 中的復制
????????副本集是一組維護相同數(shù)據(jù)集的 mongod 實例。 副本集包含多個數(shù)據(jù)承載節(jié)點和可選的一個仲裁節(jié)點。在承載數(shù)據(jù)的節(jié)點中,一個且僅一個成員被視為主節(jié)點,而其他節(jié)點被視為次要(從)節(jié)點。
????????主節(jié)點接收所有寫操作。 副本集只能有一個主要的寫入; 雖然在某些情況下,另一個 mongod 實例可能暫時認為自己也是主要的。主要記錄其操作日志中的數(shù)據(jù)集的所有更改,即 oplog。
????????輔助(副本)節(jié)點復制主節(jié)點的 oplog 并將操作應用于其數(shù)據(jù)集,以使輔助節(jié)點的數(shù)據(jù)集反映主節(jié)點的數(shù)據(jù)集。 如果主要人員不在,則符合條件的中學將舉行選舉以選出新的主要人員。
3):主從復制和副本集區(qū)別
????????主從集群和副本集最大的區(qū)別就是副本集沒有固定的 “主節(jié)點”;整個集群會選出一個“主節(jié)點”,當其掛掉后,又在剩下的從節(jié)點中選中其他節(jié)點為 “主節(jié)點”,副本集總有一個活躍點(主、primary) 和一個或多個備份節(jié)點 (從、secondary)。
1.2 副本集三個角色
? ? ? ? 副本集有兩種類型三種角色。
兩種類型:
????????主節(jié)點(Primary)類型:數(shù)據(jù)操作的主要連接點,可讀寫。
????????次要(輔助、從)節(jié)點(Secondaries)類型:數(shù)據(jù)冗余備份節(jié)點,可以讀或選舉。
三種角色:
????????主要成員(Primary):主要接收所有寫操作。就是主節(jié)點。
????????副本成員(Replicate):從主節(jié)點通過復制操作以維護相同的數(shù)據(jù)集,即備份數(shù)據(jù),不可寫操作,但可以讀操作(但需要配置)。是默認的一種從節(jié)點類型。
????????仲裁者(Arbiter):不保留任何數(shù)據(jù)的副本,只具有投票選舉作用。當然也可以將仲裁服務器維護為副本集的一部分,即副本成員同時也可以是仲裁者。也是一種從節(jié)點類型。
關于仲裁者的額外說明:
????????您可以將額外的 mongod 實例添加到副本集作為仲裁者。 仲裁者不維護數(shù)據(jù)集。 仲裁者的目的是通過響應其他副本集成員的心跳和選舉請求來維護副本集中的仲裁。 因為它們不存儲數(shù)據(jù)集,所以仲裁器可以是提供副本集仲裁功能的好方法,其資源成本比具有數(shù)據(jù)集的全功能副本集成員更便宜。
????????如果您的副本集具有偶數(shù)個成員,請?zhí)砑又俨谜咭垣@得主要選舉中的“大多數(shù)”投票。 仲裁者不需要專用硬件。
????????仲裁者將永遠是仲裁者,而主要人員可能會退出并成為次要人員,而次要人員可能成為選舉期間的主要人員。
????????如果你的副本+主節(jié)點的個數(shù)是偶數(shù),建議加一個仲裁者,形成奇數(shù),容易滿足大多數(shù)的投票。
????????如果你的副本+主節(jié)點的個數(shù)是奇數(shù),可以不加仲裁者。?
1.3 副本集架構目標
? ? ? ? 一主一副本一仲裁,架構圖如下所示:
1.4 副本集的創(chuàng)建
1.4.1 創(chuàng)建主節(jié)點
????????建立存放數(shù)據(jù)和日志的目錄
# 存放日志信息
mkdir -p /usr/local/mongodb/replica_sets/myrs_27017/log# 存放數(shù)據(jù)信息
mkdir -p /usr/local/mongodb/replica_sets/myrs_27017/data/db
????????新建配置信息
vim /usr/local/mongodb/replica_sets/myrs_27017/mongod.conf
? ? ? ? 內容如下:
systemLog:# MongoDB發(fā)送所有日志輸出的目標指定為文件destination: file# mongod或mongos應向其發(fā)送所有診斷日志記錄信息的日志文件的路徑path: "/usr/local/mongodb/replica_sets/myrs_27017/log/mongod.log"# 當mongos或mongod實例重新啟動時,mongos或mongod會將新條目附加到現(xiàn)有日志文件的末尾。logAppend: true
storage:# mongod實例存儲其數(shù)據(jù)的目錄。storage.dbPath設置僅適用于mongod。dbPath: "/usr/local/mongodb/replica_sets/myrs_27017/data/db"journal:# 啟用或禁用持久性日志以確保數(shù)據(jù)文件保持有效和可恢復。enabled: true
processManagement:# 啟用在后臺運行mongos或mongod進程的守護進程模式。fork: true# 指定用于保存mongos或mongod進程的進程ID的文件位置,其中mongos或mongod將寫入其PIDpidFilePath: "/usr/local/mongodb/replica_sets/myrs_27017/log/mongod.pid"
net:# 服務實例綁定所有IP,有副作用,副本集初始化的時候,節(jié)點名字會自動設置為本地域名,而不是ip#bindIpAll: true# 服務實例綁定的IPbindIp: localhost,192.168.229.154#bindIp# 綁定的端口port: 27017
replication:# 副本集的名稱replSetName: myrs
????????啟動節(jié)點服務:
[root@node1 mongodb]# /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/replica_sets/myrs_27017/mongod.conf
about to fork child process, waiting until server is ready for connections.
forked process: 42243
child process started successfully, parent exiting
1.4.2 創(chuàng)建副本節(jié)點
????????建立存放數(shù)據(jù)和日志的目錄
# 存放日志信息
mkdir -p /usr/local/mongodb/replica_sets/myrs_27018/log# 存放數(shù)據(jù)信息
mkdir -p /usr/local/mongodb/replica_sets/myrs_27018/data/db
????????新建配置信息
vim /usr/local/mongodb/replica_sets/myrs_27018/mongod.conf
? ? ? ? 內容如下:
systemLog:# MongoDB發(fā)送所有日志輸出的目標指定為文件destination: file# mongod或mongos應向其發(fā)送所有診斷日志記錄信息的日志文件的路徑path: "/usr/local/mongodb/replica_sets/myrs_27018/log/mongod.log"# 當mongos或mongod實例重新啟動時,mongos或mongod會將新條目附加到現(xiàn)有日志文件的末尾。logAppend: true
storage:# mongod實例存儲其數(shù)據(jù)的目錄。storage.dbPath設置僅適用于mongod。dbPath: "/usr/local/mongodb/replica_sets/myrs_27018/data/db"journal:# 啟用或禁用持久性日志以確保數(shù)據(jù)文件保持有效和可恢復。enabled: true
processManagement:# 啟用在后臺運行mongos或mongod進程的守護進程模式。fork: true# 指定用于保存mongos或mongod進程的進程ID的文件位置,其中mongos或mongod將寫入其PIDpidFilePath: "/usr/local/mongodb/replica_sets/myrs_27018/log/mongod.pid"
net:# 服務實例綁定所有IP,有副作用,副本集初始化的時候,節(jié)點名字會自動設置為本地域名,而不是ip#bindIpAll: true# 服務實例綁定的IPbindIp: localhost,192.168.229.154#bindIp# 綁定的端口port: 27018
replication:# 副本集的名稱replSetName: myrs
????????啟動節(jié)點服務:
[root@node1 mongodb]# /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/replica_sets/myrs_27018/mongod.conf
about to fork child process, waiting until server is ready for connections.
forked process: 45029
child process started successfully, parent exiting
1.4.3 創(chuàng)建仲裁節(jié)點
????????建立存放數(shù)據(jù)和日志的目錄
# 存放日志信息
mkdir -p /usr/local/mongodb/replica_sets/myrs_27019/log# 存放數(shù)據(jù)信息
mkdir -p /usr/local/mongodb/replica_sets/myrs_27019/data/db
????????新建配置信息
vim /usr/local/mongodb/replica_sets/myrs_27019/mongod.conf
? ? ? ? 內容如下:
systemLog:# MongoDB發(fā)送所有日志輸出的目標指定為文件destination: file# mongod或mongos應向其發(fā)送所有診斷日志記錄信息的日志文件的路徑path: "/usr/local/mongodb/replica_sets/myrs_27019/log/mongod.log"# 當mongos或mongod實例重新啟動時,mongos或mongod會將新條目附加到現(xiàn)有日志文件的末尾。logAppend: true
storage:# mongod實例存儲其數(shù)據(jù)的目錄。storage.dbPath設置僅適用于mongod。dbPath: "/usr/local/mongodb/replica_sets/myrs_27019/data/db"journal:# 啟用或禁用持久性日志以確保數(shù)據(jù)文件保持有效和可恢復。enabled: true
processManagement:# 啟用在后臺運行mongos或mongod進程的守護進程模式。fork: true# 指定用于保存mongos或mongod進程的進程ID的文件位置,其中mongos或mongod將寫入其PIDpidFilePath: "/usr/local/mongodb/replica_sets/myrs_27019/log/mongod.pid"
net:# 服務實例綁定所有IP,有副作用,副本集初始化的時候,節(jié)點名字會自動設置為本地域名,而不是ip#bindIpAll: true# 服務實例綁定的IPbindIp: localhost,192.168.229.154#bindIp# 綁定的端口port: 27019
replication:# 副本集的名稱replSetName: myrs
????????啟動節(jié)點服務:
[root@node1 mongodb]# /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/replica_sets/myrs_27019/mongod.conf
about to fork child process, waiting until server is ready for connections.
forked process: 46093
child process started successfully, parent exiting
1.4.4 初始化配置副本集和主節(jié)點
????????使用客戶端命令連接任意一個節(jié)點,但這里盡量要連接主節(jié)點 (27017節(jié)點):
/usr/local/mongodb/bin/mongo --host=192.168.229.154 --port=27017
????????結果,連接上之后,很多命令無法使用,比如 show dbs 等,如下所示,必須初始化副本集才可以。
# 使用默認的配置來初始化副本集
rs.initiate()
# "ok":1,說明創(chuàng)建成功。
# 命令行提示符發(fā)生變化,變成了一個從節(jié)點角色,此時默認不能讀寫。稍等片刻,回車,變成主節(jié)點。
> rs.initiate()
{"info2" : "no configuration specified. Using a default configuration for the set","me" : "192.168.229.154:27017","ok" : 1
}
myrs:SECONDARY>
myrs:PRIMARY>
1.4.5 查看副本集的配置內容
? ? ? ? 查看當前副本集配置的文檔,語法如下:
# rs.config() 是該方法的別名。
# configuration:可選,如果沒有配置,則使用默認主節(jié)點配置
rs.conf(configuration)
????????在 27017 上執(zhí)行副本集中當前節(jié)點的默認節(jié)點配置,如下:
myrs:PRIMARY> rs.conf()
{# 副本集的配置數(shù)據(jù)存儲的主鍵值,默認就是副本集的名字"_id" : "myrs","version" : 1,"protocolVersion" : NumberLong(1),"writeConcernMajorityJournalDefault" : true,# 副本集成員數(shù)組,此時只有一個: "host" : "192.168.229.154:27017" "members" : [{"_id" : 0,"host" : "192.168.229.154:27017",# 該成員不是仲裁節(jié)點"arbiterOnly" : false,"buildIndexes" : true,"hidden" : false,# 優(yōu)先級(權重值)"priority" : 1,"tags" : {},"slaveDelay" : NumberLong(0),"votes" : 1}],# 副本集的參數(shù)配置"settings" : {"chainingAllowed" : true,"heartbeatIntervalMillis" : 2000,"heartbeatTimeoutSecs" : 10,"electionTimeoutMillis" : 10000,"catchUpTimeoutMillis" : -1,"catchUpTakeoverDelayMillis" : 30000,"getLastErrorModes" : {},"getLastErrorDefaults" : {"w" : 1,"wtimeout" : 0},"replicaSetId" : ObjectId("6528b761af0089c47768dd07")}
}
?提示:
????????副本集配置的查看命令,本質是查詢的是 system.replset 的表中的數(shù)據(jù)
myrs:PRIMARY> use local
switched to db local
myrs:PRIMARY> show collections
oplog.rs
replset.election
replset.minvalid
replset.oplogTruncateAfterPoint
startup_log
system.replset
system.rollback.id
myrs:PRIMARY> db.system.replset.find()
{ "_id" : "myrs", "version" : 1, "protocolVersion" : NumberLong(1), "writeConcernMajorityJournalDefault" : true, "members" : [ { "_id" : 0, "host" : "192.168.229.154: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("6528b761af0089c47768dd07") } }
myrs:PRIMARY>
1.4.6 查看副本集狀態(tài)
????????返回包含狀態(tài)信息的文檔。此輸出使用從副本集的其他成員發(fā)送的心跳包中獲得的數(shù)據(jù)反映副本集的當前狀態(tài)。語法如下:
rs.status()
# 在 27017 上查看副本集狀態(tài)
myrs:PRIMARY> rs.status()
{# 副本集的名字"set" : "myrs","date" : ISODate("2023-10-13T06:33:05.838Z"),# 說明狀態(tài)正常"myState" : 1,"term" : NumberLong(1),"syncingTo" : "","syncSourceHost" : "","syncSourceId" : -1,"heartbeatIntervalMillis" : NumberLong(2000),"optimes" : {"lastCommittedOpTime" : {"ts" : Timestamp(1697178781, 1),"t" : NumberLong(1)},"readConcernMajorityOpTime" : {"ts" : Timestamp(1697178781, 1),"t" : NumberLong(1)},"appliedOpTime" : {"ts" : Timestamp(1697178781, 1),"t" : NumberLong(1)},"durableOpTime" : {"ts" : Timestamp(1697178781, 1),"t" : NumberLong(1)}},"lastStableCheckpointTimestamp" : Timestamp(1697178721, 1),"electionCandidateMetrics" : {"lastElectionReason" : "electionTimeout","lastElectionDate" : ISODate("2023-10-13T03:20:02.154Z"),"electionTerm" : NumberLong(1),"lastCommittedOpTimeAtElection" : {"ts" : Timestamp(0, 0),"t" : NumberLong(-1)},"lastSeenOpTimeAtElection" : {"ts" : Timestamp(1697167201, 1),"t" : NumberLong(-1)},"numVotesNeeded" : 1,"priorityAtElection" : 1,"electionTimeoutMillis" : NumberLong(10000),"newTermStartDate" : ISODate("2023-10-13T03:20:02.231Z"),"wMajorityWriteAvailabilityDate" : ISODate("2023-10-13T03:20:02.308Z")},# 副本集成員數(shù)組,此時只有一個"members" : [{"_id" : 0,"name" : "192.168.229.154:27017",# 該節(jié)點是健康的"health" : 1,"state" : 1,"stateStr" : "PRIMARY","uptime" : 12350,"optime" : {"ts" : Timestamp(1697178781, 1),"t" : NumberLong(1)},"optimeDate" : ISODate("2023-10-13T06:33:01Z"),"syncingTo" : "","syncSourceHost" : "","syncSourceId" : -1,"infoMessage" : "","electionTime" : Timestamp(1697167202, 1),"electionDate" : ISODate("2023-10-13T03:20:02Z"),"configVersion" : 1,"self" : true,"lastHeartbeatMessage" : ""}],"ok" : 1,"operationTime" : Timestamp(1697178781, 1),"$clusterTime" : {"clusterTime" : Timestamp(1697178781, 1),"signature" : {"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),"keyId" : NumberLong(0)}}
}
1.4.7 添加副本從節(jié)點
????????在主節(jié)點添加從節(jié)點,將其他成員加入到副本集,語法如下:
# host格式為:ip地址:端口號
rs.add(host)
????????將 27018 的副本節(jié)點添加到副本集中,命令如下:
myrs:PRIMARY> rs.add("192.168.229.154:27018")
{# 說明添加成功"ok" : 1,"operationTime" : Timestamp(1697179246, 1),"$clusterTime" : {"clusterTime" : Timestamp(1697179246, 1),"signature" : {"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),"keyId" : NumberLong(0)}}
}
? ? ? ? 此時,再次查看副本集狀態(tài)
myrs:PRIMARY> rs.status()
{"set" : "myrs","date" : ISODate("2023-10-13T06:41:58.219Z"),"myState" : 1,"term" : NumberLong(1),"syncingTo" : "","syncSourceHost" : "","syncSourceId" : -1,"heartbeatIntervalMillis" : NumberLong(2000),"optimes" : {"lastCommittedOpTime" : {"ts" : Timestamp(1697179312, 1),"t" : NumberLong(1)},"readConcernMajorityOpTime" : {"ts" : Timestamp(1697179312, 1),"t" : NumberLong(1)},"appliedOpTime" : {"ts" : Timestamp(1697179312, 1),"t" : NumberLong(1)},"durableOpTime" : {"ts" : Timestamp(1697179312, 1),"t" : NumberLong(1)}},"lastStableCheckpointTimestamp" : Timestamp(1697179262, 1),"electionCandidateMetrics" : {"lastElectionReason" : "electionTimeout","lastElectionDate" : ISODate("2023-10-13T03:20:02.154Z"),"electionTerm" : NumberLong(1),"lastCommittedOpTimeAtElection" : {"ts" : Timestamp(0, 0),"t" : NumberLong(-1)},"lastSeenOpTimeAtElection" : {"ts" : Timestamp(1697167201, 1),"t" : NumberLong(-1)},"numVotesNeeded" : 1,"priorityAtElection" : 1,"electionTimeoutMillis" : NumberLong(10000),"newTermStartDate" : ISODate("2023-10-13T03:20:02.231Z"),"wMajorityWriteAvailabilityDate" : ISODate("2023-10-13T03:20:02.308Z")},"members" : [{"_id" : 0,"name" : "192.168.229.154:27017","health" : 1,"state" : 1,"stateStr" : "PRIMARY","uptime" : 12883,"optime" : {"ts" : Timestamp(1697179312, 1),"t" : NumberLong(1)},"optimeDate" : ISODate("2023-10-13T06:41:52Z"),"syncingTo" : "","syncSourceHost" : "","syncSourceId" : -1,"infoMessage" : "","electionTime" : Timestamp(1697167202, 1),"electionDate" : ISODate("2023-10-13T03:20:02Z"),"configVersion" : 2,"self" : true,"lastHeartbeatMessage" : ""},# 這個新創(chuàng)建的第二個角色{"_id" : 1,"name" : "192.168.229.154:27018","health" : 1,"state" : 2,"stateStr" : "SECONDARY","uptime" : 71,"optime" : {"ts" : Timestamp(1697179312, 1),"t" : NumberLong(1)},"optimeDurable" : {"ts" : Timestamp(1697179312, 1),"t" : NumberLong(1)},"optimeDate" : ISODate("2023-10-13T06:41:52Z"),"optimeDurableDate" : ISODate("2023-10-13T06:41:52Z"),"lastHeartbeat" : ISODate("2023-10-13T06:41:56.894Z"),"lastHeartbeatRecv" : ISODate("2023-10-13T06:41:57.236Z"),"pingMs" : NumberLong(0),"lastHeartbeatMessage" : "","syncingTo" : "192.168.229.154:27017","syncSourceHost" : "192.168.229.154:27017","syncSourceId" : 0,"infoMessage" : "","configVersion" : 2}],"ok" : 1,"operationTime" : Timestamp(1697179312, 1),"$clusterTime" : {"clusterTime" : Timestamp(1697179312, 1),"signature" : {"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),"keyId" : NumberLong(0)}}
}
1.4.8 添加仲裁從節(jié)點
????????添加一個仲裁節(jié)點到副本集,語法如下:
rs.addArb(host)
????????將 27019?的仲裁節(jié)點添加到副本集中?
myrs:PRIMARY> rs.addArb("192.168.229.154:27019")
{# 說明添加成功"ok" : 1,"operationTime" : Timestamp(1697179436, 1),"$clusterTime" : {"clusterTime" : Timestamp(1697179436, 1),"signature" : {"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),"keyId" : NumberLong(0)}}
}
?? ? ? ? 此時,再次查看副本集狀態(tài)
myrs:PRIMARY> rs.status()
{"set" : "myrs","date" : ISODate("2023-10-13T06:45:08.595Z"),"myState" : 1,"term" : NumberLong(1),"syncingTo" : "","syncSourceHost" : "","syncSourceId" : -1,"heartbeatIntervalMillis" : NumberLong(2000),"optimes" : {"lastCommittedOpTime" : {"ts" : Timestamp(1697179502, 1),"t" : NumberLong(1)},"readConcernMajorityOpTime" : {"ts" : Timestamp(1697179502, 1),"t" : NumberLong(1)},"appliedOpTime" : {"ts" : Timestamp(1697179502, 1),"t" : NumberLong(1)},"durableOpTime" : {"ts" : Timestamp(1697179502, 1),"t" : NumberLong(1)}},"lastStableCheckpointTimestamp" : Timestamp(1697179436, 1),"electionCandidateMetrics" : {"lastElectionReason" : "electionTimeout","lastElectionDate" : ISODate("2023-10-13T03:20:02.154Z"),"electionTerm" : NumberLong(1),"lastCommittedOpTimeAtElection" : {"ts" : Timestamp(0, 0),"t" : NumberLong(-1)},"lastSeenOpTimeAtElection" : {"ts" : Timestamp(1697167201, 1),"t" : NumberLong(-1)},"numVotesNeeded" : 1,"priorityAtElection" : 1,"electionTimeoutMillis" : NumberLong(10000),"newTermStartDate" : ISODate("2023-10-13T03:20:02.231Z"),"wMajorityWriteAvailabilityDate" : ISODate("2023-10-13T03:20:02.308Z")},"members" : [{"_id" : 0,"name" : "192.168.229.154:27017","health" : 1,"state" : 1,"stateStr" : "PRIMARY","uptime" : 13073,"optime" : {"ts" : Timestamp(1697179502, 1),"t" : NumberLong(1)},"optimeDate" : ISODate("2023-10-13T06:45:02Z"),"syncingTo" : "","syncSourceHost" : "","syncSourceId" : -1,"infoMessage" : "","electionTime" : Timestamp(1697167202, 1),"electionDate" : ISODate("2023-10-13T03:20:02Z"),"configVersion" : 3,"self" : true,"lastHeartbeatMessage" : ""},{"_id" : 1,"name" : "192.168.229.154:27018","health" : 1,"state" : 2,"stateStr" : "SECONDARY","uptime" : 262,"optime" : {"ts" : Timestamp(1697179502, 1),"t" : NumberLong(1)},"optimeDurable" : {"ts" : Timestamp(1697179502, 1),"t" : NumberLong(1)},"optimeDate" : ISODate("2023-10-13T06:45:02Z"),"optimeDurableDate" : ISODate("2023-10-13T06:45:02Z"),"lastHeartbeat" : ISODate("2023-10-13T06:45:06.956Z"),"lastHeartbeatRecv" : ISODate("2023-10-13T06:45:06.973Z"),"pingMs" : NumberLong(0),"lastHeartbeatMessage" : "","syncingTo" : "192.168.229.154:27017","syncSourceHost" : "192.168.229.154:27017","syncSourceId" : 0,"infoMessage" : "","configVersion" : 3},{"_id" : 2,"name" : "192.168.229.154:27019","health" : 1,"state" : 7,"stateStr" : "ARBITER","uptime" : 71,"lastHeartbeat" : ISODate("2023-10-13T06:45:06.955Z"),"lastHeartbeatRecv" : ISODate("2023-10-13T06:45:06.956Z"),"pingMs" : NumberLong(0),"lastHeartbeatMessage" : "","syncingTo" : "","syncSourceHost" : "","syncSourceId" : -1,"infoMessage" : "","configVersion" : 3}],"ok" : 1,"operationTime" : Timestamp(1697179502, 1),"$clusterTime" : {"clusterTime" : Timestamp(1697179502, 1),"signature" : {"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),"keyId" : NumberLong(0)}}
}
1.5 副本集讀寫操作
? ? ? ? 接下來我們測試三個不同角色的節(jié)點的數(shù)據(jù)讀寫情況。登錄主節(jié)點?27017,寫入和讀取數(shù)據(jù)
myrs:PRIMARY> use articledb
switched to db articledb
myrs:PRIMARY> db
articledb
myrs:PRIMARY> db.comment.insert({"articleid":"100000","content":"今天天氣真好,陽光明媚","userid":"1001","nickname":"Rose","createdatetime":new Date()})
WriteResult({ "nInserted" : 1 })
myrs:PRIMARY> db.comment.find()
{ "_id" : ObjectId("6528e8155dabb447bc9211d2"), "articleid" : "100000", "content" : "今天天氣真好,陽光明媚", "userid" : "1001", "nickname" : "Rose", "createdatetime" : ISODate("2023-10-13T06:47:49.542Z") }
????????登錄從節(jié)點 27018 ?
myrs:SECONDARY> show dbs
2023-10-13T00:06:41.119-0700 E QUERY [js] Error: listDatabases failed:{"operationTime" : Timestamp(1697180793, 1),"ok" : 0,"errmsg" : "not master and slaveOk=false","code" : 13435,"codeName" : "NotMasterNoSlaveOk","$clusterTime" : {"clusterTime" : Timestamp(1697180793, 1),"signature" : {"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),"keyId" : NumberLong(0)}}
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:151:1
shellHelper.show@src/mongo/shell/utils.js:882:13
shellHelper@src/mongo/shell/utils.js:766:15
@(shellhelp2):1:1
????????發(fā)現(xiàn),不能讀取集合的數(shù)據(jù)。當前從節(jié)點只是一個備份,不是奴隸節(jié)點,無法讀取數(shù)據(jù),寫當然更不行。
????????因為默認情況下,從節(jié)點是沒有讀寫權限的,可以增加讀的權限,但需要進行設置。
# 設置讀操作權限
# 該命令是 db.getMongo().setSlaveOk() 的簡化命令。
rs.slaveOk() 或 rs.slaveOk(true)
# 在 27018 上設置作為奴隸節(jié)點權限,具備讀權限
myrs:SECONDARY> rs.slaveOk()
WARNING: slaveOk() is deprecated and may be removed in the next major release. Please use secondaryOk() instead.
# 執(zhí)行查詢命令,運行成功!
myrs:SECONDARY> show dbs
admin 0.000GB
articledb 0.000GB
config 0.000GB
local 0.000GB
myrs:SECONDARY> db.comment.find()
myrs:SECONDARY> use articledb
switched to db articledb
myrs:SECONDARY> db.comment.find()
{ "_id" : ObjectId("6528e8155dabb447bc9211d2"), "articleid" : "100000", "content" : "今天天氣真好,陽光明媚", "userid" : "1001", "nickname" : "Rose", "createdatetime" : ISODate("2023-10-13T06:47:49.542Z") }
# 但仍然不允許插入
myrs:SECONDARY> db.comment.insert({"_id":"1","articleid":"100001","content":"我們不應該把清晨浪費在手機上,健康很重要,k一杯溫水幸福你我他。","userid":"1002","nickname":"相忘于江湖","createdatetime":new Date("2019-08-05T22:08:15.522Z"),"likenum":NumberInt(1000),"state":"1"})
WriteCommandError({"operationTime" : Timestamp(1697181093, 1),"ok" : 0,"errmsg" : "not master","code" : 10107,"codeName" : "NotMaster","$clusterTime" : {"clusterTime" : Timestamp(1697181093, 1),"signature" : {"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),"keyId" : NumberLong(0)}}
})
????????現(xiàn)在實現(xiàn)了讀寫分離,讓主插入數(shù)據(jù),讓從來讀取數(shù)據(jù)。
????????如果要取消作為奴隸節(jié)點的讀權限:
rs.slaveOk(false)
# 在 27018 取消設置奴隸節(jié)點權限
myrs:SECONDARY> rs.slaveOk(false)
WARNING: slaveOk() is deprecated and may be removed in the next major release. Please use secondaryOk() instead.
# 無法再查看數(shù)據(jù)
myrs:SECONDARY> db.comment.find()
Error: error: {"operationTime" : Timestamp(1697181203, 1),"ok" : 0,"errmsg" : "not master and slaveOk=false","code" : 13435,"codeName" : "NotMasterNoSlaveOk","$clusterTime" : {"clusterTime" : Timestamp(1697181203, 1),"signature" : {"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),"keyId" : NumberLong(0)}}
}
????????仲裁者節(jié)點,不存放任何業(yè)務數(shù)據(jù)的,可以登錄查看
# 登錄 27019 節(jié)點
/usr/local/mongodb/bin/mongo --host 192.168.229.154 --port 27019# 設置為奴隸節(jié)點
myrs:ARBITER> rs.slaveOk()
WARNING: slaveOk() is deprecated and may be removed in the next major release. Please use secondaryOk() instead.
# 無法查看相關信息
myrs:ARBITER> show dbs
2023-10-13T00:15:19.072-0700 E QUERY [js] Error: listDatabases failed:{"ok" : 0,"errmsg" : "node is not in primary or recovering state","code" : 13436,"codeName" : "NotMasterOrSecondary"
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:151:1
shellHelper.show@src/mongo/shell/utils.js:882:13
shellHelper@src/mongo/shell/utils.js:766:15
@(shellhelp2):1:1
?1.6 主節(jié)點的選舉原則
????????MongoDB 在副本集中,會自動進行主節(jié)點的選舉,主節(jié)點選舉的觸發(fā)條件:
a、主節(jié)點故障
b、主節(jié)點網(wǎng)絡不可達(默認心跳信息為10秒)
c、人工干預(rs.stepDown(600))
????????一旦觸發(fā)選舉,就要根據(jù)一定規(guī)則來選主節(jié)點。選舉規(guī)則是根據(jù)票數(shù)來決定誰獲勝:
票數(shù)最高,并且獲得了 “大多數(shù)” 成員的投票支持的節(jié)點獲勝。
? ? ? ? “大多數(shù)” 的定義為:假設復制集內投票成員數(shù)量為 N,則大多數(shù)為 N/2 + 1。例如:3 個投票成員,則大多數(shù)的值是 2。當復制集內存活成員數(shù)量不足大多數(shù)時,整個復制集將無法選舉出?Primary,復制集將無法提供寫服務,處于只讀狀態(tài)。
若票數(shù)相同,且都獲得了“大多數(shù)”成員的投票支持的,數(shù)據(jù)新的節(jié)點獲勝。
????????數(shù)據(jù)的新舊是通過操作日志 oplog 來對比的。
????????在獲得票數(shù)的時候,優(yōu)先級(priority)參數(shù)影響重大。
????????可以通過設置優(yōu)先級(priority)來設置額外票數(shù)。優(yōu)先級即權重,取值為 0-1000,相當于可額外增加 0-1000 的票數(shù),優(yōu)先級的值越大,就越可能獲得多數(shù)成員的投票(votes)數(shù)。指定較高的值可使成員更有資格成為主要成員,更低的值可使成員更不符合條件。
????????默認情況下,優(yōu)先級的值是 1
myrs:PRIMARY> rs.conf()
{"_id" : "myrs","version" : 3,"protocolVersion" : NumberLong(1),"writeConcernMajorityJournalDefault" : true,"members" : [{"_id" : 0,"host" : "192.168.229.154:27017","arbiterOnly" : false,"buildIndexes" : true,"hidden" : false,"priority" : 1,"tags" : {},"slaveDelay" : NumberLong(0),"votes" : 1},{"_id" : 1,"host" : "192.168.229.154:27018","arbiterOnly" : false,"buildIndexes" : true,"hidden" : false,"priority" : 1,"tags" : {},"slaveDelay" : NumberLong(0),"votes" : 1},{"_id" : 2,"host" : "192.168.229.154:27019","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("6528b761af0089c47768dd07")}
}
????????可以看出,主節(jié)點和副本節(jié)點的優(yōu)先級各為 1,即,默認可以認為都已經有了一票。但選舉節(jié)點,優(yōu)先級是 0,(要注意是,官方說了,選舉節(jié)點的優(yōu)先級必須是 0,不能是別的值。即不具備選舉權,但具有投票權)。
1.7 故障測試
1.7.1 副本節(jié)點故障測試
? ? ? ? 首先關閉 27018 副本節(jié)點。主節(jié)點和仲裁節(jié)點對 27018 的心跳失敗。但是因為主節(jié)點還在,因此,沒有觸發(fā)投票選舉。如果此時,在主節(jié)點寫入數(shù)據(jù)。
db.comment.insert({"_id":"1","articleid":"100001","content":"我們不應該把清晨浪費在手機上,健康很重要,一杯溫水幸福你我他。","userid":"1002","nickname":"相忘于江湖","createdatetime":new Date("2019-08-05T22:08:15.522Z"),"likenum":NumberInt(1000),"state":"1"})
? ? ? ? 再次啟動 27018 從節(jié)點,會發(fā)現(xiàn),主節(jié)點寫入的數(shù)據(jù),會自動同步給從節(jié)點。?
1.7.2 主節(jié)點故障測試
????????關閉 27017 節(jié)點,從節(jié)點和仲裁節(jié)點對 27017 的心跳失敗,當失敗超過 10 秒,此時因為沒有主節(jié)點了,會自動發(fā)起投票。
????????而副本節(jié)點只有 27018,因此,候選人只有一個就是 27018,開始投票。
????????27019 向 27018 投了一票,27018 本身自帶一票,因此共兩票,超過了 “大多數(shù)”
????????27019 是仲裁節(jié)點,沒有選舉權,27018 不向其投票,其票數(shù)是 0。
????????最終結果,27018 成為主節(jié)點。具備讀寫功能。在 27018 寫入數(shù)據(jù)查看。
db.comment.insert({"_id":"1","articleid":"100001","content":"我們不應該把清晨浪費在手機上,健康很重要,一杯溫水幸福你我他。","userid":"1002","nickname":"相忘于江湖","createdatetime":new Date("2019-08-05T22:08:15.522Z"),"likenum":NumberInt(1000),"state":"1"})
????????再啟動 27017 節(jié)點,發(fā)現(xiàn) 27017 變成了從節(jié)點,27018 仍保持主節(jié)點。
????????登錄 27017 節(jié)點,發(fā)現(xiàn)是從節(jié)點了,數(shù)據(jù)自動從 27018 同步。從而實現(xiàn)了高可用。
1.7.3 仲裁節(jié)點和主節(jié)點故障
????????先關掉仲裁節(jié)點 27019,關掉現(xiàn)在的主節(jié)點 27018。
????????登錄 27017 后,發(fā)現(xiàn),27017 仍然是從節(jié)點,副本集中沒有主節(jié)點了,導致此時,副本集是只讀狀態(tài),無法寫入。
????????為啥不選舉了?因為 27017 的票數(shù),沒有獲得大多數(shù),即沒有大于等于 2,它只有默認的一票(優(yōu)先級是1)如果要觸發(fā)選舉,隨便加入一個成員即可。
????????如果只加入 27019 仲裁節(jié)點成員,則主節(jié)點一定是 27017,因為沒得選了,仲裁節(jié)點不參與選舉,但參與投票。
????????如果只加入 27018 節(jié)點,會發(fā)起選舉。因為 27017 和 27018 都是兩票,則按照誰數(shù)據(jù)新,誰當主節(jié)點。
1.7.4 仲裁節(jié)點和從節(jié)點故障
????????先關掉仲裁節(jié)點 27019,關掉現(xiàn)在的副本節(jié)點 27018,
????????10 秒后,27017 主節(jié)點自動降級為副本節(jié)點。(服務降級)副本集不可寫數(shù)據(jù)了,已經故障了。
1.8 Compass 連接副本集
1.9 SpringDataMongoDB 連接副本集
????????副本集語法如下:
# slaveOk=true :開啟副本節(jié)點讀的功能,可實現(xiàn)讀寫分離
# connect=replicaSet:自動到副本集中選擇讀寫的主機,如果 slaveOk 是打開的,則實現(xiàn)了讀寫分離
mongodb://host1,host2,host3/數(shù)據(jù)庫名稱?connect=replicaSet&laveOk=true$replicaSet=副本集名字
????????修改我們自己的?application.yml 文件,如下所示:
spring:# 數(shù)據(jù)源配置data:mongodb:# 主機地址# host: 192.168.229.154# 數(shù)據(jù)庫# database: articledb# 默認端口是27017# port: 27017# 也可以使用uri連接uri: mongodb://192.168.229.154:27017,192.168.229.154:27018,192.168.229.154:27019/articledb?connect=replicaSet&slaveOk=true&replicaSet=myrs
注意:
????????SpringDataMongoDB 自動實現(xiàn)了讀寫分離。
????????寫操作時,只打開主節(jié)點連接;
????????讀操作時,同時打開主節(jié)點和從節(jié)點連接,但使用從節(jié)點獲取數(shù)據(jù)。