Mongodb主從複製/ 副本集/分片集羣介紹

前面的文章介紹了Mongodb的安裝使用,在 MongoDB 中,有兩種數據冗餘方式,一種 是 Master-Slave 模式(主從複製),一種是 Replica Sets 模式(副本集)。html

Mongodb一共有三種集羣搭建的方式:
Replica Set(副本集)、
Sharding(切片)
Master-Slaver(主從)【目前已不推薦使用了!!!】

其中,Sharding集羣也是三種集羣中最複雜的。
副本集比起主從能夠實現故障轉移!!很是使用!

mongoDB目前已不推薦使用主從模式,取而代之的是副本集模式。副本集其實一種互爲主從的關係,可理解爲主主。
副本集指將數據複製,多份保存,不一樣服務器保存同一份數據,在出現故障時自動切換。對應的是數據冗餘、備份、鏡像、讀寫分離、高可用性等關鍵詞;
而分片則指爲處理大量數據,將數據分開存儲,不一樣服務器保存不一樣的數據,它們的數據總和即爲整個數據集。追求的是高性能。

在生產環境中,一般是這兩種技術結合使用,分片+副本集。

1、先說說mongodb主從複製配置前端

主從複製是MongoDB最經常使用的複製方式,也是一個簡單的數據庫同步備份的集羣技術,這種方式很靈活.可用於備份,故障恢復,讀擴展等. 
最基本的設置方式就是創建一個主節點和一個或多個從節點,每一個從節點要知道主節點的地址。採用雙機備份後主節點掛掉了後從節點能夠接替主機繼續服務。因此這種模式比單節點的高可用性要好不少。java

 配置主從複製的注意點node

1)在數據庫集羣中要明確的知道誰是主服務器,主服務器只有一臺.
2)從服務器要知道本身的數據源也就是對應的主服務是誰.
3)--master用來肯定主服務器,--slave 和 --source 來控制從服務器

能夠在mongodb.conf配置文件裏指明主從關係,這樣啓動mongodb的時候只要跟上配置文件就行,就不須要經過--master和--slave來指明主從了。mysql

下面簡單記錄下Mongodb主從複製的部署過程linux

1)機器環境
182.48.115.238    master-node
182.48.115.236    slave-node

兩臺機器都關閉防火牆和selinux
mongodb的安裝參考:http://www.cnblogs.com/kevingrace/p/5752382.html

2)主從配置
.............master-node節點配置.............
[root@master-node ~]# vim /usr/local/mongodb/mongodb.conf
port=27017
bind_ip = 182.48.115.238
dbpath=/usr/local/mongodb/data
logpath=/usr/local/mongodb/log/mongo.log
logappend=true
journal = true
fork = true
master = true        //肯定本身是主服務器

[root@master-node ~]# nohup /usr/local/mongodb/bin/mongod --config /usr/local/mongodb/mongodb.conf &

[root@master-node ~]# ps -ef|grep mongodb
root     15707 15514 23 16:45 pts/2    00:00:00 /usr/local/mongodb/bin/mongod --config /usr/local/mongodb/mongodb.conf
root     15736 15514  0 16:45 pts/2    00:00:00 grep mongodb
[root@master-node ~]# lsof -i:27017
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
mongod  15707 root    7u  IPv4 153114      0t0  TCP 182.48.115.238:27017 (LISTEN)

因爲mongodb.conf裏綁定了本機的ip地址182.48.115.238,因此鏈接mongodb的時候必須用這個ip地址,不能使用默認的127.0.0.1,也就是說:
[root@master-node ~]# mongo 182.48.115.238:27017     //這樣才能鏈接mongodb
[root@master-node ~]# mongo 或者 mongodb 127.0.0.1:27017    // 這樣不能鏈接mongodb

.............slave-node節點配置.............
[root@slave-node ~]# vim /usr/local/mongodb/mongodb.conf 
port=27017
dbpath=/usr/local/mongodb/data
logpath=/usr/local/mongodb/log/mongo.log
logappend=true
journal = true
fork = true
bind_ip = 182.48.115.236            //肯定主數據庫端口
source = 182.48.115.238:27017      //肯定主數據庫端口
slave = true               //肯定本身是從服務器

[root@slave-node ~]# nohup /usr/local/mongodb/bin/mongod --config /usr/local/mongodb/mongodb.conf &

[root@slave-node ~]# ps -ef|grep mongo
root     26290 26126  8 16:47 pts/0    00:00:00 /usr/local/mongodb/bin/mongod --config /usr/local/mongodb/mongodb.conf
root     26316 26126  0 16:47 pts/0    00:00:00 grep mongo
[root@slave-node ~]# lsof -i:27017
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
mongod  26290 root    7u  IPv4 663904      0t0  TCP slave-node1:27017 (LISTEN)
mongod  26290 root   25u  IPv4 663917      0t0  TCP slave-node1:51060->slave-node2:27017 (ESTABLISHED)

在slave-node測試鏈接master-node的mongodb數據庫是否正常
[root@slave-node ~]# mongo 182.48.115.236:27017
MongoDB shell version v3.4.4
connecting to: 182.48.115.236:27017
MongoDB server version: 3.4.4
Server has startup warnings: 
2017-06-03T16:47:31.200+0800 I STORAGE  [initandlisten] 
2017-06-03T16:47:31.200+0800 I STORAGE  [initandlisten] ** WARNING: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine
2017-06-03T16:47:31.200+0800 I STORAGE  [initandlisten] **          See http://dochub.mongodb.org/core/prodnotes-filesystem
2017-06-03T16:47:32.472+0800 I CONTROL  [initandlisten] 
2017-06-03T16:47:32.472+0800 I CONTROL  [initandlisten] ** WARNING: Access control is not enabled for the database.
2017-06-03T16:47:32.472+0800 I CONTROL  [initandlisten] **          Read and write access to data and configuration is unrestricted.
2017-06-03T16:47:32.472+0800 I CONTROL  [initandlisten] ** WARNING: You are running this process as the root user, which is not recommended.
2017-06-03T16:47:32.472+0800 I CONTROL  [initandlisten] 
2017-06-03T16:47:32.473+0800 I CONTROL  [initandlisten] 
2017-06-03T16:47:32.473+0800 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
2017-06-03T16:47:32.473+0800 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2017-06-03T16:47:32.473+0800 I CONTROL  [initandlisten] 
2017-06-03T16:47:32.473+0800 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
2017-06-03T16:47:32.473+0800 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2017-06-03T16:47:32.473+0800 I CONTROL  [initandlisten] 
>

3)主從數據同步測試
在master-node節點數據庫裏建立master_slave庫,並插入20條數據
[root@master-node ~]# mongo 182.48.115.238:27017
MongoDB shell version v3.4.4
connecting to: 182.48.115.238:27017
MongoDB server version: 3.4.4
Server has startup warnings: 
2017-06-03T16:45:07.406+0800 I STORAGE  [initandlisten] 
2017-06-03T16:45:07.407+0800 I STORAGE  [initandlisten] ** WARNING: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine
2017-06-03T16:45:07.407+0800 I STORAGE  [initandlisten] **          See http://dochub.mongodb.org/core/prodnotes-filesystem
2017-06-03T16:45:08.373+0800 I CONTROL  [initandlisten] 
2017-06-03T16:45:08.373+0800 I CONTROL  [initandlisten] ** WARNING: Access control is not enabled for the database.
2017-06-03T16:45:08.373+0800 I CONTROL  [initandlisten] **          Read and write access to data and configuration is unrestricted.
2017-06-03T16:45:08.373+0800 I CONTROL  [initandlisten] ** WARNING: You are running this process as the root user, which is not recommended.
2017-06-03T16:45:08.373+0800 I CONTROL  [initandlisten] 
2017-06-03T16:45:08.374+0800 I CONTROL  [initandlisten] 
2017-06-03T16:45:08.374+0800 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
2017-06-03T16:45:08.374+0800 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2017-06-03T16:45:08.374+0800 I CONTROL  [initandlisten] 
2017-06-03T16:45:08.374+0800 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
2017-06-03T16:45:08.374+0800 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2017-06-03T16:45:08.374+0800 I CONTROL  [initandlisten] 
> use master_slave
switched to db master_slave
> function add(){var i = 0;for(;i<20;i++){db.persons.insert({"name":"wang"+i})}}
> add()
> db.persons.find()
{ "_id" : ObjectId("593278699a9e2e9f37ac4dbb"), "name" : "wang0" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dbc"), "name" : "wang1" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dbd"), "name" : "wang2" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dbe"), "name" : "wang3" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dbf"), "name" : "wang4" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dc0"), "name" : "wang5" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dc1"), "name" : "wang6" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dc2"), "name" : "wang7" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dc3"), "name" : "wang8" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dc4"), "name" : "wang9" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dc5"), "name" : "wang10" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dc6"), "name" : "wang11" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dc7"), "name" : "wang12" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dc8"), "name" : "wang13" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dc9"), "name" : "wang14" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dca"), "name" : "wang15" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dcb"), "name" : "wang16" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dcc"), "name" : "wang17" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dcd"), "name" : "wang18" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dce"), "name" : "wang19" }
Type "it" for more

