MongoDB 副本集的相關概念【轉】


一、副本集基本概念

副本集(replica set)

MongoDB的replica set是一個mongod進程實例簇,數據在這個簇中相互復制,並自動進行故障切換。

MongoDB的數據庫復制增加了冗余,確保了高可用性,簡化了管理任務如備份,並且增加了讀能力。大多數產品部署都使用了復制。MongoDB中primary處理寫操作,其它進行復制的成員則是secondaries。

一個副本集可以最多支持12個成員,但是只有7個成員可以參與投票。

注:MongoDB同時提供了傳統的master/slave復制,這種復制的操作方法與副本集相同,但是master/slave復制不支持自動故障切換。很容易理解,主備模式下,cli端是指定了地址和端口進行mongodb的訪問的,而副本集模式則是通過訪問mongos來隱藏動態切換的。

成員配置

成員可以是以下某種角色:

 

成為primary

對客戶端可見

參與投票

延遲同步

復制數據

Default

Secondary-Only

Hidden

Delayed

Arbiters

Non-Voting

表:副本集角色屬性

故障切換恢復

副本集能夠自動進行故障切換恢復。如果primary掉線或者無反應且多數的副本集成員能夠相互連接,則選出一個新的primary。

在多數情況下,當primary宕機、不可用或者是不適合做primary時,在沒有管理者干預的幾秒后會進行故障切換。

如果MongoDB部署沒有如預期那樣進行故障切換,則可能是下面的問題:

  • 剩余的成員個數少於副本集的一半
  • 沒有成員有資格成為primary

Rollback

多數情況下,回滾操作可以優雅的對不能進行故障切換恢復的情況進行恢復。

Rollbacks操作發生在primary處理寫操作,但其它成員沒有成功的進行復制之前primary掉線時。當先前的primary開始復制 時,則表現出rollback。如果操作復制到其它成員,該成員可用,並且可以和大多數的副本集連接,則沒有rollback。

Rollbacks刪除了那些沒有進行復制的操作,以保證數據集的一致性。

選舉(Elections)

當任意的故障切換發生,都會伴隨着一個選舉的出現,以此來決定哪個成員成為primary。

選舉提供了一種機制,用於副本集中的成員無需管理員的干預,自動的選出一個新的primary。選舉可以讓副本集快速和堅決的從故障中恢復。

當primary變為不可達時,secondary成員發起選舉,第一個收到大多數選票的成員成為新的primary。

成員優先級

在副本集中,每個成員都有優先級,它可以幫助決定選舉出primary。默認情況下,所有的成員的優先級都為1。

一致性

在MongoDB中,所有針對於primary的讀操作都與最后的寫操作結果相一致。

如果客戶端配置了讀選項以允許secondary讀,讀操作能從沒有近期復制更新或操作的secondary成員返回結果。在這種情況下,查詢操作可能返回之前的狀態。

這種行為有時稱為最終一致性,因為secodary成員的狀態最終都會是primary的狀態。MongoDB不能保證從secondary成員的讀操作的強一致性。

沒有辦法保證從secondary成員讀的一致性,除非在配置時保證寫操作成功的在所有節點上都執行成功后才返回成功。

二、副本集架構和部署模式

架構

副本集部署的架構對其容量和性能都有很大影響。大多數產品部署成包含3個優先級為1 的成員就足夠了。

當開發一個副本集架構時要注意下面的因素:

  • 確保副本集的成員總能選出一個primary。運行奇數個成員或者運行一個仲裁者(arbiter)+偶數個成員。
  • 分布在不同地理位置的成員,知道“群體”的成員在任意網絡分區中的情況。試圖確保在主數據中心的成員中選舉出primary。
  • 考慮副本集中包含hidden或者delayed成員用於支持專用功能,如備份、reporting和測試。
  • 考慮保留一或者兩個位於其他數據中心的成員,同時通過配置確保其不會成為primary。
  • 使用replica set tags創建定制的寫規則以確保應用能夠控制寫操作成功的門限值。使用寫規則確保操作在返回成功之前將操作傳遞給指定的數據中心或不同功能的機器。

部署策略

不存在一個理想的副本集架構可以滿足任意部署環境。

最小的副本集推薦架構為三成員集合,其中一個為primary,另外兩個為secondary,secondary在一定情況下可以成為primary。

如果副本集中的成員多於三個,則需要遵照下面的架構條件:

  • 集合中有奇數個參與投票的成員。如果有偶數個投票成員,則部署一個仲裁者將個數變為奇數。
  • 集合中同一時刻不多於7個參與投票的成員
  • 如果不想讓某些成員在故障切換時成為primary,則將它們的優先級設為0。
  • 集合的多數成員運行在主要的數據中心

