目錄html
單節點的 MongoDB
在數據的安全和冗餘方面是比較低的,在生產環境中,咱們爲 MongoDB
配置副本集,這樣能夠提升數據的高可用性和安全性。linux
副本集 :是一組 Mongod
維護相同數據集的實例。副本集能夠包含多個數據承載點和多個仲裁點。在承載數據的節點中,僅有一個節點被視爲主節點,其餘節點稱爲次節點。git
副本集的節點角色:github
主節點接收全部的數據寫入操做,主節點記錄數據的全部更改,即oplog
。mongodb
將一個額外的mongod
實例添加到副本集做爲 仲裁節點。仲裁節點不維護數據集。仲裁節點的目的是經過響應其餘副本集成員的心跳和選舉請求來維護副本集中的選舉。由於它們不存儲數據集,因此仲裁節點能夠是提供副本集仲裁功能的好方法,其資源成本比具備數據集的全功能副本集成員更低。若是您的副本集具備偶數個成員,請添加仲裁者以免腦裂出現。shell
在主節點未與配置中的其它成員通訊超過 10s(默認爲10s)的話,則符合條件的次節點將推選本身爲主節點。數據庫
在選舉成功完成以前,副本集沒法處理寫入操做。api
electionTimeoutMillis
默認值爲10000(10s) ,咱們能夠根據本身的項目狀況來升高或者下降該值,咱們在更改該值的時候須要考慮到網絡延遲等因素。安全
默認狀況下,副本集在選取新的主節點的等待時間不超過12秒(主要用於將原有主節點標記爲不可用,並選舉出新的主節點),bash
爲了保持次節點與主節點的數據同步,MongoDB 使用兩種方式進行數據的同步:
初始同步, 用於同步主節點的全部數據
初始同步將全部的數據從副本集的一個成員複製到另一個成員
增量同步,在初始同步後不斷複製新的數據
在初始同步後不斷複製數據,次節點從主節點中同步複製 Oplog,並在異步過程當中應用這些操做
副本集在部署前須要肯定成員數據,副本集最多能有50個節點,可是隻能有7個節點擁有被選舉權,副本集須要具備奇數個投票成員,若是有偶數個的話,能夠添加一個 仲裁者,來保證有奇數個成員,避免腦裂狀況發生,
儘可能使用 主機名 來尋找對應的節點,而不是使用 ip 地址,避免 ip 改變致使配置須要更改。
部署須要更改 /etc/hosts 文件,將主機名和 ip 地址對應好,不該該使用ip。
使用統一的端口。
建立數據儲存的位置和配置文件的位置。
肯定好副本集的名稱
搭建架構選擇
三節點,一個主節點,一個次節點,一個仲裁節點
基本環境: 系統 CentOS 7 MongoDB 版本 4.0.8 3個節點 fymongodb001 內網IP:172.18.186.161 公網ip: 47.112.129.2 # 主節點 fymongodb002 內網IP: 172.18.186.162 公網ip: 47.112.131.231 # 次節點 fymongodb003 內網IP: 172.18.186.163 公網ip: 47.112.98.64 # 仲裁節點 副本集名稱: fymongodb
三個節點都須要執行
# 下載mongodb cat <<EOF >>/etc/hosts 172.18.186.161 fymongodb001 172.18.186.162 fymongodb002 172.18.186.163 fymongodb003 EOF cd /tmp && wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-4.0.8.tgz tar -zxf mongodb-linux-x86_64-4.0.8.tgz mv mongodb-linux-x86_64-4.0.8 /opt/mongodb mkdir /opt/mongodb/{data,logs} useradd mongodb # 咱們這裏使用的配置文件 是YAML 格式的 wget https://raw.githubusercontent.com/tobewithyou1996/LinuxGuide/master/MongoDB/mongodb_rep.yaml -P /opt/mongodb/ chown -R mongodb:mongodb /opt/mongodb/ cat <<EOF >>/usr/lib/systemd/system/mongodb.service [Unit] Description= mongodb service manager [Service] # Other directives omitted # (file size) LimitFSIZE=infinity # (cpu time) LimitCPU=infinity # (virtual memory size) LimitAS=infinity # (locked-in-memory size) LimitMEMLOCK=infinity # (open files) LimitNOFILE=64000 # (processes/threads) LimitNPROC=64000 Type=forking User=mongodb Group=mongodb PIDFile=/opt/mongodb/logs/mongod.pid ExecStart= /opt/mongodb/bin/mongod -f /opt/mongodb/mongodb_rep.yaml ExecStop= /opt/mongodb/bin/mongod --shutdown --dbpath /opt/mongodb/data Restart=always [Install] WantedBy=multi-user.target EOF # 添加環境變量 echo "export PATH=$PATH:/opt/mongodb/bin" >>/etc/profile source /etc/profile # 啓動 systemctl start mongodb
主節點操做
# 主節點操做 [root@fymongodb001 tmp]# mongo MongoDB shell version v4.0.8 connecting to: mongodb://127.0.0.1:27017/?gssapiServiceName=mongodb Implicit session: session { "id" : UUID("77f60167-1d37-4796-bf2a-60cfdc4b0526") } MongoDB server version: 4.0.8 > use admin # 切換到 admin 數據庫 switched to db admin # 初始化副本集,副本集名稱爲 fymongodb ,第一個成員爲本身自己。 > rs.initiate({_id:'fymongodb',members: [{ _id: 0 , host: "fymongodb001:27017"}]}) { "ok" : 1 } fymongodb:SECONDARY> # 接着回車,直到顯示這個節點爲Primary主節點 fymongodb:PRIMARY> # 接着添加 次節點 fymongodb002 # 添加次節點 fymongodb:PRIMARY> rs.add('fymongodb002:27017') { "ok" : 1, "operationTime" : Timestamp(1555663440, 1), "$clusterTime" : { "clusterTime" : Timestamp(1555663440, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } } # 添加仲裁節點 fymongodb:PRIMARY> rs.addArb("fymongodb003:27017") { "ok" : 1, "operationTime" : Timestamp(1555663631, 1), "$clusterTime" : { "clusterTime" : Timestamp(1555663631, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } } # 查看當前配置 fymongodb:PRIMARY> rs.conf() { "_id" : "fymongodb", "version" : 3, "protocolVersion" : NumberLong(1), "writeConcernMajorityJournalDefault" : true, "members" : [ { "_id" : 0, "host" : "fymongodb001:27017", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 1, "tags" : { }, "slaveDelay" : NumberLong(0), "votes" : 1 }, { "_id" : 1, "host" : "fymongodb002:27017", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 1, "tags" : { }, "slaveDelay" : NumberLong(0), "votes" : 1 }, { "_id" : 2, "host" : "fymongodb003: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("5cb98534cd9d16ff3f4fffdc") } } # rs.status() 查看各個節點的身份
當咱們完成上面的操做的時,咱們主節點更改的數據已是會自動同步到次節點的。
次節點操做
fymongodb002
次節點(Secondary)設置容許讀寫操做。
[root@fymongodb002 ~]# mongo MongoDB shell version v4.0.8 connecting to: mongodb://127.0.0.1:27017/?gssapiServiceName=mongodb Implicit session: session { "id" : UUID("f353edd5-d79a-4947-9844-7f9bde98a949") } MongoDB server version: 4.0.8 fymongodb:SECONDARY> fymongodb:SECONDARY> show dbs; # 咱們發現沒法讀寫 2019-04-19T17:04:40.852+0800 E QUERY [js] Error: listDatabases failed:{ "operationTime" : Timestamp(1555664675, 1), "ok" : 0, "errmsg" : "not master and slaveOk=false", "code" : 13435, "codeName" : "NotMasterNoSlaveOk", "$clusterTime" : { "clusterTime" : Timestamp(1555664675, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } } : fymongodb:SECONDARY> rs.slaveOk() # 容許 次節點 進行讀取 fymongodb:SECONDARY> show dbs; # 咱們就能夠查看到次節點的數據了。 admin 0.000GB config 0.000GB djx 0.000GB local 0.000GB fymongodb:SECONDARY> use djx; switched to db djx fymongodb:SECONDARY> show collections; # 從主節點同步過來的數據。 djx lsp
測試數據的同步,咱們在主節點建立一個集合test
並添加一條數據 'age':38
,咱們能夠看到次節點也同步了該數據。
測試一
模擬主節點 fymongodb001
宕機了,而後查看次節點 fymongodb002
是否會被選舉成爲主節點。
咱們能夠看到 fymongodb002
選舉爲主節點.
測試二
當 fymongodb002
選舉爲主節點後,fymongodb001
恢復了,fymongodb001
會做爲次節點加入。
測試三
測試在次節點(Secondary)進行數據刪除。是刪除不了的。
fymongodb:SECONDARY> db.test.drop() 2019-04-19T21:48:38.140+0800 E QUERY [js] Error: drop failed: { "operationTime" : Timestamp(1555681711, 1), "ok" : 0, "errmsg" : "not master", "code" : 10107, "codeName" : "NotMaster", "$clusterTime" : { "clusterTime" : Timestamp(1555681711, 1), "signature" : { "hash" : BinData(0,"I+dFkOHcdqW+La7xvy8JFij+5CY="), "keyId" : NumberLong("6681517989155569665") } } } : _getErrorWithCode@src/mongo/shell/utils.js:25:13 DBCollection.prototype.drop@src/mongo/shell/collection.js:707:1 @(shell):1:1
副本集配置用戶和密碼,登陸主節點,添加admin
用戶。
> use admin switched to db admin > db.createUser({ user: "admin", pwd: "9toc7tpji8", roles: [{ role: "root", db: "admin" }] }) Successfully added user: { "user" : "admin", "roles" : [ { "role" : "root", "db" : "admin" } ] }
在主節點生成 keyflie
並複製到其它兩個節點
# 生成 keyFile openssl rand -base64 90 -out /opt/mongodb/keyfile #並複製到其它兩個節點 scp /opt/mongodb/keyfile fymongodb002:/opt/mongodb/ scp /opt/mongodb/keyfile fymongodb003:/opt/mongodb/
更改三個節點的 keyFile
文件權限和全部者
chmod 600 /opt/mongodb/keyfile # 必定要更改爲 600 權限,否正會報錯 chown mongodb:mongodb /opt/mongodb/keyfile # 更改文件全部者
更改三個節點的 mongodb_rep.yaml
配置文件,將 security
的參數 authorization
設置爲 enabled
,並配置
keyFile
的路徑。
security: authorization: "enabled" keyFile: '/opt/mongodb/keyfile' clusterAuthMode: "keyFile"
而後依次重啓 fymongodb001
、 fymongodb002
、 fymongodb003
。
# fymongodb001 systemctl restart mongodb # fymongodb002 systemctl restart mongodb # fymongodb003 systemctl restart mongodb
登錄 fymongodb001
,咱們使用 db.auth()
進行登錄驗證。
fymongodb:PRIMARY> show dbs; fymongodb:PRIMARY> use admin switched to db admin fymongodb:PRIMARY> db.auth('admin','9toc7tpji8') 1 fymongodb:PRIMARY> show dbs; admin 0.000GB config 0.000GB local 0.000GB
副本集當作單節點啓動須要更改配置文件,主要的配置文件有如下幾點:
replSet=fymongodb
而後咱們執行維護完後,關閉節點
use admin db.shutdownServer()
而後還原原來的配置,而後做爲副本集成員加入副本集。
若是咱們想讓某個節點成爲主節點,或者是當主節點 down 了後,你想指定某個節點 優先級更高地成爲 次節點。
cfg = rs.conf() cfg.members[0].priority = 0.5 cfg.members[1].priority = 0.5 cfg.members[2].priority = 1 rs.reconfig(cfg)
# 使用備份數據進行啓動 mongod --dbpath /data/db # 刪除 local 數據庫 use local db.dropDatabase() # 指定副本集名稱並以備份數據 啓動 mongod --dbpath /data/db --replSet <replName> # 啓動副本集 rs.initiate( { _id : <replName>, members: [ { _id : 0, host : <host:port> } ] })
當副本集的數據量比較大的時候,咱們添加新的節點的時候,若是使用初始化同步的話,會給主節點形成比較大的壓力。咱們有如下選擇:
暫停當前副本集中的一個次節點,而後將 次節點的數據(data)複製到要新添加的節點的數據目錄。而後再將兩個節點啓動。(建議先測試)
若是要複製數據文件,請確保您的副本包含
local
數據庫的內容。
指定同步節點 rs.syncFrom(hostportstr)
,指定同步節點爲次節點,默認的是同步節點 是主節點。
可是該設置在從新啓動節點,或者同步指定的新節點的鏈接被關閉了,是會失效的。(建議先測試)
若是咱們決定仍是從主節點進行同步數據。
延遲節點在此未記錄,詳細見官方文檔。
# 副本集初始化 rs.initiate( { _id : "rs0", members: [ { _id: 0, host: "mongodb0.example.net:27017" }, { _id: 1, host: "mongodb1.example.net:27017" }, { _id: 2, host: "mongodb2.example.net:27017" } ] }) # 副本集添加成員 rs.add('mongodb3.example.net:27017') # 副本集添加仲裁節點 rs.addArb('mongodb4.example.net:27017') # 移除節點 rs.remove('hostportstr') # 查看當前的配置 rs.conf() # 查看各個節點狀態和身份 rs.status() # 設定某個節點多少秒不可成爲主節點 rs.freeze(secs) # 設置次節點從指定節點同步數據 rs.syncFrom(hostportstr) # 下降主節點爲次節點,只能在主節點上運行 rs.stepDown([stepdownSecs, catchUpSecs]) # 查看幫助 rs.help() # 次節點執行,表示容許次節點讀取數據 rs.slaveOk() # 判斷當前節點是不是主節點 rs.isMaster() # 查看 Oplog 信息 rs.printReplicationInfo() # 查看副本集的次節點與主節點延遲 db.printSlaveReplicationInfo() # 移除原有副本集命令 use local db.system.replset.remove({}) # 關閉 mongodb進程服務 use admin db.shutdownServer()
建議將副本集至少部署在3個可用區。
配置副本集成員,使用的是主機名而不是 ip,由於 ip 可能變更。
副本集包含奇數個投票成員。
報錯內容:
Failed global initialization: BadValue: replication.replSetName is not allowed when storage.indexBuildRetry is specified
storage
參數 indexBuildRetry
不能與 副本集共存,當開啓 副本集的時候,就須要將indexBuildRetry
參數註釋。官網連接
Changed in version 4.0: The setting
storage.indexBuildRetry
cannot be used in conjunction withreplication.replSetName
.