MongoDB叢集運維筆記

散盡浮華發表於2018-01-02

 

前面的文章介紹了MongoDB副本集和分片叢集的做法,下面對MongoDB叢集的日常維護操作進行小總結:

        MongDB副本集故障轉移功能得益於它的選舉機制。選舉機制採用了Bully演算法,可以很方便從分散式節點中選出主節點。Bully演算法是一種協調者(主節點)競選演算法,主要思想是叢集的每個成員都可以宣告它是主節點並通知其他節點。別的節點可以選擇接受這個聲稱或是拒絕並進入主節點競爭。被其他所有節點接受的節點才能成為主節點。節點按照一些屬性來判斷誰應該勝出。這個屬性可以是一個靜態ID,也可以是更新的度量像最近一次事務ID(最新的節點會勝出)。

1)MongoDB叢集的節點數量
       官方推薦MongoDB副本集的成員數量最好為奇數,且選舉要求參與的節點數量必須大於成員數的一半。假設MongoDB叢集有3個節點,那麼只要有2個節點活著就可以選舉;如果有5個,那麼活3個節點就可以選舉;如果有7個節點,那麼活4個就可以選舉.....
MongoDB叢集最多允許12個副本集節點,其中最多7個節點參與選舉。這是為了減少心跳請求的網路流量和選舉話費的時間,心跳每2秒傳送一次。
MongoDB叢集最多12個副本集節點,是因為沒必要一份資料複製那麼多份,備份太多反而增加了網路負載和拖慢了叢集效能;而最多7個節點參與選舉是因為內部選舉機制
節點數量太多就會導致1分鐘內還選不出主節點,凡事只要適當就好。

2)MongoDB心跳
       整個MongoDB叢集需要保持一定的通訊才能知道哪些節點活著哪些節點掛掉。MongoDB節點會向副本集中的其他節點每兩秒就會傳送一次pings包,如果其他節點在10秒
鍾之內沒有返回就標示為不能訪問。每個節點內部都會維護一個狀態對映表,表明當前每個節點是什麼角色、日誌時間戳等關鍵資訊。如果是主節點,除了維護對映
表外還需要檢查自己能否和叢集中內大部分節點通訊,如果不能則把自己降級為secondary只讀節點。

3)MongoDB同步
       MongoDB副本集同步分為初始化同步和keep複製。初始化同步指全量從主節點同步資料,如果主節點資料量比較大同步時間會比較長。而keep複製指初始化同步過後,
節點之間的實時同步一般是增量同步。初始化同步不只是在第一次才會被處罰,有以下兩種情況會觸發:
       [1]  secondary第一次加入,這個是肯定的。
       [2]  secondary落後的資料量超過了oplog的大小,這樣也會被全量複製。

=============================================================================================
何為oplog?
       oplog(應用日誌)儲存了資料的操作記錄,oplog主要用於副本,secondary複製oplog並把裡面的操作在secondary執行一遍。但是oplog也是mongodb的一個集合,儲存在local.oplog.rs裡;然而這個oplog是一個capped collection,也就是固定大小的集合,新資料加入超過集合的大小會覆蓋,所以這裡需要注意,跨IDC的複製要設定合適的oplogSize,避免在生產環境經常產生全量複製。oplogSize可以通過--oplogSize設定大小,對於Linux 和Windows 64位,oplog size預設為剩餘磁碟空間的5%

       在mongodb主從結構中,主節點的操作記錄成為oplog(operation log)。oplog儲存在一個系統資料庫local的集合oplog.$main中,這個集合的每個文件都代表主節點上執行的一個操作。從伺服器會定期從主伺服器中獲取oplog記錄,然後在本機上執行!對於儲存oplog的集合,MongoDB採用的是固定集合,也就是說隨著操作過多,新的操作會覆蓋舊的操作!主節點通過--oplogSize設定oplog的大小(主節點操作記錄儲存到local的oplog中)
=============================================================================================

       MongoDB同步也並非只能從主節點同步,假設叢集中3個節點,節點1是主節點在IDC1,節點2、節點3在IDC2,初始化節點2、節點3會從節點1同步資料。後面節點2、節點3會使用就近原則從當前IDC的副本集中進行復制,只要有一個節點從IDC1的節點1複製資料。設定mongodb、同步還要注意以下幾點:
       [1] secondary不會從delayed(延遲)和hidden(隱藏)成員上覆制資料。
       [2] 要是需要同步,兩個成員的buildindexes必須要相同無論是否是true和false。
       [3] buildindexes主要用來設定是否這個節點的資料用於查詢,預設為true。
       [4] 如果同步操作30秒都沒有反應,則會重新選擇一個節點進行同步。