地理上的分布式集

一個基於地理的分布式副本集可以應對一個數據中心恢復失敗的情況。這種集合至少包含了一個在備份數據中心的集合成員。

 

圖:基於地理上的分布式副本集

如果primary掉線,則副本集選出一個新的primary;如果主數據中心和備數據中心連接失敗,備數據中心的secondary不能成為primary。如果主數據中心失敗,則需要人為的從備數據中心恢復數據。

值得注意的是,這種架構下,必須注意在主數據中心要保持奇數個參與投票的成員,上圖中則需要在主數據中心添加一個仲裁者。

非生產者成員

在有些時候,我們可能想有一個成員能夠拷貝整個的數據集,但並不使其成為primary。這種成員可以作為備份、支持報告操作或者作為一個冷備。這種成員被分為以下幾種:

  • 低優先級:通過 local.system.replset.members[n].priority設置成員的低優先級,從而使其不可能成為primary
  • 隱藏(Hidden):這種成員不可能primary,對客戶端不可見。
  • 投票(Voting):這會改變進行選舉的副本集的票數。

三、復制設置注意事項、應用和發展行為

寫關注(Write Concerns)

寫關注(Write concern)是指每個MongoDB寫操作的質量,描述關心應用寫操作結果的總量。如果寫關注設置為weak或者disabled,則應用會將寫操作 發送給MongoDB,不需要等待數據庫的響應而繼續執行;如果設置為強關注,則寫操作會等待MongoDB的寫操作確認。MongoDB提供不同的寫關 注來適應不同的應用場景。

寫關注的類型(按照從弱到強的順序):

  • Errors Ignored:寫操作不需要MongoDB的確認。這種效率是最高的,因為無需等待響應,但由於其隱藏了有可能的異常和錯誤,會對數據的持續性和持久性帶來很大的危險。(注意:通常情況下不會用這種類型)
  • Unacknowledged:MongoDB不會發送ack因為寫關注的級別是igore,但驅動會接收和處理網絡錯誤。
  • Acknowledge:mongod會確認收到的寫操作。在這個級別的寫關注下,客戶端能夠捕獲網絡、key重復和其它異常。這是默認的寫關注級別。默認的寫關注下無參數的調用getLastError。
  • Journaled:mongod會在寫入日志后確認寫操作。這確保了寫操作在mongod關閉時不會丟失,保證了寫操作的持久性。
  • Replica Acknowledge:這是對副本集的寫關注進行設置的。你能保證寫操作傳播到副本集的成員。詳見副本集的寫關注(Write Concern for Replica Set)。

副本集的寫關注(Write Concern for Replica Set)

MongoDB內嵌了寫關注來確保寫操作在副本集中primary的成功。寫關注在寫操作完成后,使用getLastError命令來獲取一個對象,包含錯誤信息或者是無錯誤的確認。

  • 驗證寫操作

默認的寫關注只在primary上確認寫操作。可以通過getLastError命令的w選項配置副本集中其它成員的寫關注。

w選項指定寫操作被復制到副本集成員的數目,包括primary。可以通過指定一個數或者majority來確保寫操作傳播到集合的多數成員。

  • 修改默認的寫關注

可以通過getLastError來配置自己的默認副本集行為。使用getLastErrorDefaults設置副本集的配置。下面的命令行是創建一個配置,指定寫操作需要在多數成員完成后才能返回。

cfg = rs.conf()

cfg.settings = {}

cfg.settings.getLastErrorDefaults = {w: “majority”}

rs.reconfig(cfg)

  • 定制寫關注

可以通過副本集標記(tag)使用getLastErrorDefaults和getLastErrorModes副本集設置來創建一個定制寫關注。

舉個例子:如果有一個三個成員的副本集,它們有以下標記:

{“disk”:”ssd”}

{“disk”:san, “disk.san”:san}

{“disk”:”spinning”}

然后創建一個定制的getLastErrorModes值:

cfg = rs.conf()

cfg.settings = { getLastErrorModes : { san : { “disk.san” : 1} } }

rs.reconfig(cfg)

通過san使用這個模式指定w選項:

db.runCommand( { getLastError : 1, w : san } )

這個操作在標簽disk.san返回之前不會返回。

也可以使用getLastErrorDefaults設置定制寫關注:

cfg = rs.conf()

cfg.settings.getLastErrorDefaults = { ssd : 1 }

rs.reconfig(cfg)

讀偏好(Read Preference)

讀偏好描述了MongoDB客戶端如何將讀請求路由到副本集的成員。