而後在slave-node節點數據庫裏查看,是否將master-node寫入的新數據同步過來了
[root@slave-node log]# mongo 182.48.115.236:27017
MongoDB shell version v3.4.4
connecting to: 182.48.115.236:27017
MongoDB server version: 3.4.4
Server has startup warnings: 
2017-06-03T16:56:28.928+0800 I STORAGE  [initandlisten] 
2017-06-03T16:56:28.928+0800 I STORAGE  [initandlisten] ** WARNING: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine
2017-06-03T16:56:28.928+0800 I STORAGE  [initandlisten] **          See http://dochub.mongodb.org/core/prodnotes-filesystem
2017-06-03T16:56:29.883+0800 I CONTROL  [initandlisten] 
2017-06-03T16:56:29.883+0800 I CONTROL  [initandlisten] ** WARNING: Access control is not enabled for the database.
2017-06-03T16:56:29.883+0800 I CONTROL  [initandlisten] **          Read and write access to data and configuration is unrestricted.
2017-06-03T16:56:29.883+0800 I CONTROL  [initandlisten] ** WARNING: You are running this process as the root user, which is not recommended.
2017-06-03T16:56:29.883+0800 I CONTROL  [initandlisten] 
2017-06-03T16:56:29.884+0800 I CONTROL  [initandlisten] 
2017-06-03T16:56:29.884+0800 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
2017-06-03T16:56:29.884+0800 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2017-06-03T16:56:29.884+0800 I CONTROL  [initandlisten] 
2017-06-03T16:56:29.884+0800 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
2017-06-03T16:56:29.884+0800 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2017-06-03T16:56:29.884+0800 I CONTROL  [initandlisten] 
> show dbs
2017-06-03T17:10:32.136+0800 E QUERY    [thread1] Error: listDatabases failed:{
    "ok" : 0,
    "errmsg" : "not master and slaveOk=false",
    "code" : 13435,
    "codeName" : "NotMasterNoSlaveOk"
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:62:1
shellHelper.show@src/mongo/shell/utils.js:769:19
shellHelper@src/mongo/shell/utils.js:659:15
@(shellhelp2):1:1
> rs.slaveOk();
> show dbs
admin         0.000GB
local         0.000GB
master_slave  0.000GB
wangshibo     0.000GB
> use master_slave
switched to db master_slave
> db.persons.find()
{ "_id" : ObjectId("593278699a9e2e9f37ac4dbb"), "name" : "wang0" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dbc"), "name" : "wang1" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dbd"), "name" : "wang2" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dbe"), "name" : "wang3" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dbf"), "name" : "wang4" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dc0"), "name" : "wang5" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dc1"), "name" : "wang6" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dc2"), "name" : "wang7" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dc3"), "name" : "wang8" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dc4"), "name" : "wang9" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dc5"), "name" : "wang10" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dc6"), "name" : "wang11" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dc7"), "name" : "wang12" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dc8"), "name" : "wang13" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dc9"), "name" : "wang14" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dca"), "name" : "wang15" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dcb"), "name" : "wang16" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dcc"), "name" : "wang17" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dcd"), "name" : "wang18" }
{ "_id" : ObjectId("593278699a9e2e9f37ac4dce"), "name" : "wang19" }
Type "it" for more
........................................................................................
若是在slave-node節點上的數據庫中查看,有報錯:"errmsg" : "not master and slaveOk=false"!!!
首先這是正常的,由於SECONDARY是不容許讀寫的, 在寫多讀少的應用中,使用Replica Sets來實現讀寫分離。
經過在鏈接時指定或者在主庫指定slaveOk,由Secondary來分擔讀的壓力,Primary只承擔寫操做。
對於replica set 中的secondary 節點默認是不可讀的。

解決辦法:
在slave-node節點數據庫中執行"rs.slaveOk();"命令便可
........................................................................................

在slave-node節點數據庫中發現已經同步過來了master_slave庫的20條數據,說明mongodb的主從複製環境已經成功了!當配置完主從服務器後,一但主服務器上的數據發生變化,從服務器也會發生變化

主從複製的原理算法

在主從結構中,主節點的操做記錄成爲oplog(operation log)。oplog存儲在一個系統數據庫local的集合oplog.$main中,這個集合的每一個文檔都表明主節點上執行的一個操做。 
從服務器會按期從主服務器中獲取oplog記錄,而後在本機上執行!對於存儲oplog的集合,MongoDB採用的是固定集合,也就是說隨着操做過多,新的操做會覆蓋舊的操做!

主從複製的其餘設置項
--only             從節點指定複製某個數據庫,默認是複製所有數據庫 
--slavedelay       從節點設置主數據庫同步數據的延遲(單位是秒) 
--fastsync         從節點以主數據庫的節點快照爲節點啓動從數據庫 
--autoresync       從節點若是不一樣步則重新同步數據庫(即選擇當經過熱添加了一臺從服務器以後,從服務器選擇是否更新主服務器之間的數據) 
--oplogSize        主節點設置oplog的大小(主節點操做記錄存儲到local的oplog中)

在上面slave-node從節點的local數據庫中,存在一個集合sources。這個集合就保存了這個服務器的主服務器是誰sql

[root@slave-node mongodb]# mongo 182.48.115.236:27017
......
> show dbs
admin         0.000GB
local         0.000GB
master_slave  0.000GB
wangshibo     0.000GB
> use local
switched to db local
> show collections
me
sources
startup_log
> db.sources.find()
{ "_id" : ObjectId("593277a5105051e5648605a3"), "host" : "182.48.115.238:27017", "source" : "main", "syncedTo" : Timestamp(1496481652, 1) }
>

2、Mongodb副本集(Replica Sets)   (能夠參考:搭建高可用mongodb集羣)mongodb

mongodb 不推薦主從複製,推薦創建副本集(Replica Set)來保證1個服務掛了,能夠有其餘服務頂上,程序正常運行,幾個服務的數據都是同樣的,後臺自動同步。主從複製其實就是一個單副本的應用,沒有很好的擴展性餓容錯性。然而副本集具備多個副本保證了容錯性,就算一個副本掛掉了還有不少個副本存在,而且解決了"主節點掛掉後,整個集羣內會自動切換"的問題。副本集比傳統的Master-Slave主從複製有改進的地方就是它能夠進行故障的自動轉移,若是咱們停掉複製集中的一個成員,那麼剩餘成員會再自動選舉一個成員,做爲主庫。
Replica Set 使用的是 n 個 mongod 節點,構建具有自動的容錯功能(auto-failover),自動恢復的(auto-recovery)的高可用方案。使用 Replica Set 來實現讀寫分離。經過在鏈接時指定或者在主庫指定 slaveOk,由Secondary 來分擔讀的壓力,Primary 只承擔寫操做。對於 Replica Set 中的 secondary 節點默認是不可讀的。shell

1)關於副本集的概念

副本集是一種在多臺機器同步數據的進程,副本集體提供了數據冗餘,擴展了數據可用性。在多臺服務器保存數據能夠避免由於一臺服務器致使的數據丟失。
也能夠從硬件故障或服務中斷解脫出來,利用額外的數據副本,能夠從一臺機器致力於災難恢復或者備份。

在一些場景,可使用副本集來擴展讀性能,客戶端有能力發送讀寫操做給不一樣的服務器。也能夠在不一樣的數據中心獲取不一樣的副原本擴展分佈式應用的能力。
mongodb副本集是一組擁有相同數據的mongodb實例,主mongodb接受全部的寫操做,全部的其餘實例能夠接受主實例的操做以保持數據同步。
主實例接受客戶的寫操做,副本集只能有一個主實例,由於爲了維持數據一致性,只有一個實例可寫,主實例的日誌保存在oplog。

Client Application Driver
  Writes  Reads
    |   |
    Primary
  |Replication|Replication
Secondary    Secondary

二級節點複製主節點的oplog而後在本身的數據副本上執行操做,二級節點是主節點數據的反射,若是主節點不可用,會選舉一個新的主節點。
默認讀操做是在主節點進行的,可是能夠指定讀取首選項參數來指定讀操做到副本節點。
能夠添加一個額外的仲裁節點(不擁有被選舉權),使副本集節點保持奇數,確保能夠選舉出票數不一樣的直接點。仲裁者並不須要專用的硬件設備。
仲裁者節點一直會保存仲裁者身份

........異步複製........
副本節點同步直接點操做是異步的,然而會致使副本集沒法返回最新的數據給客戶端程序。

........自動故障轉移........
若是主節點10s以上與其餘節點失去通訊,其餘節點將會選舉新的節點做爲主節點。
擁有大多數選票的副節點會被選舉爲主節點。
副本集提供了一些選項給應用程序,能夠作一個成員位於不一樣數據中心的副本集。
也能夠指定成員不一樣的優先級來控制選舉。

2)副本集的結構及原理

MongoDB 的副本集不一樣於以往的主從模式。
在集羣Master故障的時候,副本集能夠自動投票,選舉出新的Master,並引導其他的Slave服務器鏈接新的Master,而這個過程對於應用是透明的。能夠說MongoDB的副本集
是自帶故障轉移功能的主從複製。
相對於傳統主從模式的優點
傳統的主從模式,須要手工指定集羣中的 Master。若是 Master 發生故障,通常都是人工介入,指定新的 Master。 這個過程對於應用通常不是透明的,每每伴隨着應用重
新修改配置文件,重啓應用服務器等。而 MongoDB 副本集,集羣中的任何節點均可能成爲 Master 節點。一旦 Master 節點故障,則會在其他節點中選舉出一個新的 Master 節點。 並引導剩餘節點鏈接到新的 Master 節點。這個過程對於應用是透明的。

一個副本集即爲服務於同一數據集的多個 MongoDB 實例,其中一個爲主節點,其他的都爲從節點。主節 點上可以完成讀寫操做,從節點僅能用於讀操做。主節點須要記錄全部改變數據庫狀態的操做,這些記錄 保存在 oplog 中,這個文件存儲在 local 數據庫,各個從節點經過此 oplog 來複制數據並應用於本地,保持 本地的數據與主節點的一致。oplog 具備冪等性,即不管執行幾回其結果一致,這個比 mysql 的二進制日 志更好用。
集羣中的各節點還會經過傳遞心跳信息來檢測各自的健康情況。當主節點故障時,多個從節點會觸發一次 新的選舉操做,並選舉其中的一個成爲新的主節點(一般誰的優先級更高,誰就是新的主節點),心跳信 息默認每 2 秒傳遞一次。

客戶端鏈接到副本集後,不關心具體哪一臺機器是否掛掉。主服務器負責整個副本集的讀寫,副本集按期同步數據備份。一旦主節點掛掉,副本節點就會選舉一個新的主服務器。這一切對於應用服務器不須要關心。

心跳檢測:
整個集羣須要保持必定的通訊才能知道哪些節點活着哪些節點掛掉。mongodb節點會向副本集中的其餘節點每兩秒就會發送一次pings包,若是其餘節點在10秒鐘
以內沒有返回就標示爲不能訪問。每一個節點內部都會維護一個狀態映射表,代表當前每一個節點是什麼角色、日誌時間戳等關鍵信息。若是是主節點,除了維護映射表
外還須要檢查本身可否和集羣中內大部分節點通信,若是不能則把本身降級爲secondary只讀節點。

數據同步
副本集同步分爲初始化同步和keep複製。初始化同步指全量從主節點同步數據,若是主節點數據量比較大同步時間會比較長。而keep複製指初始化同步事後,節點
之間的實時同步通常是增量同步。初始化同步不僅是在第一次纔會被處罰,有如下兩種狀況會觸發:
1)secondary第一次加入,這個是確定的。
2)secondary落後的數據量超過了oplog的大小,這樣也會被全量複製。

副本集中的副本節點在主節點掛掉後經過心跳機制檢測到後,就會在集羣內發起主節點的選舉機制,自動選舉出一位新的主服務器。

副本集包括三種節點:主節點、從節點、仲裁節點。

1)主節點負責處理客戶端請求,讀、寫數據, 記錄在其上全部操做的 oplog;
2)從節點按期輪詢主節點獲取這些操做,而後對本身的數據副本執行這些操做,從而保證從節點的數據與主節點一致。默認狀況下,從節點不支持外部讀取,但能夠設置;
   副本集的機制在於主節點出現故障的時候,餘下的節點會選舉出一個新的主節點,從而保證系統能夠正常運行。
3)仲裁節點不復制數據,僅參與投票。因爲它沒有訪問的壓力,比較空閒,所以不容易出故障。因爲副本集出現故障的時候,存活的節點必須大於副本集節點總數的一半,
   不然沒法選舉主節點,或者主節點會自動降級爲從節點,整個副本集變爲只讀。所以,增長一個不容易出故障的仲裁節點,能夠增長有效選票,下降整個副本集不可用的
   風險。仲裁節點可多於一個。也就是說只參與投票,不接收復制的數據,也不能成爲活躍節點。

官方推薦MongoDB副本節點最少爲3臺, 建議副本集成員爲奇數,最多12個副本節點,最多7個節點參與選舉。限制副本節點的數量,主要是由於一個集羣中過多的副本節點,增長了複製的成本,反而拖累了集羣
的總體性能。 太多的副本節點參與選舉,也會增長選舉的時間。而官方建議奇數的節點,是爲了不腦裂 的發生。

3)副本集的工做流程 

在 MongoDB 副本集中,主節點負責處理客戶端的讀寫請求,備份節點則負責映射主節點的 數據。備份節點的工做原理過程能夠大體描述爲,備份節點按期輪詢主節點上的數據操做,
而後對 本身的數據副本進行這些操做,從而保證跟主節點的數據同步。至於主節點上的全部 數據庫狀態改變 的操做,都會存放在一張特定的系統表中。備份節點則是根據這些數據進
行本身的數據更新。

oplog
上面提到的數據庫狀態改變的操做,稱爲 oplog(operation log,主節點操做記錄)。oplog 存儲在 local 數據庫的"oplog.rs"表中。副本集中備份節點異步的從主節點同步 oplog,而後從新 執行它記錄的操做,以此達到了數據同步的做用。
關於 oplog 有幾個注意的地方:
1)oplog 只記錄改變數據庫狀態的操做
2)存儲在 oplog 中的操做並非和主節點執行的操做徹底同樣,例如"$inc"操做就會轉化爲"$set"操做
3)oplog 存儲在固定集合中(capped collection),當 oplog 的數量超過 oplogSize,新的操做就會覆蓋就的操做

數據同步
在副本集中,有兩種數據同步方式:
1)initial sync(初始化):這個過程發生在當副本集中建立一個新的數據庫或其中某個節點剛從宕機中恢復,或者向副本集中添加新的成員的時候,默認的,副本集中的節點會從離 它最近
   的節點複製 oplog 來同步數據,這個最近的節點能夠是 primary 也能夠是擁有最新 oplog 副本的 secondary 節點。該操做通常會從新初始化備份節點,開銷較大。
2)replication(複製):在初始化後這個操做會一直持續的進行着,以保持各個 secondary 節點之間的數據同步。

initial sync
當遇到沒法同步的問題時,只能使用如下兩種方式進行 initial sync 了
1)第一種方式就是中止該節點,而後刪除目錄中的文件,從新啓動該節點。這樣,這個節 點就會執行 initial sync
   注意:經過這種方式,sync 的時間是根據數據量大小的,若是數據量過大,sync 時間就 會很長
   同時會有不少網絡傳輸,可能會影響其餘節點的工做
2)第二種方式,中止該節點,而後刪除目錄中的文件,找一個比較新的節點,而後把該節點目 錄中的文件拷貝到要 sync 的節點目錄中
經過上面兩種方式中的一種,均可以從新恢復"port=33333"的節點。不在進行截圖了。

副本集管理
1)查看oplog的信息 經過"db.printReplicationInfo()"命令能夠查看 oplog 的信息
   字段說明:
   configured oplog size: oplog 文件大小
   log length start to end:     oplog 日誌的啓用時間段
   oplog first event time:      第一個事務日誌的產生時間
   oplog last event time:       最後一個事務日誌的產生時間
   now:                         如今的時間

2)查看 slave 狀態 經過"db.printSlaveReplicationInfo()"能夠查看 slave 的同步狀態
  當插入一條新的數據,而後從新檢查 slave 狀態時,就會發現 sync 時間更新了

4)副本集選舉的過程和注意點

Mongodb副本集選舉採用的是Bully算法,這是一種協調者(主節點)競選算法,主要思想是集羣的每一個成員均可以聲明它是主節點並通知其餘節點。
別的節點能夠選擇接受這個聲稱或是拒絕並進入主節點競爭,被其餘全部節點接受的節點才能成爲主節點。 
節點按照一些屬性來判斷誰應該勝出,這個屬性能夠是一個靜態 ID,也能夠是更新的度量像最近一次事務ID(最新的節點會勝出) 

副本集的選舉過程大體以下:
1)獲得每一個服務器節點的最後操做時間戳。每一個 mongodb 都有 oplog 機制會記錄本機的操做,方便和主服 務器進行對比數據是否同步還能夠用於錯誤恢復。
2)若是集羣中大部分服務器 down 機了,保留活着的節點都爲 secondary 狀態並中止,不選舉了。
3)若是集羣中選舉出來的主節點或者全部從節點最後一次同步時間看起來很舊了,中止選舉等待人來操做。
4)若是上面都沒有問題就選擇最後操做時間戳最新(保證數據是最新的)的服務器節點做爲主節點。


副本集選舉的特色:
選舉還有個前提條件,參與選舉的節點數量必須大於副本集總節點數量的一半(建議副本集成員爲奇數。最多12個副本節點,最多7個節點參與選舉)
若是已經小於一半了全部節點保持只讀狀態。集合中的成員必定要有大部分紅員(即超過一半數量)是保持正常在線狀態,3個成員的副本集,須要至少2個從屬節點是正常狀態。
若是一個從屬節點掛掉,那麼當主節點down掉 產生故障切換時,因爲副本集中只有一個節點是正常的,少於一半,則選舉失敗。
4個成員的副本集,則須要3個成員是正常狀態(先關閉一個從屬節點,而後再關閉主節點,產生故障切換,此時副本集中只有2個節點正常,則沒法成功選舉出新主節點)。

5)副本集數據過程

Primary節點寫入數據,Secondary經過讀取Primary的oplog獲得複製信息,開始複製數據而且將複製信息寫入到本身的oplog。若是某個操做失敗,則備份節點
中止從當前數據源複製數據。若是某個備份節點因爲某些緣由掛掉了,當從新啓動後,就會自動從oplog的最後一個操做開始同步,同步完成後,將信息寫入本身的
oplog,因爲複製操做是先複製數據,複製完成後再寫入oplog,有可能相同的操做會同步兩份,不過MongoDB在設計之初就考慮到這個問題,將oplog的同一個操做
執行屢次,與執行一次的效果是同樣的。簡單的說就是:

當Primary節點完成數據操做後,Secondary會作出一系列的動做保證數據的同步:
1)檢查本身local庫的oplog.rs集合找出最近的時間戳。
2)檢查Primary節點local庫oplog.rs集合,找出大於此時間戳的記錄。
3)將找到的記錄插入到本身的oplog.rs集合中,並執行這些操做。

副本集的同步和主從同步同樣,都是異步同步的過程,不一樣的是副本集有個自動故障轉移的功能。其原理是:slave端從primary端獲取日誌,而後在本身身上徹底順序
的執行日誌所記錄的各類操做(該日誌是不記錄查詢操做的),這個日誌就是local數據 庫中的oplog.rs表,默認在64位機器上這個表是比較大的,佔磁盤大小的5%,
oplog.rs的大小能夠在啓動參數中設 定:--oplogSize 1000,單位是M。

注意:在副本集的環境中,要是全部的Secondary都宕機了,只剩下Primary。最後Primary會變成Secondary,不能提供服務。

6)MongoDB 同步延遲問題

當你的用戶抱怨修改過的信息不改變,刪除掉的數據還在顯示,你掐指一算,估計是數據庫主從不一樣步。與其餘提供數據同步的數據庫同樣,MongoDB 也會遇到同步延遲的問題,
在MongoDB的Replica Sets模式中,同步延遲也常常是困擾使用者的一個大問題。

什麼是同步延遲?
首先,要出現同步延遲,必然是在有數據同步的場合,在 MongoDB 中,有兩種數據冗餘方式,一種是Master-Slave 模式,一種是Replica Sets模式。這兩個模式本質上都是
在一個節點上執行寫操做, 另外的節點將主節點上的寫操做同步到本身這邊再進行執行。在MongoDB中,全部寫操做都會產生 oplog,oplog 是每修改一條數據都會生成一條,若是你採用一個批量 update 命令更新了 N 多條數據, 那麼抱歉,oplog 會有不少條,而不是一條。因此同步延遲就是寫操做在主節點上執行完後,從節點尚未把 oplog 拿過來再執行一次。而這個寫操做的量越大,主節點與從節點的差異也就越大,同步延遲也就越大了。

同步延遲帶來的問題
首先,同步操做一般有兩個效果,一是讀寫分離,將讀操做放到從節點上來執行,從而減小主節點的 壓力。對於大多數場景來講,讀多寫少是基本特性,因此這一點是頗有用的。
另外一個做用是數據備份, 同一個寫操做除了在主節點執行以外,在從節點上也一樣執行,這樣咱們就有多份一樣的數據,一旦 主節點的數據由於各類天災人禍沒法恢復的時候,咱們至少還有從節點能夠依賴。可是主從延遲問題 可能會對上面兩個效果都產生很差的影響。

若是主從延遲過大,主節點上會有不少數據更改沒有同步到從節點上。這時候若是主節點故障,就有 兩種狀況:
1)主節點故障而且沒法恢復,若是應用上又沒法忍受這部分數據的丟失,咱們就得想各類辦法將這部 數據更改找回來,再寫入到從節點中去。能夠想象,即便是有可能,那這也絕對是一件很是噁心的活。
2)主節點可以恢復,可是須要花的時間比較長,這種狀況若是應用能忍受,咱們能夠直接讓從節點提 供服務,只是對用戶來講,有一段時間的數據丟失了,而若是應用不能接受數據的不一致,那麼就只能下線整個業務,等主節點恢復後再提供服務了。

若是你只有一個從節點,當主從延遲過大時,因爲主節點只保存最近的一部分 oplog,可能會致使從 節點青黃不接,不得不進行 resync 操做,全量從主節點同步數據。
帶來的問題是:當從節點全量同步的時候,實際只有主節點保存了完整的數據,這時候若是主節點故障,極可能全 部數據都丟掉了。

7)Mongodb副本集環境部署記錄

1)機器環境
182.48.115.236    master-node(主節點)
182.48.115.237    slave-node1(從節點)
182.48.115.238    slave-node2(從節點)

MongoDB 安裝目錄:/usr/local/mongodb
MongoDB 數據庫目錄:/usr/local/mongodb/data
MongoDB 日誌目錄:/usr/local/mongodb/log/mongo.log 
MongoDB 配置文件:/usr/local/mongodb/mongodb.conf

mongodb安裝能夠參考:http://www.cnblogs.com/kevingrace/p/5752382.html

對以上三臺服務器部署Mongodb的副本集功能,定義副本集名稱爲:hqmongodb
關閉三臺服務器的iptables防火牆和selinux

2)確保三臺副本集服務器上的配置文件徹底相同(即三臺機器的mongodb.conf配置同樣,除了配置文件中綁定的ip不同)。下面操做在三臺節點機上都要執行:

編寫配置文件
[root@master-node ~]# cat /usr/local/mongodb/mongodb.conf
port=27017
bind_ip = 182.48.115.236                 //這個最好配置成本機的ip地址。不然後面進行副本集初始化的時候可能會失敗!            
dbpath=/usr/local/mongodb/data
logpath=/usr/local/mongodb/log/mongo.log
pidfilepath=/usr/local/mongodb/mongo.pid
fork=true
logappend=true 
shardsvr=true 
directoryperdb=true
#auth=true
#keyFile =/usr/local/mongodb/keyfile
replSet =hqmongodb

編寫啓動腳本(各個節點須要將腳本中的ip改成本機本身的ip地址)
[root@master-node ~]# cat /usr/local/mongodb/mongodb.conf
port=27017
dbpath=/usr/local/mongodb/data
logpath=/usr/local/mongodb/log/mongo.log
pidfilepath=/usr/local/mongodb/mongo.pid
fork=true
logappend=true 
shardsvr=true 
directoryperdb=true
#auth=true
#keyFile =/usr/local/mongodb/keyfile
replSet =hqmongodb
[root@master-node ~]# cat /etc/init.d/mongodb
#!/bin/sh
# chkconfig: - 64 36
# description:mongod
case $1 in
start)
/usr/local/mongodb/bin/mongod --maxConns 20000 --config /usr/local/mongodb/mongodb.conf
;;
stop)
/usr/local/mongodb/bin/mongo 182.48.115.236:27017/admin --eval "db.shutdownServer()"
#/usr/local/mongodb/bin/mongo 182.48.115.236:27017/admin --eval "db.auth('system', '123456');db.shutdownServer()"
;;
status)
/usr/local/mongodb/bin/mongo 182.48.115.236:27017/admin --eval "db.stats()"
#/usr/local/mongodb/bin/mongo 182.48.115.236:27017/admin --eval "db.auth('system', '123456');db.stats()"
;; esac

啓動mongodb
[root@master-node ~]# ulimit -SHn 655350

[root@master-node ~]# /etc/init.d/mongodb start
about to fork child process, waiting until server is ready for connections.
forked process: 28211
child process started successfully, parent exiting
[root@master-node ~]# ps -ef|grep mongodb
root     28211     1  2 00:30 ?        00:00:00 /usr/local/mongodb/bin/mongod --maxConns 20000 --config /usr/local/mongodb/mongodb.conf
root     28237 27994  0 00:30 pts/2    00:00:00 grep mongodb

[root@master-node ~]# lsof -i:27017
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
mongod  28211 root    7u  IPv4 684206      0t0  TCP *:27017 (LISTEN)
------------------------------------------------------------------
若是啓動mongodb的時候報錯以下:
about to fork child process, waiting until server is ready for connections.
forked process: 14229
ERROR: child process failed, exited with error number 100

這算是一個Mongod 啓動的一個常見錯誤,非法關閉的時候,lock 文件沒有幹掉,第二次啓動的時候檢查到有lock 文件的時候,就報這個錯誤了。
解決方法:進入mongod啓動時指定的data目錄下刪除lock文件,而後執行"./mongod  --repair"就好了。即
# rm -rf /usr/local/mongodb/data/mongod.lock                   //因爲個人測試環境下沒有數據,我將data數據目錄下的文件所有清空,而後--repair
# /usr/local/mongodb/bin/mongod --repair

而後再啓動mongodb就ok了!
------------------------------------------------------------------

3)對master-node主節點進行配置(182.48.115.236)         //其實,剛開始這三個節點中的任何一個均可以用來初始化爲開始的主節點。這裏選擇以master-node爲主節點
[root@master-node ~]# mongo 182.48.115.236:27017        //登錄到mongodb數據庫中執行下面命令操做。因爲配置文件中綁定了ip,因此要用這個綁定的ip登錄
....

3.1)初始化副本集,設置本機爲主節點 PRIMARY

> rs.initiate()
{
  "info2" : "no configuration specified. Using a default configuration for the set",
  "me" : "182.48.115.236:27017",
  "ok" : 1
}
hqmongodb:OTHER> rs.conf()
{
  "_id" : "hqmongodb",
  "version" : 1,
  "protocolVersion" : NumberLong(1),
  "members" : [
    {
      "_id" : 0,
      "host" : "182.48.115.236: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" : 2000,
    "getLastErrorModes" : {
      
    },
    "getLastErrorDefaults" : {
      "w" : 1,
      "wtimeout" : 0
    },
    "replicaSetId" : ObjectId("5932f142a55dc83eca86ea86")
  }
}

3.2)添加副本集從節點。(發如今執行上面的兩個命令後,前綴已經改爲"hqmongodb:PRIMARY"了,即已經將其本身設置爲主節點 PRIMARY了)
hqmongodb:PRIMARY> rs.add("182.48.115.237:27017")
{ "ok" : 1 }
hqmongodb:PRIMARY> rs.add("182.48.115.238:27017")
{ "ok" : 1 }

3.3)設置節點優先級
hqmongodb:PRIMARY> cfg = rs.conf()          //查看節點順序
{
  "_id" : "hqmongodb",
  "version" : 3,
  "protocolVersion" : NumberLong(1),
  "members" : [
    {
      "_id" : 0,
      "host" : "182.48.115.236:27017",
      "arbiterOnly" : false,
      "buildIndexes" : true,
      "hidden" : false,
      "priority" : 1,
      "tags" : {
        
      },
      "slaveDelay" : NumberLong(0),
      "votes" : 1
    },
    {
      "_id" : 1,
      "host" : "182.48.115.237:27017",
      "arbiterOnly" : false,
      "buildIndexes" : true,
      "hidden" : false,
      "priority" : 1,
      "tags" : {
        
      },
      "slaveDelay" : NumberLong(0),
      "votes" : 1
    },
    {
      "_id" : 2,
      "host" : "182.48.115.238: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" : 2000,
    "getLastErrorModes" : {
      
    },
    "getLastErrorDefaults" : {
      "w" : 1,
      "wtimeout" : 0
    },
    "replicaSetId" : ObjectId("5932f142a55dc83eca86ea86")
  }
}

hqmongodb:PRIMARY> cfg.members[0].priority = 1
1
hqmongodb:PRIMARY> cfg.members[1].priority = 1
1
hqmongodb:PRIMARY> cfg.members[2].priority = 2      //設置_ID 爲 2 的節點爲主節點。即噹噹前主節點發生故障時,該節點就會轉變爲主節點接管服務
2
hqmongodb:PRIMARY> rs.reconfig(cfg)                 //使配置生效
{ "ok" : 1 }


說明:
MongoDB副本集經過設置priority 決定優先級,默認優先級爲1,priority值是0到100之間的數字,數字越大優先級越高,priority=0,則此節點永遠不能成爲主節點 primay。
cfg.members[0].priority =1 參數,中括號裏的數字是執行rs.conf()查看到的節點順序, 第一個節點是0,第二個節點是 1,第三個節點是 2,以此類推。優先級最高的那個
被設置爲主節點。

4)分別對兩臺從節點進行配置

slave-node1節點操做(182.48.115.237)
[root@slave-node1 ~]# mongo 182.48.115.237:27017
.....
hqmongodb:SECONDARY> db.getMongo().setSlaveOk()        //設置從節點爲只讀.注意從節點的前綴如今是SECONDARY。看清楚才設置

slave-node2節點操做(182.48.115.238)
[root@slave-node2 ~]# mongo 182.48.115.238:27017
......
hqmongodb:SECONDARY> db.getMongo().setSlaveOk()       //從節點的前綴是SECONDARY,看清楚才設置。執行這個,不然後續從節點同步數據時會報錯:"errmsg" : "not master and slaveOk=false",

5)設置數據庫帳號,開啓登陸驗證(這一步能夠直接跳過,即不開啓登錄驗證,只是爲了安全着想)
5.1)設置數據庫帳號
在master-node主節點服務器182.48.115.236上面操做
[root@master-node ]# mongo 182.48.115.236:27017
......
-------------------------------------------------
若是執行命令後出現報錯: "errmsg" : "not master and slaveOk=false",
這是正常的,由於SECONDARY是不容許讀寫的,若是非要解決,方法以下:
> rs.slaveOk();              //執行這個命令而後,再執行其它命令就不會出現這個報錯了
-------------------------------------------------
hqmongodb:PRIMARY> show dbs
local  0.000GB        
hqmongodb:PRIMARY> use admin     //mongodb3.0沒有admin數據庫了,須要手動建立。admin庫下添加的帳號纔是管理員帳號
switched to db admin    
hqmongodb:PRIMARY> show collections

#添加兩個管理員帳號,一個系統管理員:system 一個數據庫管理員:administrator
#先添加系統管理員帳號,用來管理用戶
hqmongodb:PRIMARY> db.createUser({user:"system",pwd:"123456",roles:[{role:"root",db:"admin"}]})
Successfully added user: {
  "user" : "system",
  "roles" : [
    {
      "role" : "root",
      "db" : "admin"
    }
  ]
}
hqmongodb:PRIMARY> db.auth('system','123456')        //添加管理員用戶認證,認證以後才能管理全部數據庫
1

#添加數據庫管理員,用來管理全部數據庫
hqmongodb:PRIMARY> db.createUser({user:'administrator', pwd:'123456', roles:[{ role: "userAdminAnyDatabase", db: "admin"}]});
Successfully added user: {
  "user" : "administrator",
  "roles" : [
    {
      "role" : "userAdminAnyDatabase",
      "db" : "admin"
    }
  ]
}
hqmongodb:PRIMARY> db.auth('administrator','123456')      //添加管理員用戶認證,認證以後才能管理全部數據庫
1

hqmongodb:PRIMARY> db
admin
hqmongodb:PRIMARY> show collections
system.users
system.version
hqmongodb:PRIMARY> db.system.users.find()
{ "_id" : "admin.system", "user" : "system", "db" : "admin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "uTGH9NI6fVUFXd2u7vu3Pw==", "storedKey" : "qJBR7dlqj3IgnWpVbbqBsqo6ECs=", "serverKey" : "pTQhfZohNh760BED7Zn1Vbety4k=" } }, "roles" : [ { "role" : "root", "db" : "admin" } ] }
{ "_id" : "admin.administrator", "user" : "administrator", "db" : "admin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "zJ3IIgYCe4IjZm0twWnK2Q==", "storedKey" : "2UCFc7KK1k5e4BgWbkTKGeuOVB4=", "serverKey" : "eYHK/pBpf8ntrER1A8fiI+GikBY=" } }, "roles" : [ { "role" : "userAdminAnyDatabase", "db" : "admin" } ] }

退出,用剛纔建立的帳號進行登陸
[root@master-node ~]# mongo 182.48.115.236:27017 -u system -p 123456 --authenticationDatabase admin
[root@master-node ~]# mongo 182.48.115.236:27017 -u administrator -p 123456  --authenticationDatabase admin

5.2)開啓登陸驗證
在master-node主節點服務器182.48.115.236上面操做
[root@master-node ~]# cd /usr/local/mongodb/                        //切換到mongodb主目錄
[root@master-node mongodb]# openssl rand -base64 21 > keyfile      //建立一個 keyfile(使用 openssl 生成 21 位 base64 加密的字符串)
[root@master-node mongodb]# chmod 600 /usr/local/mongodb/keyfile
[root@master-node mongodb]# cat /usr/local/mongodb/keyfile          //查看剛纔生成的字符串,作記錄,後面要用到
RavtXslz/WTDwwW2JiNvK4OBVKxU

注意:上面的數字 21,最好是 3 的倍數,不然生成的字符串可能含有非法字符,認證失敗。

5.3)設置配置文件
分別在全部節點上面操做(即三個節點的配置文件上都要修改)
[root@master-node ~]# vim /usr/local/mongodb/mongodb.conf     //添加下面兩行內容
......
auth=true
keyFile =/usr/local/mongodb/keyfile

啓動腳本使用下面的代碼(註釋原來的,啓用以前註釋掉的)
[root@master-node ~]# cat /etc/init.d/mongodb
#!/bin/sh
# chkconfig: - 64 36
# description:mongod
case $1 in
start)
/usr/local/mongodb/bin/mongod --maxConns 20000 --config /usr/local/mongodb/mongodb.conf
;;
stop)
#/usr/local/mongodb/bin/mongo 182.48.115.236:27017/admin --eval "db.shutdownServer()"
/usr/local/mongodb/bin/mongo 182.48.115.236:27017/admin --eval "db.auth('system', '123456');db.shutdownServer()"
;;
status)
#/usr/local/mongodb/bin/mongo 182.48.115.236:27017/admin --eval "db.stats()"
/usr/local/mongodb/bin/mongo 182.48.115.236:27017/admin --eval "db.auth('system', '123456');db.stats()"
;; esac

5.4)設置權限驗證文件
先進入master-node主節點服務器182.48.115.236,查看 
[root@master-node ~]# cat /usr/local/mongodb/keyfile
RavtXslz/WTDwwW2JiNvK4OBVKxU                              //查看剛纔生成的字符串,作記錄

再分別進入兩臺從節點服務器182.48.115.237/238
[root@slave-node1 ~]# vim /usr/local/mongodb/keyfile       //將主節點生成的權限驗證字符碼複製到從節點的權限驗證文件裏
RavtXslz/WTDwwW2JiNvK4OBVKxU
[root@slave-node1 ~]# chmod 600 /usr/local/mongodb/keyfile

[root@slave-node2 ~]# vim /usr/local/mongodb/keyfile 
[root@slave-node2 ~]# cat /usr/local/mongodb/keyfile
RavtXslz/WTDwwW2JiNvK4OBVKxU
[root@slave-node2 ~]# chmod 600 /usr/local/mongodb/keyfile