4)Mongodb主節點的讀寫壓力過大如何解決?
       在系統早期,資料量還小的時候不會引起太大的問題,但是隨著資料量持續增多,後續遲早會出現一臺機器硬體瓶頸問題的。而MongoDB主打的就是海量資料架構,它不能解決海量資料怎麼行! mongodb的"分片"就是用來解決這個問題的。

       傳統資料庫怎麼做海量資料讀寫?其實一句話概括:分而治之。如下TaoBao早期的一個架構圖:

      上圖中有個TDDL,是TaoBao的一個資料訪問層元件,它主要的作用是SQL解析、路由處理。根據應用的請求的功能解析當前訪問的sql判斷是在哪個業務資料庫、哪個表訪問查詢並返回資料結果。具體如圖:

       說了這麼多傳統資料庫的架構,那NoSQL怎麼去做到了這些呢?MySQL要做到自動擴充套件需要加一個資料訪問層用程式去擴充套件,資料庫的增加、刪除、備份還需要程式去控制。一但資料庫的節點一多,要維護起來也是非常頭疼的。不過MongoDB所有的這一切通過它自己的內部機制就可以搞定的了。如下圖看看MongoDB通過哪些機制實現路由、分片:

從圖中可以看到有四個元件:mongos、config server、shard、replica set
      mongos,資料庫叢集請求的入口,所有的請求都通過mongos進行協調,不需要在應用程式新增一個路由選擇器,mongos自己就是一個請求分發中心,它負責把對應的資料請求請求轉發到對應的shard伺服器上。在生產環境通常有多mongos作為請求的入口,防止其中一個掛掉所有的mongodb請求都沒有辦法操作。

      config server,顧名思義為配置伺服器,儲存所有資料庫元資訊(路由、分片)的配置。mongos本身沒有物理儲存分片伺服器和資料路由資訊,只是快取在記憶體裡,配置伺服器則實際儲存這些資料。mongos第一次啟動或者關掉重啟就會從 config server 載入配置資訊,以後如果配置伺服器資訊變化會通知到所有的 mongos 更新自己的狀態,這樣      mongos 就能繼續準確路由。在生產環境通常有多個 config server 配置伺服器,因為它儲存了分片路由的後設資料,這個可不能丟失!就算掛掉其中一臺,只要還有存貨, mongodb叢集就不會掛掉。

      shard,這就是傳說中的分片了。上面提到一個機器就算能力再大也有天花板,就像軍隊打仗一樣,一個人再厲害喝血瓶也拼不過對方的一個師。俗話說三個臭皮匠頂個諸葛亮,這個時候團隊的力量就凸顯出來了。在網際網路也是這樣,一臺普通的機器做不了的多臺機器來做,如下圖:

      一臺機器的一個資料表 Collection1 儲存了 1T 資料,壓力太大了!在分給4個機器後,每個機器都是256G,則分攤了集中在一臺機器的壓力。也許有人問一臺機器硬碟加大一點不就可以了,為什麼要分給四臺機器呢?不要光想到儲存空間,實際執行的資料庫還有硬碟的讀寫、網路的IO、CPU和記憶體的瓶頸。在mongodb叢集只要設定好了分片規則,通過mongos運算元據庫就能自動把對應的資料操作請求轉發到對應的分片機器上。在生產環境中分片的片鍵可要好好設定,這個影響到了怎麼把資料均勻分到多個分片機器上,不要出現其中一臺機器分了1T,其他機器沒有分到的情況,這樣還不如不分片!

     replica set(副本集),其實上圖4個分片如果沒有 replica set 是個不完整架構,假設其中的一個分片掛掉那四分之一的資料就丟失了,所以在高可用性的分片架構還需要對於每一個分片構建 replica set 副本集保證分片的可靠性生產環境通常是 2個副本 + 1個仲裁(即一主一從一仲裁)

5)MongoDB 複製集節點增加移除及節點屬性配置
複製集(replica Set)或者副本集是MongoDB的核心高可用特性之一,它基於主節點的oplog日誌持續傳送到輔助節點,並重放得以實現主從節點一致。再結合心跳機制,當感知到主節點不可訪問或當機的情形下,輔助節點通過選舉機制來從剩餘的輔助節點中推選一個新的主節點從而實現自動切換。對於一個已經存在的MongoDB Replica Set叢集,可以對其進行節點的增加,刪除,以及修改節點屬性等等。

1)檢視當前版本環境
repSetTest:PRIMARY> db.version()
3.2.11

注意:利用rs.add和rs.remove是不用rs.reconfig來使用配置生效的。

2)刪除節點
repSetTest:PRIMARY> rs.remove("192.168.10.220:27000")
{ "ok" : 1 }

移除節點後的狀態資訊
repSetTest:PRIMARY> rs.status()     

移除後檢視配置檔案
repSetTest:PRIMARY> rs.config()
---------------------------------------------------------------------
repmore:PRIMARY> config = {_id:"repmore",members:[{_id:0,host:'192.168.10.220:27017',priority :2}]};     //刪除節點  
repmore:PRIMARY> rs.reconfig(config);   //使配置生效  
repmore:PRIMARY> rs.status();   //檢視節點狀態  
---------------------------------------------------------------------

3)增加節點
repSetTest:PRIMARY> rs.add("192.168.10.220:27000")
repSetTest:PRIMARY> rs.status()
repSetTest:PRIMARY> rs.config()
---------------------------------------------------------------------
或者使用下面方法新增節點:
repmore:PRIMARY> config = {_id:"repmore",members:[{_id:0,host:'192.168.10.220:27017',priority :2},{_id:1,host:'192.168.10.220:27018',priority:1}]};   //新增節點  
repmore:PRIMARY> rs.reconfig(config);    //使配置生效  
repmore:PRIMARY> rs.status();            //檢視節點狀態