默認情況下,一個應用會將其讀操作導向副本集中的primary。從primary中讀可以保證讀操作返回的是最新的文檔。然后,一個應用如果不需 要完全實時的數據,則可以通過分布一些或全部的讀操作到副本集的secondary成員上,從而提高讀操作的吞吐量或者降低時延。

MongoDB驅動允許客戶端應用對於每個連接、每個collection或者每個操作進行讀偏好設置。

讀偏好模式同樣對通過mongos連接分片簇的客戶端有效。

注意:如果一個應用的讀操作比例很大,則從secondary成員分布式讀可以提高吞吐量。

讀偏好模式:

  • primary

所有的讀操作只訪問當前副本集的primary,為默認模式。如果primary不可用,則讀操作會產生一個error或拋出一個異常。

這個模式與標簽集模式的讀偏好不兼容。

  • primaryPreferred

在通常情況下,從副本集的primary上讀數據,當primary不可用時,也就是在故障切換的過程中,從副本集的secondary成員上讀數據。

當讀偏好包含了標簽集時,如果primary可用,客戶端從primary上讀數據,否則從指定標簽的secondary成員上讀數據。如果沒有匹配標簽的secondary時,則產生一個error。

  • secondary

讀操作只從副本集的secondary成員上讀數據。如果沒有secondary可用,則產生一個error或者拋出一個異常。

當讀偏好包含標簽集時,客戶端試圖找出指定標簽集的secondary成員,並將讀操作隨機的導向其中一個secondary成員。如果沒有相匹配的secondary則產生一個error。

  • secondaryPreferred

在通常情況下,讀操作從secondary成員上讀數據,但是當副本集中只有一個primary成員時,則從primary讀數據。

當讀偏好包含標簽集時,客戶端試圖找出指定標簽集的secondary成員,並將讀操作隨機的導向其中一個secondary成員。如果沒有相匹配的secondary則產生一個error。

  • nearest

驅動從最近的集合成員中讀數據時一個成員選擇的過程。該模式不關注成員的類型,不管是primary還是secondary成員。

當讀偏好包含標簽集時,客戶端試圖找到指定標簽的集合成員並將讀操作導向其中任意的一個成員。

自動重試

在MongoDB驅動和副本集中mongod實例之間的鏈接必須平衡兩個問題:

  • 客戶端應該試圖獲取當前的結果,並且任何連接應該盡可能從相同的副本集成員上讀取數據。
  • 客戶端應該最小化由於連接問題、網絡問題或者副本集故障切換造成的不可達時間。

方法如下:

  • 當連接穩定后盡可能長時間的復用指定mongod的連接。連接與mongod綁定在一起。
  • 如果與mongod的連接失敗,則在遵守以后的讀偏好模式下,試圖連接到一個新的成員。

重連操作對於應用本身是透明的。如果連接允許從secondary成員上讀數據,在重連后,應用能夠相繼從不同的secondary收到兩個讀取結果。依照個別secondary成員的狀態,文檔能夠反映不同時間的數據庫狀態。

  • 只有在試圖依照讀偏好模式和標簽集,連接集合的三個成員后返回error。如果集合少於3個成員,則客戶端在連接所有存在的成員后返回error。

在收到error后,驅動使用指定的讀偏好模式選擇一個新的成員。如果沒有指定的讀偏好,則使用primary。

  • 在檢測故障切換狀態后,驅動會盡快的嘗試刷新副本集的狀態。

請求聯合

從secondary讀數據能夠反映數據集在不同時間點的狀態,因為副本集的secondary成員相對於primary的最新狀態都有不同程度的 滯后。為了防止后面的讀操作在時間上的跳躍,驅動能在第一個讀操作后把應用線程綁定到指定的集合成員上。線程持續的從相同成員上讀取,直到一下情況發生:

  • 應用執行一個有不同讀偏好設置的讀操作
  • 線程終止
  • 客戶端收到一個socket異常,造成這種情況的原因可能是網絡錯誤,或是在故障切換過程中mongod關閉了連接操作的。這會引起一次重連操作,但其對應用來說是透明的。

如果應用線程在primary不可用時,發出一次primaryPreferred模式的查詢操作,則線程會一直固定的訪問一個secondary 成員,盡管primary恢復后,也不會切回。同樣的,如果線程在所有secondary成員都down掉時,發起一次 secondaryPreferred模式的查詢,應用線程會一直從primary上進行讀取,盡管secondary恢復。

成員選擇

客戶端通過驅動和分片簇的mongos實例會定期的更新副本集的狀態:哪些成員up或down了,哪個成員成為了primary,以及每個mongod實例的延遲。

