複製:兩種架構
1、一個master(讀寫),多個slave(讀),但是mongodb這種架構無法實現故障自動轉移
2、副本集:
複製集、副本集:Replica set,至少三個節點,通過選舉選出1個主節點和2個備節點。主節點負責讀寫,備節點監控主節點並從主節點上獲得其心跳信息。萬一主節點掛了,則剩下的節點通過選舉選出新的主節點,備節點則自動將其主節點指向新的主節點。能實現自動故障轉移。在實現複製時,必須指明處於哪個副本集,所有節點都要明確工作於某個副本之上,只在此副本實現主從架構。如果還有其他節點,但其他節點所處的集羣名稱不一樣的話,就處於不同的複製架構中。集羣名稱通過副本集名稱定義的。主節點將所有的寫操作寫在一個日誌文件(oplog)中,從節點複製寫操作並在本地執行一遍。這個複製是異步的。
還有一種情況:
三個節點中有一個節點不存任何數據,只有選舉權,而沒有被選舉權。這樣會導致假如一個節點掛了後,剩下的一個節點沒有從節點,這樣那個活動節點要降級爲只讀模式,因爲它無法保證數據有副本存放的。
副本集參數:
replset:副本集名稱
oplogsize:日誌大小
fastsync:快速同步
replindexprefetch:在實現複製時,根據索引實現數據預取。這種特性可以實現快速裝載主節點上的數據,尤其在修改量比較大的集羣上,非常有意義,在2.2.2版本實現
實驗:
條件:
所有節點時間同步
配置文件中的集羣名稱一致
三個節點都安裝mongodb
三個節點的/etc/hosts文件設置如下:
三個節點都創建數據目錄、更改屬主屬組、修改配置文件請看上文
配置文件最後加上:
rest = true 顯示按鈕的相關信息
複製配置文件到另外兩個節點:
啓動服務:(三個節點都啓動)
連接到任意節點執行副本集初始化命令即可。(rs命令)
rs.status:顯示rs狀態
rs.initiate:初始化,第一次實現創建副本集要用這個命令初始化
rs.initiate(cfg):通過配置文件來初始化,配置文件由下面的命令獲得
rs.conf:獲取配置文件
rs.reconfig(cfg):重新初始化
rs.add(hostportstr):添加從節點的端口號
rs.add(membercfgobj):添加從節點
初始化:
查看狀態:
查看是否爲主節點:
添加從節點並查看信息:
testrs0:PRIMARY> rs.add("192.168.0.22:27017") { "ok" : 1 } testrs0:PRIMARY> rs.status() { "set" : "testrs0", "date" : ISODate("2016-11-29T14:25:50Z"), "myState" : 1, "members" : [ { "_id" : 0, "name" : "node1:27017", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 557, "optime" : Timestamp(1480429519, 1), "optimeDate" : ISODate("2016-11-29T14:25:19Z"), "self" : true }, { "_id" : 1, "name" : "192.168.0.22:27017", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 31, "optime" : Timestamp(1480429519, 1), "optimeDate" : ISODate("2016-11-29T14:25:19Z"), "lastHeartbeat" : ISODate("2016-11-29T14:25:49Z"), "lastHeartbeatRecv" : ISODate("2016-11-29T14:25:50Z"), "pingMs" : 0, "syncingTo" : "node1:27017" } ], "ok" : 1 }
添加第二個節點並查看狀態:(不知爲何會不一樣)
testrs0:PRIMARY> rs.add("192.168.0.23:27017") { "down" : [ "192.168.0.23:27017" ], "ok" : 1 } testrs0:PRIMARY> rs.status() { "set" : "testrs0", "date" : ISODate("2016-11-29T14:28:05Z"), "myState" : 1, "members" : [ { "_id" : 0, "name" : "node1:27017", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 692, "optime" : Timestamp(1480429663, 1), "optimeDate" : ISODate("2016-11-29T14:27:43Z"), "self" : true }, { "_id" : 1, "name" : "192.168.0.22:27017", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 166, "optime" : Timestamp(1480429663, 1), "optimeDate" : ISODate("2016-11-29T14:27:43Z"), "lastHeartbeat" : ISODate("2016-11-29T14:28:04Z"), "lastHeartbeatRecv" : ISODate("2016-11-29T14:28:04Z"), "pingMs" : 0, "syncingTo" : "node1:27017" }, { "_id" : 2, "name" : "192.168.0.23:27017", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 22, "optime" : Timestamp(1480429663, 1), "optimeDate" : ISODate("2016-11-29T14:27:43Z"), "lastHeartbeat" : ISODate("2016-11-29T14:28:03Z"), "lastHeartbeatRecv" : ISODate("2016-11-29T14:28:04Z"), "pingMs" : 2, "syncingTo" : "node1:27017" } ], "ok" : 1 }
查看master:
在主節點創建數據,看從能否獲取到
主節點:
testrs0:PRIMARY> use testdb switched to db testdb testrs0:PRIMARY> db.testcoll.insert({Name:'test',Age:50,Gender:'F'}) testrs0:PRIMARY> db.testcoll.find({Name:'test'}) { "_id" : ObjectId("583d92d63b539fcc9aef4fd4"), "Name" : "test", "Age" : 50, "Gender" : "F"
從節點:
從節點不能直接查詢的,必須使用rs.slaveOk()把自己提升爲可以接受查詢的從節點
testrs0:SECONDARY> rs.slaveOk() testrs0:SECONDARY> use testdb switched to db testdb testrs0:SECONDARY> db.testcoll.find({Name:'test'}) { "_id" : ObjectId("583d92d63b539fcc9aef4fd4"), "Name" : "test", "Age" : 50, "Gender" : "F" }
讓主節點掛點,看是否有一個會提升爲主的:
停止主節點的服務即可:
[root@node1 ~]# service mongod stop Stopping mongod: [ OK ]
在剛纔的備節點查看狀態:
testrs0:SECONDARY> rs.status() { "set" : "testrs0", "date" : ISODate("2016-11-29T14:45:20Z"), "myState" : 1, "members" : [ { "_id" : 0, "name" : "node1:27017", "health" : 0, "state" : 8, "stateStr" : "(not reachable/healthy)", "uptime" : 0, "optime" : Timestamp(1480430294, 1), "optimeDate" : ISODate("2016-11-29T14:38:14Z"), "lastHeartbeat" : ISODate("2016-11-29T14:45:19Z"), "lastHeartbeatRecv" : ISODate("2016-11-29T14:44:00Z"), "pingMs" : 0 }, { "_id" : 1, "name" : "192.168.0.22:27017", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 1210, "optime" : Timestamp(1480430294, 1), "optimeDate" : ISODate("2016-11-29T14:38:14Z"), "self" : true }, { "_id" : 2, "name" : "192.168.0.23:27017", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 1056, "optime" : Timestamp(1480430294, 1), "optimeDate" : ISODate("2016-11-29T14:38:14Z"), "lastHeartbeat" : ISODate("2016-11-29T14:45:19Z"), "lastHeartbeatRecv" : ISODate("2016-11-29T14:45:19Z"), "pingMs" : 1, "lastHeartbeatMessage" : "syncing to: 192.168.0.22:27017", "syncingTo" : "192.168.0.22:27017" } ], "ok" : 1 } testrs0:PRIMARY> #這裏已經改爲主的了
在新的主節點添加數據:
然後在從節點查看:
讓之前的主節點從新上線:
testrs0:PRIMARY> rs.status() { "set" : "testrs0", "date" : ISODate("2016-11-29T14:50:31Z"), "myState" : 1, "members" : [ { "_id" : 0, "name" : "node1:27017", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", #其狀態不再是主的了 "uptime" : 45, "optime" : Timestamp(1480430874, 1), "optimeDate" : ISODate("2016-11-29T14:47:54Z"), "lastHeartbeat" : ISODate("2016-11-29T14:50:30Z"), "lastHeartbeatRecv" : ISODate("2016-11-29T14:50:29Z"), "pingMs" : 1, "lastHeartbeatMessage" : "syncing to: 192.168.0.22:27017", "syncingTo" : "192.168.0.22:27017" }, { "_id" : 1, "name" : "192.168.0.22:27017", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 1521, "optime" : Timestamp(1480430874, 1), "optimeDate" : ISODate("2016-11-29T14:47:54Z"), "self" : true }, { "_id" : 2, "name" : "192.168.0.23:27017", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 1367, "optime" : Timestamp(1480430874, 1), "optimeDate" : ISODate("2016-11-29T14:47:54Z"), "lastHeartbeat" : ISODate("2016-11-29T14:50:29Z"), "lastHeartbeatRecv" : ISODate("2016-11-29T14:50:29Z"), "pingMs" : 1, "syncingTo" : "192.168.0.22:27017" } ], "ok" : 1 }
打印複製信息:
配置優先級:
rs.conf()顯示現有的配置
testrs0:SECONDARY> rs.conf() { "_id" : "testrs0", "version" : 3, "members" : [ { "_id" : 0, "host" : "node1:27017" }, { "_id" : 1, "host" : "192.168.0.22:27017" }, { "_id" : 2, "host" : "192.168.0.23:27017" } ] }
編輯配置文件:
方式1:rs.conf({id:xxx}),這種方式比較麻煩
方式2:把內容保存到文件中,重新應用就可以了
cfg=rs.conf()保存文件
cfg.members[0].priority=2設置優先級
rs.reconfig(cfg)重新應用
只能在主節點進行配置:
40-45從看
三個節點理由有一個可以不被選舉,只參與選舉,無法觸發選舉,但可以參與選舉。這種節點的優先級爲0
觸發重新選舉:
一個幾點只能以從節點的身份去上線,然後主節點主持重新選舉。
優先級爲0的節點:無權觸發,僅參與選舉
添加優先級爲0的節點:rs.addArb(hostportstr)
移除節點:rs.remove(hostportstr)
Sharding:把一個很大的表的數據切割後放到不同的節點,各節點只存放一部分。每個服務器成爲一個sharding節點。把每個collection分割爲多片,平均分配到各節點。均勻分配。
用途:
複製集很大、吞吐量大
高併發查詢可能耗盡cpu的處理能力
海量數據集超出某一個節點的存儲能力
降低單臺服務器的io壓力
sharding架構:
config servers:存儲元數據
shard:存儲數據
讀操作:請求過來了,app server先去查找元數據,再查找shard。性能不好,因爲各索引在shard節點中
寫操作:shard特長
shard必須和業務數據相關聯。
生產環境中應該至少有三個config server節點,這些服務器壓力很小,所以可以放到運行其他應用的節點
mongos:端口28017,用來接收用戶請求,合併數據,扮演前段的代理服務器。router之間不會通信。mongos1個也可以,mongos也可以直接安裝到應用服務器中
shard:至少有2個
實驗:1個mongos,1個config server,2個shard
1、配置config server
2、配置mongos
3、配置shard
配置config server:192.168.0.22
保存退出,重啓服務
端口:
配置mongos:
啓動shard:
只需改下數據目錄,重啓服務即可
下圖中的A爲主shard:
連接mongos:
查看shard狀態:
添加shard:在192.168.0.22上添加
使用分區功能:sh.enableSharding(dbname)
collection支持分區功能:sh.shardCollection(fullName,key,unique)
添加數據:
在mongos上查看分片:192.168.0.21
完成重新均衡:
sh.addShard(host)添加新的shade
sh.setBalancerState均衡
查看是否均衡:
補充:
php訪問mongodb,需要編譯相應的驅動。
aubiter:僅參與選舉,不持有任何數據
0優先級的節點:持有數據,參與選舉,但不能成爲主節點
shard:
讀:不離散
寫:離散
選擇sharding key的標準:
應該在哪裏存儲數據
應該從哪裏得到希望的數據
基本法則:
sharding key應該是主鍵
sharding key應該能儘量保證避免跨分片查詢
自學:
1、新增shard
2、移除shard
命令:
mongodump:備份
mongorestore:恢復
mongoexport:導出
mongoimport:導入
mongostat:監控
mongotop:
mongooplog:
mongoperf:性能評估
mongofiles:查看和修改GridFS文件系統