注意:新增節點的replSet要和其他節點要一樣
---------------------------------------------------------------------

4)啟用Arbiter節點
repSetTest:PRIMARY> rs.remove("192.168.10.220:27000")
repSetTest:PRIMARY> rs.add({host:"192.168.10.220:27000",arbiterOnly:true})

對於Arbiter也可以使用rs.addArb函式來新增
> rs.addArb("192.168.10.220:27000")

6)MongoDB複製集狀態檢視

複製集狀態查詢命令
1)複製集狀態查詢:rs.status()
2)檢視oplog狀態: rs.printReplicationInfo()
3)檢視複製延遲:  rs.printSlaveReplicationInfo()
4)檢視服務狀態詳情:   db.serverStatus()

====================================================================
1)rs.status()
self:只會出現在執行rs.status()命令的成員裡
uptime:從本節點 網路可達到當前所經歷的時間
lastHeartbeat:當前伺服器最後一次收到其心中的時間
Optime & optimeDate:命令發出時oplog所記錄的操作時間戳
pingMs: 網路延遲
syncingTo: 複製源
stateStr:

可提供服務的狀態:primary, secondary, arbiter
即將提供服務的狀態:startup, startup2, recovering
不可提供服務狀態:down,unknow,removed,rollback,fatal

2)rs.printReplicationInfo()
log length start to end: 當oplog寫滿時可以理解為時間視窗
oplog last event time: 最後一個操作發生的時間

3).rs.printSlaveReplicationInfo()
複製進度:synedTo
落後主庫的時間:X secs(X hrs)behind the primary

4).db.serverStatus()
可以使用如下命令查詢需要用到的資訊
db.serverStatus.opcounterRepl
db.serverStatus.repl

5).常用監控專案:
QPS: 每秒查詢數量
I/O: 讀寫效能
Memory: 記憶體使用
Connections: 連線數
Page Faults: 缺頁中斷
Index hit: 索引命中率
Bakground flush: 後臺重新整理
Queue: 佇列

7)MongoDB複製集常用監控工具

1) mongostat
-h, --host   主機名或 主機名:埠
--port     埠號
-u ,--uername  使用者名稱(驗證)
-p ,--password   密碼(驗證)
--authenticationDatabase   從哪個庫進行驗證
--discover   發現叢集某個其他節點

[root@centos6-vm01 ~]# mongostat -h 192.168.10.220:27017  
[root@centos6-vm01 ~]# mongostat -h 192.168.10.220:27017  --discover  

mongostat重點關注的欄位:
getmore 大量的排序操作在進行
faults 需要的資料不在記憶體中
locked db 鎖比例最高的庫
index miss 索引未命中
qr|qw 讀寫產生佇列,供求失衡

2) mongostop:與mongostat基本一樣
-h, --host   主機名或 主機名:埠
--port     埠號
-u ,--uername  使用者名稱(驗證)
-p ,--password   密碼(驗證)
--authenticationDatabase   從哪個庫進行驗證

8)對於Secondary來說有幾個比較重要的屬性:Priority優先順序、Vote投票節點、Hidden節點、Delayed節點

設定節點的優先順序別(Priority)
Priority=0 即優先順序為0的節點。字面上來說,許可權為0。擁有最低的許可權。已然是Secondary了,許可權還最低,啥影響呢?之前說過,mongoDB的副本集中是有投票機制的,如果一個Primary不可達,那麼所有的Secondary會聯合起來投票選舉,選出心目中的新的Primary。因為只有Primary才能接收Writes的操作,所以Primary在一個mongoDB的叢集中是必須的。下圖展示了一個在兩個IDC中存放Primary,Secondary,以及一個Priority=0的Secondary的場景(關於這個存放方式以及奇數偶數。

優先順序為0的節點的特點

1)此節點喪失了當選Primary的機會。永遠不會上位。
2)此節點正常參與Primary產生的oplog的讀取,進行資料備份和命令執行。
3)此節點正常參與客戶端對於資料的讀取,進行擔當負載均衡的工作。
4)此節點雖然不能當選Primary但是卻可以投票,很民主。

Priority=0在mongoDB中的解釋就是一個Standby,可投票不可參選,又幹活又負載。有點像日本議會黨派中剛入黨派的小嘍囉,可以參與自己黨派黨首的選舉,還要幹好多活,外面民眾開罵還得擋著,但就是不可能當選黨首。

1)優先順序用於確定一個傾向成為主節點的程度。取值範圍為0-100
2)Priority 0節點的選舉優先順序為0,不會被選舉為Primary,這樣的成員稱為被動成員
3)對於跨機房複製集的情形,如A,B機房,最好將『大多數』節點部署在首選機房,以確保能選擇合適的Primary
4)對於Priority為0節點的情況,通常作為一個standby,或由於硬體配置較差,設定為0以使用不可能成為主

如下示例,在新增節點的時候設定該節點的優先順序別
repSetTest:PRIMARY> rs.add({"_id":3,"host":"localhost:27000","priority":1.5})