對於任意針對非primary成員的操作,驅動會:

  • 匯集一個合適成員的列表,考慮成員的類型(如secondary、primary或者所有成員)
  • 如果指定標簽集,則排除所有不匹配標簽集的成員
  • 判斷出那個合適的成員離客戶端最近
  • 建立一個成員列表,其包含了一個到絕對最近成員的ping距離。
  • 在這些主機中隨機選擇一個成員,這個成員接收讀操作。

分片和mongos

在多數的分片簇中,一個副本集提供每一個分片,這里讀偏好也是可用的。分片簇中的帶有讀偏好的讀操作與不分片副本集是完全相同的。

與簡單的副本集不同的是,在分片簇中,客戶端所有與分片的交互都是通過mongos連接到副本集成員上。Mongos負責應用的讀偏好,這對應用是透明的。

在支持所有讀偏好的分片環境中沒有配置更改的需要。所有的mongos保存着他們自己與副本集成員間的連接池。

四、副本集內部組成和行為

Oplog內部組成

在各種異常情況下,更新一個secondary的oplog可能會比預期時間有所延遲。

所有副本集的成員會在集合中向其它所有成員發送心跳(ping)包,並且能夠將集合中的其它成員的操作加入本地oplog。

副本集的oplog操作時冪等的。下面的操作時需要冪等的:

  • 初始同步
  • 快速回滾(post-rollback catch-up)
  • 分片塊遷移

讀偏好的內部組成

MongoDB使用單一主復制來確保數據庫保持一致性。然而,客戶端可能修改每個連接的讀偏好來分發讀操作到從副本集中的secondary成員上。一個以讀為主的部署能夠通過分發讀取到secondary成員上實現更多的查詢。但

選舉內部組成

選舉是副本集選擇某個成員成為primary的過程。primary是一個副本集中唯一能夠接收寫操作的成員。

下面的事件能夠引發一次選舉:

  • 第一次初始化一個副本集
  • Primary失效。replSetStepDown命令能夠使Primary失效,或者當前secondary成員中有合適的選舉者且優先級更 高。當Primary與集合中的大多數成員失去聯系時也會失效,它會關閉所有的客戶端連接,以此防止客戶端向一個沒有primary成員寫數據。
  • 一個secondary成員於primary失去聯系。當secondary成員不能與primary建立一個穩定的連接時會發起選舉。
  • 故障切換發生。

在選舉過程中,所有的成員都有一票,包括隱藏成員、仲裁者和正在恢復的成員。任意mongod能夠否決一次選舉。在默認的配置中,所有成員都有相同 的機會成為primary。然而可以通過設置優先級來影響選舉。在一些結構中,這可能有操作因素來提高一個成員成為primary的可能性。例如,一個在 遠程數據中心的成員不應該成為primary。

任意成員都能否決一次選舉,盡管這個成員是一個非投票成員。

一個成員在下列情況下會否決一次選舉:

  • 如果發起選舉的成員不是一個投票集中的成員
  • 如果發起選舉的成員沒有更新副本集最新的操作
  • 如果發起選舉的成員比集合中其他更適合發起選舉的成員的優先級低
  • 如果一個只能是secondary成員在選舉時是最新的成員,其它合適的集合成員趕上了這個secondary成員的狀態,並試圖成為primary
  • 如果當前primary比發起選舉的成員有更多的最近操作,從投票成員的角度上。
  • 如果當前的primary與發起選舉的成員有相同或者更新的操作時,會否決這次選舉。

第一個接收到集合中多數選票的成員將成為primary,只到下次選舉。了解下面的條件和可能的情況:

  • 副本集成員每兩秒發一次心跳包。如果心跳包沒有在10秒內收到響應,則其他成員將這個不良成員標記為不可達的。
  • 副本集成員只與集合內的其它成員進行優先級比較。優先級的絕對值不會影響副本集選舉的結果,當然除了0之外,它表明這個成員不能成為primary,也不能發起選舉。
  • 如果一個副本集成員在可見的成員中有最高的操作時間,則其不能成為primary
  • 如果一個成員擁有副本集中的最高優先級,但其與最近的oplog操作有10秒的差距,則集合不會選舉出primary,只到這個擁有最高優先級的成員更新到最近的操作。

同步

為了能夠跟上副本集的最近狀態,設置成員從其它成員同步或者復制oplog記錄。成員同步數據在兩個不同的點:

  • 當MongoDB在一個新的或者修復后的成員上創建一個新的數據庫時進行初始同步。當一個新的或者修復后的成員加入或重新加入一個集合時,該成員 會等待接收其它成員的心跳包。默認情況下,成員從最近的集合成員進行同步,這個成員有更近的oplog記錄,無論其是primary還是其它 secondary。
  • 在初始同步后,復制會繼續進行,以此保證副本集的成員能夠保持數據更新。