6)驗證副本集
分別重啓三臺副本集服務器(三臺節點都要重啓)
[root@master-node ~]# ps -ef|grep mongodb
root     28964     1  1 02:22 ?        00:00:31 /usr/local/mongodb/bin/mongod --maxConns 20000 --config /usr/local/mongodb/mongodb.conf
root     29453 28911  0 03:04 pts/0    00:00:00 grep mongodb
[root@master-node ~]# kill -9 28964
[root@master-node ~]# /etc/init.d/mongodb start
about to fork child process, waiting until server is ready for connections.
forked process: 29457
child process started successfully, parent exiting
[root@master-node ~]# lsof -i:27017
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
mongod  29457 root    7u  IPv4 701471      0t0  TCP slave-node1:27017 (LISTEN)
mongod  29457 root   29u  IPv4 701526      0t0  TCP slave-node1:27017->master-node:39819 (ESTABLISHED)
mongod  29457 root   30u  IPv4 701573      0t0  TCP slave-node1:27017->master-node:39837 (ESTABLISHED)
mongod  29457 root   31u  IPv4 701530      0t0  TCP slave-node1:36768->master-node:27017 (ESTABLISHED)
mongod  29457 root   32u  IPv4 701549      0t0  TCP slave-node1:36786->master-node:27017 (ESTABLISHED)
mongod  29457 root   33u  IPv4 701574      0t0  TCP slave-node1:27017->master-node:39838 (ESTABLISHED)

而後登錄mongodb
[root@master-node ~]# mongo 182.48.115.236:27017 -u system -p 123456 --authenticationDatabase admin
.......
hqmongodb:PRIMARY> rs.status()             //副本集狀態查看.也能夠省略上面添加登錄驗證的步驟,不作驗證,直接查看集羣狀態。集羣狀態中能夠看出哪一個節點目前是主節點
{
  "set" : "hqmongodb",
  "date" : ISODate("2017-06-03T19:06:59.708Z"),
  "myState" : 1,
  "term" : NumberLong(2),
  "heartbeatIntervalMillis" : NumberLong(2000),
  "optimes" : {
    "lastCommittedOpTime" : {
      "ts" : Timestamp(1496516810, 1),
      "t" : NumberLong(2)
    },
    "appliedOpTime" : {
      "ts" : Timestamp(1496516810, 1),
      "t" : NumberLong(2)
    },
    "durableOpTime" : {
      "ts" : Timestamp(1496516810, 1),
      "t" : NumberLong(2)
    }
  },
  "members" : [
    {
      "_id" : 0,
      "name" : "182.48.115.236:27017",
      "health" : 1,
      "state" : 1,                         //state的值爲1的節點就是主節點
      "stateStr" : "PRIMARY",              //主節點PRIMARY標記
      "uptime" : 138,
      "optime" : {
        "ts" : Timestamp(1496516810, 1),
        "t" : NumberLong(2)
      },
      "optimeDate" : ISODate("2017-06-03T19:06:50Z"),
      "infoMessage" : "could not find member to sync from",
      "electionTime" : Timestamp(1496516709, 1),
      "electionDate" : ISODate("2017-06-03T19:05:09Z"),
      "configVersion" : 4,
      "self" : true
    },
    {
      "_id" : 1,
      "name" : "182.48.115.237:27017",
      "health" : 1,
      "state" : 2,
      "stateStr" : "SECONDARY",
      "uptime" : 116,
      "optime" : {
        "ts" : Timestamp(1496516810, 1),
        "t" : NumberLong(2)
      },
      "optimeDurable" : {
        "ts" : Timestamp(1496516810, 1),
        "t" : NumberLong(2)
      },
      "optimeDate" : ISODate("2017-06-03T19:06:50Z"),
      "optimeDurableDate" : ISODate("2017-06-03T19:06:50Z"),
      "lastHeartbeat" : ISODate("2017-06-03T19:06:59.533Z"),
      "lastHeartbeatRecv" : ISODate("2017-06-03T19:06:59.013Z"),
      "pingMs" : NumberLong(0),
      "syncingTo" : "182.48.115.236:27017",
      "configVersion" : 4
    },
    {
      "_id" : 2,
      "name" : "182.48.115.238:27017",
      "health" : 1,
      "state" : 2,
      "stateStr" : "SECONDARY",
      "uptime" : 189,
      "optime" : {
        "ts" : Timestamp(1496516810, 1),
        "t" : NumberLong(2)
      },
      "optimeDurable" : {
        "ts" : Timestamp(1496516810, 1),
        "t" : NumberLong(2)
      },
      "optimeDate" : ISODate("2017-06-03T19:06:50Z"),
      "optimeDurableDate" : ISODate("2017-06-03T19:06:50Z"),
      "lastHeartbeat" : ISODate("2017-06-03T19:06:59.533Z"),
      "lastHeartbeatRecv" : ISODate("2017-06-03T19:06:59.013Z"),
      "pingMs" : NumberLong(0),
      "syncingTo" : "182.48.115.236:27017",
      "configVersion" : 4
    },
  ],
  "ok" : 1
}

注意上面命令結果中的state,若是這個值爲 1,說明是主控節點(master);若是是2,說明是從屬節點slave。在上面顯示的當前主節點寫入數據,到從節點上查看發現數據會同步。
 
當主節點出現故障的時候,在兩個從節點上會選舉出一個新的主節點,故障恢復以後,以前的主節點會變爲從節點。從上面集羣狀態中開看出,當前主節點是master-node,那麼關閉它的mongodb,再次查看集羣狀態,就會發現主節點變爲以前設置的slave-node2,即182.48.115.238了!
至此,Linux 下 MongoDB 副本集部署完成。

-------------------------------------------------------------------------------------------
添加數據,來須要驗證的--------------------
1)主從服務器數據是否同步,從服務器沒有讀寫權限
a:向主服務器寫入數據 ok 後臺自動同步到從服務器,從服務器有數據
b:向從服務器寫入數據 false 從服務器不能寫
c:主服務器讀取數據 ok
d:從服務器讀取數據 false 從服務器不能讀

2)關閉主服務器,從服務器是否能頂替
 mongo 的命令行執行 rs.status() 發現 PRIMARY 替換了主機了

3)關閉的服務器,再恢復,以及主從切換
 a:直接啓動關閉的服務,rs.status()中會發現,原來掛掉的主服務器重啓後變成從服務器了
 b:額外刪除新的服務器 rs.remove("localhost:9933"); rs.status()
 c:額外增長新的服務器 rs.add({_id:0,host:"localhost:9933",priority:1});
 d:讓新增的成爲主服務器 rs.stepDown(),注意以前的 priority 投票

4)從服務器讀寫
 db.getMongo().setSlaveOk();
 db.getMongo().slaveOk();//從庫只讀,沒有寫權限,這個方法 java 裏面不推薦了
 db.setReadPreference(ReadPreference.secondaryPreferred());// 在 復 制 集 中 優 先 讀
 secondary,若是 secondary 訪問不了的時候就從 master 中讀
 db.setReadPreference(ReadPreference.secondary());// 只 從 secondary 中 讀 , 如 果
 secondary 訪問不了的時候就不能進行查詢

日誌查看--------------------------- 
 MongoDB 的 Replica Set 架構是經過一個日誌來存儲寫操做的,這個日誌就叫作」oplog」,
 它存在於」local」數據庫中,oplog 的大小是能夠經過 mongod 的參數」—oplogSize」來改變
 oplog 的日誌大小。
 > use local
 switched to db local
 > db.oplog.rs.find()
 { "ts" : { "t" : 1342511269000, "i" : 1 }, "h" : NumberLong(0), "op" : "n", "ns" : "", "o" :
 { "msg" : "initiating set" } }
 
 字段說明:
 ts: 某個操做的時間戳
 op: 操做類型,以下:
 i: insert
 d: delete
 u: update
 ns: 命名空間,也就是操做的 collection name
-------------------------------------------------------------------------------------------
其它注意細節:
rs.remove("ip:port");       //刪除副本
單服務器,啓動時添加--auth         參數開啓驗證。

副本集服務器,開啓--auth 參數的同時,必須指定 keyfile 參數,節點之間的通信基於該 keyfile,key 長度必須在 6 到 1024 個字符之間,
最好爲 3 的倍數,不能含有非法字符。

從新設置副本集 
rs.stepDown() 
cfg = rs.conf()
cfg.members[n].host= 'new_host_name:prot'
rs.reconfig(cfg)

副本集全部節點服務器總數必須爲奇數,服務器數量爲偶數的時候,須要添加一個仲裁節 點,仲裁節點不參與數副本集,只有選舉權。

rs.addArb("182.48.115.239:27017") #添加仲裁節點

3、Mongodb分片集羣(Sharding)

Sharding cluster是一種能夠水平擴展的模式,在數據量很大時特給力,實際大規模應用通常會採用這種架構去構建。sharding分片很好的解決了單臺服務器磁盤空間、內存、cpu等硬件資源的限制問題,把數據水平拆分出去,下降單節點的訪問壓力。每一個分片都是一個獨立的數據庫,全部的分片組合起來構成一個邏輯上的完整的數據庫。所以,分片機制下降了每一個分片的數據操做量及須要存儲的數據量,達到多臺服務器來應對不斷增長的負載和數據的效果。

1)Sharding分區概念

分片 (sharding)是指將數據庫拆分,將其分散在不一樣的機器上的過程。將數據分散到不一樣的機器上,不須要功能強大的服務器就能夠存儲更多的數據和處理更大的負載。

分片的基本思想就是:
將集合切成小塊,這些塊分散到若干片裏,每一個片只負責總數據的一部分。經過一個名爲 mongos 的路由進程進行操做,mongos 知道數據和片的對應
關係(經過配置服務器)。 大部分使用場景都是解決磁盤空間的問題,對於寫入有可能會變差(+++裏面的說明+++),查 詢則儘可能避免跨分片查詢。使用分片的時機:

使用場景: 
1)機器的磁盤不夠用了。使用分片解決磁盤空間的問題。
2)單個mongod已經不能知足寫數據的性能要求。經過分片讓寫壓力分散到各個分片上面,使用分片服務器自身的資源。
3)想把大量數據放到內存裏提升性能。和上面同樣,經過分片使用分片服務器自身的資源。

要構建一個MongoDB Sharding Cluster(分片集羣),須要三種角色:
1)分片服務器(Shard Server)
   mongod 實例,用於存儲實際的數據塊,實際生產環境中一個 shard server 角色可由幾臺機器組個一個 relica set 承擔,防止主機單點故障
   這是一個獨立普通的mongod進程,保存數據信息。能夠是一個副本集也能夠是單獨的一臺服務器。
2)配置服務器(Config Server)
   mongod 實例,存儲了整個 Cluster Metadata,其中包括 chunk 信息。
   這是一個獨立的mongod進程,保存集羣和分片的元數據,即各分片包含了哪些數據的信息。最早開始創建,啓用日誌功能。像啓動普通的 mongod 同樣啓動
   配置服務器,指定configsvr 選項。不須要太多的空間和資源,配置服務器的 1KB 空間至關於真是數據的 200MB。保存的只是數據的分佈表。
3)路由服務器(Route Server)
   mongos實例,前端路由,客戶端由此接入,且讓整個集羣看上去像單一數據庫,前端應用
   起到一個路由的功能,供程序鏈接。自己不保存數據,在啓動時從配置服務器加載集羣信息,開啓 mongos 進程須要知道配置服務器的地址,指定configdb選項。

片鍵的意義
一個好的片鍵對分片相當重要。 片鍵必須是一個索引 ,通 過 sh.shardCollection 加會自動建立索引。一個自增的片鍵對寫入和數據均勻分佈就不是很好, 由於自增
的片鍵總會在一個分片上寫入,後續達到某個閥值可能會寫到別的分片。可是按照片鍵查詢會很是高效。隨機片鍵對數據的均勻分佈效果很好。注意儘可能避免在多個分片上進行查詢。 
在全部分片上查詢,mongos 會對結果進行歸併排序

爲什麼須要水平分片
1)減小單機請求數,將單機負載,提升總負載
2)減小單機的存儲空間,提升總存空間

mongodb sharding 服務器架構

簡單註解:

分片集羣主要由三種組件組成:mongos,config server,shard
1) mongos  (路由進程, 應用程序接入 mongos 再查詢到具體分片)
數據庫集羣請求的入口,全部的請求都經過 mongos 進行協調,不須要在應用程序添加一個路由選擇器,mongos 本身就是一個請求分發中心,它負責把對應的數據請求
請求轉發到對應的 shard 服務器上。在生產環境一般有多個 mongos 做爲請求的入口,防止其中一個掛掉全部的 mongodb 請求都沒有辦法操做。

2) config server  (路由表服務。 每一臺都具備所有 chunk 的路由信息)
顧名思義爲配置服務器,存儲全部數據庫元信息(路由、分片)的配置。mongos 自己沒有物理存儲分片服務器和數據路由信息,只是緩存在內存裏,配置服務器則實際存儲
這些數據。mongos 第一次啓動或者關掉重啓就會從 config server 加載配置信息,之後若是配置服務器信息變化會通知到全部的 mongos 更新本身的狀態,這樣 
mongos 就能繼續準確路由。在生產環境一般有多個 config server 配置服務器,由於它存儲了分片路由的元數據,這個可不能丟失!就算掛掉其中一臺,只要還有存貨, 
mongodb 集羣就不會掛掉。

3) shard  (爲數據存儲分片。 每一片均可以是複製集(replica set))
這就是傳說中的分片了。如圖所示,一臺機器的一個數據表 Collection1 存儲了 1T 數據,壓力太大了!在分給 4 個機器後, 每一個機器都是 256G,則分攤了集中在一臺
機器的壓力。事實上,上圖4個分片若是沒有副本集(replica set)是個不完整架構,假設其中的一個分片掛掉那四 分之一的數據就丟失了,因此在高可用性的分片架構還
須要對於每個分片構建 replica set 副本集保 證分片的可靠性。生產環境一般是 2 個副本 + 1 個仲裁。

2)Sharding分區的原理

分片,是指將數據拆分,將其分散到不一樣的機器上。這樣的好處就是,不須要功能強大的大型計算機也能夠存儲更多的數據,處理更大的負載。mongoDB 的分片,
是將collection 的數據進行分割,而後將不一樣的部分分別存儲到不一樣的機器上。當 collection 所佔空間過大時,咱們須要增長一臺新的機器,分片會自動
將 collection 的數據分發到新的機器上。

mongoDB sharding分片的原理

人臉:    
表明客戶端,客戶端確定說,你數據庫分片不分片跟我不要緊,我叫你幹啥就幹啥,沒什麼好商量的。

mongos: 
首先咱們要了解」片鍵「的概念,也就是說拆分集合的依據是什麼?按照什麼鍵值進行拆分集合。mongos就是一個路由服務器,它會根據管理員設置的"片鍵"
將數據分攤到本身管理的mongod集羣,數據和片的對應關係以及相應的配置信息保存在"config服務器"上。
客戶端只須要對 mongos 進行操做就好了,至於如何進行分片,不須要 客戶端參與,由 mongos 和 config 來完成。

mongod:   
一個普通的數據庫實例或者副本集,若是不分片的話,咱們會直接連上mongod。

分片是指將數據拆分,將其分散存在不一樣機器上的過程.有時也叫分區.將數據分散在不一樣的機器上MongoDB支持自動分片,能夠擺脫手動分片的管理.集羣自動切分數據,作負載均衡

分片集羣的構造以下:

分片集羣由如下3個服務組成:Shards Server: 每一個shard由一個或多個mongod進程組成,用於存儲數據Config Server: 用於存儲集羣的Metadata信息,包括每一個Shard的信息和chunks信息Route Server: 用於提供路由服務,由Client鏈接,使整個Cluster看起來像單個DB服務器

相關文章
相關標籤/搜索