也可以通過下面的方式修改優先順序別
repSetTest:PRIMARY> var config=rs.config()
repSetTest:PRIMARY> config.members[2].priority=2
2
repSetTest:PRIMARY> rs.reconfig(config)
{ "ok" : 1 }

投票節點(Vote)

1)投票節點不儲存資料副本,不可能成為主節點。
2)Mongodb 3.0裡,複製整合員最多50個,參與Primary選舉投票的成員最多7個。
3)對於超出7個的其他成員(Vote0)的vote屬性必須設定為0,即不參與投票。

 

隱藏節點(Hidden)
字面上來說,隱藏。這個隱藏式對客戶端的隱藏,客戶端如果要讀取Secondary的資料,永遠無法讀取Hidden節點的資料,因為設定了Hidden的這個節點對於客戶端是透明的,不可見。但是,對於自己的Secondary的群體和Primary來說都是可見的,所以,Hidden依然可以投票,依然要按照oplog進行命令的複製,只是,不參與負載了。Hidden屬性的前提是必須是一個Priority=0的節點,所以會具備一些優先順序=0的特點,具體如下。

Hidden節點的特點

1)此節點喪失了當選Primary的機會。永遠不會上位。
2)此節點正常參與Primary產生的oplog的讀取,進行資料備份和命令執行。
3)此節點正常參與客戶端對於資料的讀取,進行擔當負載均衡的工作。
4)此節點不參與客戶端對於資料的讀取,不進行負載均衡
5)此節點雖然不能當選Primary但是卻可以投票,也很民主。

第3條特徵體現出它與Priority=0的不同地方,第4條特徵表現出它比0優先順序多出來的特性。如果節點是Hidden,它不參與負載,那麼空閒出來的時間可以做一些賦予給它的特殊任務,比如資料備份等等。到應用場景的時候會有用處。

1)Hidden節點不能被選為主(Priority為0),並且對Driver不可見。
2)因Hidden節點不會接受Driver的請求,可使用Hidden節點做一些資料備份、離線計算的任務,不會影響複製集的服務
3)隱藏節點成員建議總是將其優先順序設定為0(priority 0)
4)由於對Driver不可見,因此不會作為read preference節點,隱藏節點可以作為投票節點
5)在分片叢集當中,mongos不會同隱藏節點互動

> cfg = rs.conf()
> cfg.members[2].priority = 0
> cfg.members[2].hidden = true
> rs.reconfig(cfg)

檢視設定為隱藏階段後的屬性
repSetTest:SECONDARY> db.isMaster()
{
"hosts" : [
       "localhost:27000",
       "localhost:27001"
                    ],
                    "setName" : "repSetTest",
                    "setVersion" : 2,
                    "ismaster" : false,
                    "secondary" : true,
                    "primary" : "localhost:27000",
                    "passive" : true,
                    "hidden" : true,     //此處表明當前節點為隱藏節點
                    "me" : "localhost:27002",
                    "maxBsonObjectSize" : 16777216,
                    "maxMessageSizeBytes" : 48000000,
                    "maxWriteBatchSize" : 1000,
                    "localTime" : ISODate("2017-03-06T10:15:48.257Z"),
                    "maxWireVersion" : 4,
                    "minWireVersion" : 0,
                    "ok" : 1
}               

延遲節點(Delayed)
字面上來說,遲延。遲延代表此節點的資料與Primary的資料有一定的遲延,通過設定一個遲延的屬性來確定。假設,Primary的資料是10:00的最新資料,我們設定了一個3600秒的遲延引數,那麼這個帶有遲延的節點的資料或者說命令執行情況(在oplog中)應該只到9:00為止。與主節點有1小時的遲延。有些人可能會問,我們設計分散式資料庫要的就是資料能夠儘量避免遲延來達到一致,這樣才能更好的提供服務,為什麼要刻意製造遲延呢?試想這個場景:一個豬一樣的隊友在mongoDB的Replica叢集上面執行了一個Drop操作,這個操作幹掉了你的Primary的Collection,這個Drop同時被記錄到oplog中去,其他的Secondary看到這個oplog後爭相執行,各自幹掉了自己的Collection,你苦心儲存的資料就這麼消失了。。。再怎麼抽這個隊友沒用啊。所以,主動的過失避免就顯得格外重要。如果你有一個Delayed節點,有一個1000秒的遲延,那麼在你發現這個miss之後還有足夠的時間可以響應去不讓這個Delayed節點執行錯誤的command,從而挽回你的損失。具體如下。

Delayed節點的特點

1)此節點必須是一個Priority=0且為Hidden的節點,因為Hidden必須是Priority=0的,所以此節點必須是Hidden的。
2)此節點雖然又遲延又Hidden但是還是可以投票,也很民主。

Delayed節點的最大作用是用來容人為的災,豬一樣的操作,驢一樣的動作,在Delayed節點可以把損失降到最低。當然,如果你在Delayed時間經過後發現了錯誤,那麼只能"呵呵"了。Delayed的時間設定一定要大於響應時間,比如從Primary的oplog寫到Secondary需要1秒,那麼Delayed必須大於等於1秒,小於1秒的的話只能是一個不可及狀態。