例子:

  • 如果有兩個secondary成員在一個數據中心,一個primary在另一個中,如果同時啟動這三個實例(沒有數據或oplog存在),則兩個 secondary成員都很有可能從primary進行同步,因為任何一個secondary成員都沒有更近的oplog記錄。如果重啟其中的一個 secondary成員,然后當其重新加入到集合后很可能從另一個secondary成員同步數據,因為其距離更近。
  • 如果有一個primary在一個設施中,一個secondary成員在另一個設施中。如果在另一個設施中增加一個secondary成員,那么它將從已存在的secondary成員處同步數據,因為這個成員比primary距離更近。

在MongoDB2.2以后,secondary成員還可以進行以下附加的同步行為:

  • 如果沒有其它成員可用,Secondary成員將從延遲成員上同步數據
  • Secondary成員不從隱藏成員上讀取數據
  • Secondary成員不會開始從一個正在恢復狀態的成員上同步
  • 因為一個成員從另一個成員同步,兩個成員必須在buildIndexes域有相同的值,無論是true還是false。

    如果用於來oplog記錄的連接有30秒時間沒有反應,則Secondary成員停止從這個成員進行同步。如果一個連接超時,則該成員會重新選擇一個新的成員進行同步。

多線程復制

MongoDB的批量寫操作使用的多線程方式。復制過程將一組有大量並發操作的線程中每個批處理分開。

盡管多線程可能會使操作失序,客戶端從secondary成員讀取數據不會收到返回的documents,這反映了一個不會在primary存在的中間狀態。為了確保一致性,MongoDB會在處理批操作時阻塞所有的讀操作。

為了改進操作應用的性能,MongoDB獲取所有保存數據的內存頁和批處理將要影響的操作的索引。預取階段將MongoDB持有寫操作鎖的時間縮到最短。

預取索引以提高復制的吞吐量

默認情況下,secondary在通常會預取與操作影響的document的索引以此提高復制的吞吐量。可以限制只針對於_id域使用預取功能,或者完全關閉該功能。

五、主從復制

從1.6版本起,副本集方式就代替了主從復制。所有新的產品架構都使用了副本集而不是主備復制。

副本集提供了主從關系的功能超集,能夠使產品更健壯。主從復制優先復制,使其有大量的非主節點,且只為一個單獨的數據庫進行復制操作。然而主從復制提供少量冗余,且不能自動故障切換。

故障切換到從節點(提升)

永久的就從不可用或毀壞的主節點A切換到從節點B上:

  • 關閉A
  • 停止B的mongod
  • 備份並移除所有B節點上以local開頭的dbpath下的數據文件
  • 以master選項重新啟動B的mongod

轉換主從關系

如果有一個主A和一個從B,想要轉換它們的關系,則遵循以下過程。這個過程假設A是健康的、最新的和可用的。

如果A不是健康的,但硬件是正常的,則跳過①和②,並在第⑧步將所有的A文件替換為B文件。

如果A不是健康的,且硬件也不正常,則使用一個新機器代替A。

轉換主從部署:

①  使用fsync命令停止A上的寫操作

②  確保B跟上了A的狀態

③  關閉B

④  備份並移除所有B節點上以local開頭的dbpath下的數據文件

⑤  以master選項重新啟動B

⑥  在B上進行一個寫操作,這樣可以使oplog提供一個新的同步時間點

⑦  關閉B,B目前有新的以local開頭的數據集文件

⑧  關閉A,替換A上以local開頭的dbpath路徑下的所有文件為B上以local開頭的dbpath路徑下的文件拷貝。確認在拷貝B的本地文件時要進行壓縮,因為這些文件有可能很大。

⑨  以master選項啟動B

⑩  以slave選項啟動A,但是包含fastsync

恢復時過時太多則要重新同步

從節點異步從主節點上接收寫操作,從主節點的oplog上拉取數據。Oplog的長度有限,如果從節點落后太多,重新同步是非常必要的。重新同步從節點,則連接上從節點的mongod,並執行resync命令:

use admin

db.runCommand( { resync : 1 } )

從節點鏈

從節點不能被穿成鏈,它們必須與主節點直接相連。如果一個從節點試圖作為另一個從節點的從節點,你將在mongod中看到提示。

 

本文來自:http://www.cnblogs.com/geekma/archive/2013/05/09/3068988.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM