MongoDB實戰-如何在Windows環境下管理副本集

perfecttshoot發表於2017-08-30

     雖然MongoDB提供了自動化功能,但副本集其實還有些潛在的複雜配置選項,接下來,我們將詳細介紹這些選項。為了讓配置簡單一些,我也會就哪些選項是能被安全忽略的給出建議。

1. 配置細節

    這裡我會介紹一些與副本集相關的mongod啟動選項,以及副本集配置文件的結構

(1)  複製選項

     先前,學習瞭如何使用shell的rs.initiate()和rs.add()方法初始化副本集。這些方法很方便,但它們隱藏了某些副本集配置選項。這裡你將看到如何使用配置文件初始化並修改一個副本集的配置。

    配置文件裡說明了副本集的配置。要建立配置文件,先為_id新增一個值,要和傳給-replSet引數的值保持一致。

config={_id:"mySet",members:[]}
members也是配置文件的一部分,可以像下面這樣定義:

config.menbers.push({_id:0,host:'arete:40000'})
config.menbers.push({_id:1,host:'arete:40001'})
config.menbers.push({_id:2,host:'arete:40002',arbiterOnly:true})
隨後,將config文件作為rs.initiate()的第一個引數,完成副本集的初始化

       嚴格來說,該文件應該包含以下部分:包含副本集名稱的_id欄位、members陣列(可以指定3-12個成員),以及一個可選的子文件(用來設定某些全域性變數)。示例副本集中使用了最少的配置引數,外加可選的arbiterOnly設定。

      文件中要求有一個_id欄位,與副本集的名稱相匹配。初始化命令會驗證每個成員節點在初始化時是否都在-replSet選項裡使用了這個名稱。每個副本整合員都有一個_id欄位,包含從0開始遞增的整數,還要有一個host欄位,提供主機名和可選的埠。

      這裡通過rs.initiate()方法初始化了副本集,它是對replSetInitiate命令的簡單封裝。因此,也可以通過如下的方式啟動副本集:

db.runCommand({replSetInitiate:config})
     config就是一個簡單的變數,持有配置文件。一旦初始化完畢,每個集合成員都會在local資料庫的system.replSet集合裡儲存一份配置文件的副本。如果查詢該集合,你會看到該文件現在有一個版本號了。每次修改副本集的配置,都必須遞增這一版本號。

     要修改副本集的配置,有一個單獨的方法replSetReconfig,它接受一個新的配置文件。新文件可以新增或刪除集合成員,還可以修改成員說明和全域性配置選項。修改配置文件、增加版本號、以及把它傳遞給replSetReconfig方法,這個過程較為麻煩,所以在shell裡有一些輔助方法來簡化這個過程,可以用過rs.help()獲取輔助方法。

     需要牢記一點,無論何時,要是重新配置副本集導致重新選舉新的主節點,那麼所有客戶端的連線都會被關閉。這是為了確保客戶端向從節點傳送fire-and-forget風格的寫操作。

     如希望通過驅動配置副本集,可以使用rs.add方法,可以在shell中輸入rs.add來查詢使用方法。

(2) 配置文件選項

     到目前為止,我們都侷限在最簡單的副本集配置文件裡。但這些文件還支援很多選項,無論是針對副本整合員還是整個副本集。我們將從成員選項開始進行介紹。

    _id(必填):唯一的遞增整數,表示成員ID。這些_id從0 開始,每新增一個成員就加1.

    host(必填):儲存了成員主機名的字串,帶有可選埠號。如果提供了埠號,需用冒號與主機名分隔(例如arete:30000)。如果沒有指定埠號,則預設使用埠27017。

    arbiterOnly:一個布林值,true或false,標明該成員是否是仲裁節點。仲裁節點只儲存配置資料。它們是輕量級成員,參與主節點選舉但本身不參與複製。

     priority: 一個0-1000的整數,幫助確定該節點被選舉為主節點的可能性。在副本集初始化和故障轉移時,集合會嘗試將優先順序最高的節點推選為主節點,主要它的資料是最新的。也有一些場景裡,你希望某個節點永遠不會成為主節點(比方說:一個位於從資料中心的災難恢復節點)。在這些情況中,可以把優先順序設定為0.遇到isMaster()命令,帶有優先順序0的節點會被標記為被動節點,永遠不會被選舉為主節點。

     votes: 所有副本整合員預設都有一票。votes設定讓你能給某個單獨的成員更多投票。如果要使用該選項,請格外小心。首先,在各個成員的投票數不一致時,很難推測副本集的故障轉移行為。其次,絕大多數生產部署環境裡,每個成員只有一票的配置工作都得十分理想。因此,要是確定要修改某個指定成員的投票數,一定要經過深思熟慮,並仔細模擬各種故障場景。

     hidden:一個布林值,如果為true,在isMaster命令生成的響應裡則不會出現該節點。因為MongoDB驅動依賴於isMaster來獲取副本集的拓撲情況,所以隱藏一個成員能避免驅動自定訪問它。該設定能通buildIndexes協同使用,使用時必須有slaveDelay

    buildIndexes 一個布林值,預設為true,確定該成員是否會構建索引。僅當該成員永遠不會成為主節點時(那些優先順序為0的節點),才能將其設定為false。該選項是為那些只會用作備份的節點設計的。如果備份索引很重要,那就不要使用它

     slaveDelay:指定從節點要比主節點延遲的秒數。該選項只能用於永遠不會成為主節點的節點。所以如果把slaveDelay設定為大於0的值,務必保證將優先順序設定為0。可以通過延遲從節點來抵禦某些使用者錯誤。例如,如果一個延遲30分鐘的從節點,管理員不小心刪除了資料庫,那麼問題擴散之前,你有30分鐘做出反應。

     tags:包含一個任意鍵值對集合的文件,通常用來標識成員在某個資料中心或機架的位置。標籤被用來指定寫關注的粒度和讀設定。

     以上是所有針對單個副本整合員的選項。還有兩個全域性副本集配置引數,位於settings鍵中。在副本集配置文件中,他們是這樣的:

{
settings:{
getLastErrorDefaults:{w:1},
getLastErrorMode:{multiDC:{dc:2}}
}
}
    getLastErrorDefaults 當客戶端不帶引數呼叫getLastError時,預設的引數是由這個文件指定的。要謹慎對待該選項,因為它可能設定了驅動中getLastError的全域性預設值,你想象一種情況,應用程式開發者呼叫了getLastError,但他沒有意識到管理員在伺服器上指定了一個預設值。簡單起見,要指定所有寫操作都要在500ms內複製到至少兩個成員上。可以像這樣進行配置:

settings:{getLastErrorDefaults:{w:2,wtimeout:500}}
       getLastErrorModes:為getLastError命令定義了額外模式的文件,這個特定依賴於副本集狀態。

2. 副本集狀態

      通過replSetGetStatus命令能夠看到副本集機器成員的狀態。或者在shell中通過rs.status()輔助方法。結果文件標識了現存成員及其各自的狀態,正常執行時間和oplog時間。瞭解副本整合員的狀態是非常重要的。

狀態 狀態字串 說明
0 STARTUP 表示節點正在通過ping與其他節點溝通,
分享配置資料
1 PRIMARY 這是主節點,並且副本集中只有一個主節點
2 SECONDARY 這是隻讀從節點,該節點在故障轉移時可能
會成為主節點,當且僅當其優先順序大於0
並且沒有被標記為隱藏時
3 RECOVERING 該節點不能用於讀寫操作,通常會在故障轉移或
新增新節點後看到這個狀態。在恢復時,資料檔案通常正在
同步中,可以檢視正在恢復的節點的日誌進行驗證
4 FATAL 網路連線仍然建立著,但節點對ping沒響應了,節點被標記為
FATAL,通常說明託管該節點的機器發生了致命錯誤
5 STARTUP2 初始化資料檔案正在同步中
6 UNKNOWN 還在等待建立網路連線
7 ARBITER 該節點時仲裁節點
8 DOWN 該節點早些時候還能訪問並正常執行,但現在“心跳”檢測沒
應答了
9 ROLLBACK 正在進行回滾
當所有節點的狀態都是1,2,7的時候,並且至少一個節點是主節點時,可以認為副本集是穩定且線上的。可以在外部指令碼里使用replSetGetStatus命令來監控全域性狀態,複製延時以及正常執行時間,建議在生產環境部署中這樣做。

3.故障轉移與恢復

      當配置中所有成員都能和其他成員通訊時,副本集就能上線了。每個節點預設都有一票投票,那些投票最終會幫助得出投票結果,選出主節點。這意味著只要有兩個節點(和投票)就能啟動副本集了。初始的投票數還能決定發生故障轉移時,什麼才能構成多數節點。

     讓我們假設配置了一個由三個完整副本(沒有仲裁節點)組成的副本集,這也達到了自動故障轉移的推薦最小配置。如果主節點發生了故障,剩下的從節點仍能互相看到對方,那麼就能選出新的主節點。如何選擇呢?擁有最新oplog(或者更高優先順序)的從節點會被選為主節點。
      故障模式與恢復

     恢復是在故障後將副本集還原到原始狀態的過程。有兩大類故障需要處理。第一類包含所謂的無損故障(clean failure),仍然可以認為該節點的資料檔案是完好無損的。網路分割槽(network partition)就是一個例子,若某個節點失去了與其他節點的連線,你只需要等待重新建立連線就行了,被分割開的節點也會重新變為副本集中的成員。還有一個類似的情況,某個節點的mongod進行出於某些原因終止了,但它恢復正常的線上狀態。同樣的,一旦程式重啟,就能重新加入集合了。

     第二類故障包含所有明確故障(categorical failure),某個節點的資料檔案不存在或者必須假設已經損壞。非正常關閉mongod程式,又沒有開啟Journaling日誌,以及硬碟崩潰都屬於此類故障。恢復明確故障節點的唯一途徑就是重新同步或利用最近的備份完全替換資料檔案,讓我們看下這兩種策略。

    要完全同步更新,在故障節點上的某個空資料目錄裡啟動一個mongod程式。主要主機名和埠號沒有改變,新的mongod會重新加入副本集,隨後重新同步全部現有資料。如果主機名或者埠號有變化,那麼mongod重新上線後,你還需要重新配置副本集。舉個例子,假設節點arete:40000的資料無法恢復,你在foobar:40000啟動了一個新的節點。你可以重新配置副本集,只需要抓取副本集配置文件,修改第二個節點的host屬性,隨後將其傳給rs.reconfig()方法:

use local
config=db.system.replset.findOne()
config.members[1].host="fooba:40000"
rs.reconfig(config)
     現在新節點就加入副本集了,而新節點應該能從現有節點同步資料了。

     除了通過完全重新同步進行資料恢復,還可以通過最近的備份進行恢復。通常都會使用某個從節點來進行備份方法時製作資料檔案的快照並離線儲存。僅當備份中的oplog不比當前副本整合員的oplog就時,才能通過備份進行恢復。也就是說,備份的oplog的最新操作必須仍存在於線上oplog裡。可以使用db.getReplicationInfo()提供的資訊立即確定情況是否如此。在進行恢復時,不要忘記考慮還原備份所需要的時間。要是備份裡最新的oplog條目在從備份複製到新機器過程中仍可能變舊,那麼最好還是進行完全重新同步吧。

     但是通過備份進行恢復速度更快,部分原因是不用從零開始重新構建索引。要從備份進行恢復,將備份的資料檔案複製到mongod的資料路徑裡。應該會自動開始重新同步的,你可以檢查日誌或者執行rs.status()進行驗證。

4. 部署策略

     副本集最多可以包含12個節點。提供自動故障轉移的最小副本集配置就是先前構建的那個,包含兩個副本和一個仲裁節點。在生產環境下,仲裁節點可以執行在應用伺服器上,而副本則執行在自己的機器上。對於多數生產環境的應用而言,這種配置既經濟又高效。

     但是對於那些對正常執行時間有嚴格要求的應用而言,副本集中需要包含三個完整的副本。那個額外的副本能帶來什麼好處呢。想象一下,一個節點徹底損壞了。在恢復損壞節點期間,你還有兩個正常的節點可用。只要第三個節點線上並正常恢復(這可能需要幾個小時),副本集仍能自動故障轉移到擁有最新資料的節點上。

     一些應用程式要求有兩個資料中心來做冗餘,三個成員的副本集在這種情況下仍然使用。技巧在於讓其中一個資料中心僅用於災難恢復。如下圖,其中,主資料中心執行了副本集的主節點和一個從節點,備用資料中心的從節點作為被動節點(優先順序為0)。在這個配置中,副本集的主節點始終是資料中心A裡兩個節點之一。你可以在損失任意一個節點或者任意一個資料中心的情況下,保持應用程式線上。故障轉移通常是自動的,除非資料中心A的節點都發生了故障。同時損失兩個節點的情況很少見,通常表現為資料中心A完全故障或者網路分割槽。要迅速恢復,可以關閉資料中心B裡的節點,不帶-replSet引數進行重啟。除此之外,還可以在資料中心B中重啟兩個新節點,隨後強制進行副本集重新配置。照道理不該在大多數節點無法訪問的時候重新配置副本集,但在緊急情況下可以使用force選項這麼做。例如,假設定義了一個新的副本集配置config,強制重新配置使用如下方式:

rs.reconfig(config,{force:true})
       主要的還是測試工作,瞭解了副本集在這些狀況下的表現,可以讓你從容不迫地應對。

   5. 傳統的主從複製

         主從複製是MongoDB最初使用的複製正規化。這種複製易於配置,能支援任意數量的從節點。但是出於一些原因,我們不再推薦。首先,故障轉移完全是人工操作的。如果主節點發生故障,管理員必須關閉某個從節點,然後把它重啟為主節點,隨後應用程式必須重新配置以指向新的主節點。其次,恢復很困難,因為oplog僅存在於主節點上,發生故障後要去在新的主節點上建立新的oplog,這意味著發生故障時,其他節點都需要從新主節點重新進行同步。

  副本集才是王道






相關文章