延遲節點包含複製集的部分資料,是複製集資料的子集
延遲節點上的資料通常落後於Primary一段時間(可配置,比如1個小時)。
當人為錯誤或者無效的資料寫入Primary時,可通過Delayed節點的資料進行回滾

延遲節點的要求:
1)優先順序別為0(priority 0),避免參與primary選舉
2)應當設定為隱藏節點(以避免應用程式查詢延遲節點)
3)可以作為一個投票節點,設定 members[n].votes 值為1

延遲節點注意事項:       
1)延遲時間應當等於和大於維護視窗持續期
2)應當小於oplog容納資料的時間視窗 

repSetTest:SECONDARY> cfg = rs.conf()
repSetTest:SECONDARY> cfg.members[2].priority = 0
repSetTest:SECONDARY> cfg.members[2].hidden = true
repSetTest:SECONDARY> cfg.members[2].slaveDelay = 3600
repSetTest:SECONDARY> rs.reconfig(cfg)

repSetTest:SECONDARY> db.isMaster()
{
                    "hosts" : [
                            "localhost:27000",
                            "localhost:27001"
                    ],
                    "setName" : "repSetTest",
                    "setVersion" : 3,
                    "ismaster" : false,
                    "secondary" : true,
                    "primary" : "localhost:27000",
                    "passive" : true,
                    "hidden" : true,
                    "slaveDelay" : 3600,    //此處表面當前節點具有延遲屬性,為延遲節點
                    "me" : "localhost:27002",
                    "maxBsonObjectSize" : 16777216,
                    "maxMessageSizeBytes" : 48000000,
                    "maxWriteBatchSize" : 1000,
                    "localTime" : ISODate("2017-03-06T10:19:57.148Z"),
                    "maxWireVersion" : 4,
                    "minWireVersion" : 0,
                    "ok" : 1
}

mongodb副本集修改配置問題

因ip地址被佔用,需要重新設定ip地址,這時需要修改副本集中的IP地址配置:
1)檢視配置rs.config();需要找到primary主機,在該主節點伺服器上才有許可權修改配置
2)rs.remove("ip:port") 移除原配置檔案中的已經變更地址的主機
3)rs.add("ip:port")  新增新的地址主機
4)設定priority優先順序
> var config = rs.config()
> config.members[2].priority=2
> rs.reconfig(config)         //重新更新配置

9)其他維護說明

一、新增副本整合員
1)登入primary
2)
>use admin 
>rs.add("new_node:port") 
或者
>rs.add({"_id":4,"host":"new_node:port","priority":1,"hidden":false})   
3)
>use admin
>rs.addArb("new_node:port") 
或者 
>rs.addArb({"_id":5,"host":"new_node:port"})
或者
>rs.add({'_id':5,"host":"new_node:port","arbiterOnly":true})

仲裁者唯一的作用就是參與選舉,仲裁者並不儲存資料,也不會為客戶端提供服務。成員一旦以仲裁者的身份加入副本集中,它就永遠只能是仲裁者,
無法將仲裁者重新配置為非仲裁者,反之亦然。最多隻能有一個仲裁者每個副本集中。

溫馨提示:
如果複製集中 priority=1 (預設),呼叫rs.add("new_node:port") 該命令 會產生 主從切換 即選舉操作;
如果複製集中 priority=1 (預設),直接呼叫rs.remove("new_node:port") 該命令 也會產生 主從切換 ;
 

二、刪除副本整合員
1)登入要移除的目標mongodb例項;
2)利用shutdownServer()命令關閉例項;即 db.shutdownServer()
3)登入複製集的primary;
4)
primary>use admin
primary>rs.remove("del_node:port");
 

三、修改成員的優先順序及隱藏性
1)登入primary
2)
>use admin 
>conf=rs.conf()
>conf.members[1].priority=[0-1000]
>conf.members[1].hidden=true      #priority必須為0
>conf.members[9].tags={"dc":"tags_name1"} 
>rs.reconfig(conf);      # 強制重新配置 rs.reconfig(conf,{"force":true})

成員的屬性有下列選項
  [, arbiterOnly : true]
      [, buildIndexes : <bool>]
      [, hidden : true]
      [, priority: <priority>]
      [, tags: {loc1 : desc1, loc2 : desc2, ..., locN : descN}]
      [, slaveDelay : ]#秒為單位。
      [, votes : 

如果該成員要設定為 隱藏(hidden:true) 或延遲(slaveDelay:30) 則其優先順序priority必須設定為 0;
也就是說 隱藏成員和延遲成員及buildIndexs:false的成員 的優先順序別一定必須是0 即priority=0.
優先順序為0的成員不能發起選舉操作。
只要優先順序>0即使該成員不具有投票資格,也可以成為主節點。
如果某個節點的索引結構和其他節點上的索引結構不一致,則該節點就永遠不會變為主節點。
優先順序用於表示一個成員渴望成為主節點的程度。優先順序的取值範圍是[0-100],預設為1。優先順序為0的成員永遠不能成為主節點。
使用rs.status()和rs.config()能夠看到隱藏成員,隱藏成員只對rs.isMaster()不可見。客戶端連線到副本集時,會呼叫rs.isMaster()
來檢視可用成員。將隱藏成員設定為非隱藏成員,只需將配置中的hidden設定為false,或刪除hidden選項。
每個成員可以擁有多個標籤tags {“dc":"tags_name2",qty:"tag_name3"}
votes:0 代表阻止這些成員在選舉中投主動票,但是他們仍然可以投否決票。
 
修改副本整合員配置時的限制:
1)不能修改_id;
2)不能講接收rs.reconfig命令的成員的優先順序設定為 0;
3)不能將仲裁者成員變為非仲裁者成員,反正亦然;
4)不能講 buildIndexes:false 改為 true;
 
 
四、檢視副本整合員資料同步(延遲)情況
>db.printReplicationInfo();
>db.printSlaveReplicationInfo();#最好在secondary上執行
>rs.printReplicationInfo()
>rs.printSlaveReplicationInfo()
>use local>db.slaves.find()

在主節點上跟蹤延遲:
local.slaves該集合儲存著所有正從當前成員進行資料同步的成員,以及每個成員的資料新舊程度。
登入主節點
>use local
>db.slaves.find()、
檢視其中每個成員對應的"syncedTo":{"t":9999999,"i":32} 部分即可知道資料的同步程度。
"_id"欄位的值是每個當前成員伺服器識別符號。可以到每個成員的local.me.find()檢視本伺服器識別符號。

1)
如果多臺伺服器擁有相同的_id識別符號,則依次登入每臺伺服器成員,刪除local.me集合(local.me.dorp()),然後重啟mongodb,
重啟mongod後,mongod會使用新的“_id”重新生成local.me集合。
 
2)
如果伺服器的地址改變但_id沒有變,主機名變了,該情況會在本地資料庫的日誌中看到重複鍵異常(duplicate key exception)。
解決方法是:刪除local.slaves集合即可,不需要重啟mongod。
 
因為mongod不會清理local.slaves集合,故里面的資料可能不準確或過於老舊,可將整個集合刪除。當有新的伺服器將當前成員作為
複製源時,該集合會重新生成。如果在主節點中看到了某個特定的伺服器在該集合中有多個文件,即表示備份節點之間發生了複製鏈,
該情況不影響資料同步,只是把每個備份節點的同步源告訴主節點。
 
 
刪除local.me集合,需要重新啟動mongod,mongod啟動時會使用新的 _id重新生成local.me集合。
 
刪除local.slaves集合,不用重啟mongod。該集合中的資料是記錄該成員被作為同步源的伺服器的資料。該集合用於報告副本集狀態。
刪除後不久如果有新的節點成員將該伺服器節點作為複製源,該集合就會重新生成。
 

五、主節點降為secondary
>use admin
>rs.stepDown(60)#單位為 秒
 

六、鎖定指定節點在指定時間內不能成為主節點(阻止選舉)
>rs.freeze(120)#單位為 秒
釋放阻止
>rs.freeze(0)

 
七、強制節點進入維護模式(recovering)
可以通過執行replSetMaintenanceMode命令強制一個成員進入維護模式。
例如自動檢測成員落後主節點指定時間,則將其轉入維護模式:
>function maybeMaintenanceMode(){
var local=db.getSisterDB("local");
if (!local.isMaster().secondary)
{return;
)
var last=local.oplog.rs.find().sort({"$natural":-1}).next();
var lasttime=last['ts']['t'];
if (lasttime<(new date()).getTime()-30)
{db.adminCommand({"replSetMaintenanceMode":true});
}
};

將成員從維護模式轉入正常模式。即恢復:
>db.adminCommand({"replSetMaintenanceMode":false});
 

八、阻止建立索引(不可再修改為可以建立索引,故慎重考慮)
通常會在備份節點的延遲節點上設定阻止建立索引。因為該節點通常只是起到備份資料作用。設定選項 buildIndexs:false即可。該選項是永久性的。
如果要將不建立索引的成員修改為可以建立索引的成員,那麼必須將這個成員從副本集中移除,再刪除它上的所有資料,最後再將其重新新增到副本集中。
並且允許其重新進行資料同步。該選項也要求成員的優先順序為 0.
 

九、指定複製源(複製鏈) 檢視複製圖譜
使用db.adminCommand({"replSetGetStatus":1})['syncingTo'] 可以檢視複製圖譜(每個節點的同步源);
在備份節點上執行 rs.status()['sysncingTo'] 同樣可以檢視複製圖譜(同步源);
mongodb是根據ping時間來選擇同步源的,會選擇一個離自己最近而且資料比自己新的成員作為同步源。
可以使用replSetSyncFrom 命令來指定複製源或使用輔助函式rs.sysncFrom()來修改複製源。
db.adminCommand({"replSetSyncFrom":"server_name:port"});
 
副本集預設情況下是允許複製鏈存在的,因為這樣可以減少網路流量。但也有可能
花費是時間更長,因為複製鏈越長,將資料同步到全部伺服器的時間有可能就越長(比如每個備份節點都比前一個備份節點稍微舊點,這樣就得
從主節點複製資料)。

解決方法:
1)手動改變複製源
登入備份節點:
>use admin
>db.adminCommand({"replSetSyncFrom":"新複製源"})
或者
>rs.syncFrom("新複製源")
副本集中的成員會自動選擇其他成員作為複製源。這樣就會產生複製鏈。
如果一個備份節點從另一個備份節點(而非主節點)複製資料時,就會形成複製鏈。
複製鏈是可以被禁用的,這樣就可以強制要求所有備份節點都從主節點複製資料。
 
禁用複製鏈:即禁止備份節點從另一個備份節點複製資料。
>var config=rs.config()
>config.settings=config.settings ||{}
>config.settings.chainingAllowed=false
>rs.reconfig(config);
 

十、強制修改副本整合員
>var config=rs.config()
>config.member[n].host=...
>config.member[n].priority=...
.....
>rs.reconfig(config,{"force":true})
 

十一、修改Oplog集合的大小
如果是主節點,則先將primary 降為 secondary。最後確保沒有其他secondary 從該節點複製資料。rs.status()
1)關閉該mongod服務 use admin >db.adminCommand({shutdownServer:1});
2)以單機方式重啟該mongod(註釋掉 配置檔案中的 replSet    shardsvr ,修改埠號)
3)將local.oplog.rs中的最後一條 insert 操作記錄儲存到臨時集合中
> use local
>var cursor=db.oplog.rs.find({"op":"i"});
>var lastinsert=cursor.sort({$natural:-1}).limit(1).next();
>db.templastop.save(lastinsert);
>db.templastop.findOne()#確保寫入
4)將oplog.rs 刪除: db.oplog.rs.drop();
5)建立一個新的oplog.rs集合: db.createCollection("oplog.rs":{"capped":true,"size":10240});
6)將臨時集合中的最後一條insert操作記錄寫回新建立的oplog.rs:
>var temp=db.templastop.findOne();
>db.oplog.rs.insert(temp);
>db.oplog.rs.findOne() #確保寫回,否則 該節點重新加入副本集後會刪除該節點上所有資料,然後重新同步所有資料。
7)最後將該節點以副本整合員的身份重新啟動即可。
 

十二、為複製整合員設定選項
即當執行rs.initiate(replSetcfg) 或執行 rs.add(membercfg)選項時,需要提供描述複製整合員的特定配置結構:
{
_id:replSetName,
members:
[
{_id:<number>,host:<hostname|ip[:port]>,
[priority:<priority>,]#預設值為1.0.即選項的值是浮點型
[hidden:true,]#該元素將從db.isMaster()的輸出中隱藏該節點。
[arbiterOnly:true,]#預設值為 false
[votes:<n>,]#預設值為1 。改選項的值為整形
[tags:{documents},]
[slaveDelay:<seconds>,]
[buildIndexes:true,]#預設值為 false。該選項用於禁止建立索引。
}],
settings:{
[chainingAllowed:<boolen>,]#指定該成員是否允許從其他輔助伺服器複製資料。預設值為 true
[getLastErrorModes:<modes>,]#模式:用於自定義寫顧慮設定
[getLastErrorDefaults:<lasterrdefaults>,]#預設值:用於自定義寫顧慮設定。
}
}
以上是複製集的完整的配置結構。最高階的配置結構包括3級:
_id、members、settings。
_id是複製集的名稱,與建立複製整合員時時候用的 --replSet命令選項時提供的名稱一樣。
members是陣列,由一個描述每個成員的集合組成;這是新增單個伺服器到集合中時,應該在rs.add()命令中提供的成員機構;
settings也是陣列,該settings陣列包含應用到整個複製集的選項。這些選項可以設定複製整合員間如何通訊。
 

十三、Rollback
mongodb只支援小於300M的資料量回滾,如果大於300M的資料需要回滾或要回滾的操作在30分鐘以上,只能是手動去回滾。會在mongodb日誌中報以下錯誤:
[replica set sync] replSet syncThread: 13410 replSet too much data to roll back
經量避免讓rollback發生。方法是:使用 複製的 寫顧慮(Write Concern)規則來阻止回滾的發生。
如果發生了回滾操作,則會在mongodb資料檔案目錄下產生一個以database.collection.timestamp.bson的檔案。檢視該檔案的內容用 bsondump 工具來檢視。
 

十四、讀偏好設定(ReadPreferred)
讀取偏好是指選擇從哪個複製整合員讀取資料的方式。可以為驅動指定5中模式來設定讀取偏好。
readPreference=primary|primaryPreferred|secondary|secondaryPreferred|nearest
setReadPreferred()命令設定讀取偏好。
 
primary:只從主伺服器上讀取資料。如果使用者顯式指定使用標籤讀取偏好,該讀取偏好將被阻塞。這也是預設的讀取偏好。
primaryPreferred:讀取將被重定向至主伺服器;如果沒有可用的主伺服器,那麼讀取將被重定向至某個輔助伺服器;
secondary:讀取將被重定向至輔助伺服器節點。如果沒有輔助伺服器節點,該選項將會產生異常;
secondaryPreferred:讀取將被重定向至輔助伺服器;如果沒有輔助伺服器,那麼讀取將被重定向至主伺服器。該選項對應舊的“slaveOK”方法;
nearest:從最近的節點讀取資料,不論它是主伺服器還是輔助伺服器。該選項通過網路延遲決定使用哪個節點伺服器。
 

十五、寫顧慮設定(Write Concern)
寫顧慮類似讀取偏好,通過寫顧慮選項可以指定在寫操作被確認完成前,資料必須被安全提交到多少個節點。
寫顧慮的模式決定了寫操作時如何持久化資料。引數“w”會強制 getLastError等待,一直到給定資料的成員都執行完了最後的寫入操作。w的值是包含主節點的。
寫顧慮的5中模式:
w=0或不確定:單向寫操作。寫操作執行後,不需要確認提交狀態。 
w=1或確認:寫操作必須等到主伺服器的確認。這是預設行為。
w=n或複製集確認:主伺服器必須確認該寫操作。並且n-1個成員必須從主伺服器複製該寫入操作。該選項更強大,但是會引起延遲。
w=majority:寫操作必須被主伺服器確認,同時也需要集合中的大多數成員都確認該操作。而w=n可能會因為系統中斷或複製延遲引起問題。
j=true日誌:可以與w=寫顧慮一起共同指定寫入操作必須被寫入到日誌中,只有這樣才算是確認完成。
wtimeout:避免getLastError一直等待下去,該值是命令的超時時間值,如果超過這個時間還沒有返回,就會返回失敗。該值的單位是毫秒。如果返回失敗,
值在規定的時間內沒有將寫入操作複製到"w"個成員。
該操作只對該連線起作用,其他連線不受該連線的"w"值限制。
db.products.insert(
{ item : "envelopes" , qty : 100 , type : "Clasp" },
{ writeConcern : { w : 2 , wtimeout : 5000 } }
)
wtimeout#代表5秒超時
 
修改預設寫顧慮
cfg = rs.conf()
cfg.settings = {}
cfg.settings.getLastErrorDefaults = { w: "majority" , wtimeout: 5000 }
rs.reconfig(cfg)
 
設定寫等待
db.runCommand({"getLastError":1,w:"majority"})
或
db.runCommand({"getLastError":1,"w":"majority","wtimeout":10000})
即,表示寫入操作被複制到了多數個節點上(majority 或 數字),這時的 w會強制 getLastError等待,一直到給定數量的成員執行完了最後的寫入操作。
    而wtimeout是指超過這個時間沒有返回則返回失敗提示(即無法在指定時間內將寫入操作複製到w個成員中),getLastError並不代表寫操作失敗了,
    而是代表在指定給定wtimeout時間內沒有將寫入操作複製到指定的w個成員中。w是限制(控制)寫入 速度,只會阻塞這個連線上的操作,其他連線上
    的操作不受影響。
 

十六、讀取偏好和寫顧慮中使用標籤(tags)
 

十七、選舉機制
1)自身是否能夠與主節點連通;
2)希望被選件為主節點的備份節點的資料是否最新;
3)有沒有其他更高優先順序的成員可以被選舉為主節點;
4)如果被選舉為主節點的成員能夠得到副本集中“大多數”成員的投票,則它會成為主節點,如果“大多數”成員中只有一個否決了本次選舉,則本次選舉
失敗即就會取消。一張否決票相當於10000張贊成票。
5)希望成為主節點的成員必須使用複製將自己的資料更新為最新;
 

十八、資料初始化過程
1)首先做一些記錄前的準備工作:選擇一個成員作為同步源,在local.me集合中為自己建立一個識別符號,刪除索引已存在的資料庫,以一個全新的狀態
開始進行同步;該過程中,所有的資料都會被刪除。
2)然後克隆,就是將同步源的所有記錄全部複製到本地。
3)然後就進入oplog同步的第一步,克隆過程中的所有操作都會被記錄到oplog中。
4)接下來就是oplog同步過程的第二步,用於將第一個oplog同步中的操作記錄下來。
5)截止當前,本地的資料應該與主節點在某個時間點的資料集完全一致了,可以開始建立索引了。
6)若當前節點的資料仍然落後同步源,那麼oplog同步過程的最後一步就是將建立索引期間的所有操作全部同步過出來,防止該成員成為備份節點。
7)現在當前成員已經完成了初始化資料的同步,切換到普通狀態,這時該節點就可以成為備份節點了。
 
十九、mongodb3.0 建議開啟的設定
# echo never > /sys/kernel/mm/transparent_hugepage/enabled
# echo never > /sys/kernel/mm/transparent_hugepage/defrag
執行上面兩命令後只是當前起作用。如果重啟mongod服務後 就失效。永久起效則
寫入到 /etc/rc.local
即 
 
二十、修改伺服器hostname名
1)首先修改 secondary 伺服器的 hostname;然後 stop secondary;
2)重啟 secondary 以修改後的新hostname;
3)登入 primary ;
4)用rs.reconfig()命令修改 複製集的配置資訊;
>conf=rs.conf()
>conf.members[x].host='new_address:27017'
>rs.reconfig(conf);
 
二十一、生成 keyfile檔案
# openssl rand -base64 666 > /opt/mongo/conf/MongoReplSet_KeyFile
# chown mongod.mongod /opt/mongo/conf/MongoReplSet_KeyFile
# chmod 600 /opt/mongo/conf/MongoReplSet_KeyFile

相關文章