mongo——複製

複製

複製是跨多個mongodb服務器(節點)分佈和維護數據的方法。mongodb可以把數據從一個節點複製到其他節點並在修改時進行同步。這種類型的複製通過一個叫可複製集的機制提供。集羣中的節點配置爲自動同步數據,並且在服務器出錯時自動災備。mongodb也提供對於舊的複製方法的支持。這個舊方法叫做主從模式,現在已經過時了,但是主從複製仍然可以在mongodb3.0裏使用。兩種方法類似,主節點接受所有的寫請求,然後所有的從節點讀取,並且異步同步所有的數據。

主從複製和可複製集羣使用了相同的複製機制,但是可複製集羣額外增加了自動化災備機制:如果主節點宕機,無論什麼原因,其中一個從節點會自動提升爲主節點。除此之外,可複製集羣還提供了其他改進,比如更容易恢復和更復雜地部署拓撲網絡。因此我們很少再用簡單的主從複製機制。可複製集羣是推薦的生產環境下的複製策略。

複製的缺點:回滾機制,在可複製集羣裏,數據並非正在地被提交,直到它被寫入大多數集羣的節點中,這指的是50%上的服務器。因此,如果可複製集羣只有兩個服務器,就意味着每一服務器可以停機。如果主節點在複製數據之前停機,其他成員會繼續接受寫入,而且任意未複製的數據必須回滾,意味着他不能被讀取。

爲什麼複製很重要

所有的數據庫都無法擺脫環境故障的影響

1.應用程序和數據庫之前的連接丟失了

2.計劃內停止阻止了服務器按照預期上線

複製的使用場景和限制

複製首先是爲冗餘設計的。它可以確保從節點與主節點的數據同步。這些複製節點可以和主節點位於一個數據中心或者爲了安全可以分佈於其他數據中心。

複製是異步的,任何網絡延遲和分區都不會影響主節點的性能。

作爲另外一種形式的冗餘,複製節點也可以延遲某個固定的時間後執行。這防止了用戶無意刪除集合或者應用程序與數據庫衝突的情況。通常,這些操作將會被立即複製;延遲複製可以給管理員足夠的時間來做出響應並保存數據。

另外一個複製的使用情況是災備,我們希望系統是高可用的,但是隻有在冗餘節點時纔可以使用,並且在緊急情況下切換這些節點。mongodb的可複製集羣讓這一切都可以自動切換。

除了數據冗餘和災備,複製也簡化了維護工作,通常通過允許管理員在從節點而不是主節點上運行命令。例如,通常的經驗是在從節點上運行備份命令來緩解對於主節點的壓力,避免宕機。構建大型索引是另外一個例子。因爲所有構建非常昂貴,我們可以在從節點上優先構建,然後切換主從節點的角色,再次在新的從節點上構建索引。

最後,複製可以允許我們從節點上平衡讀寫壓力。對於讀取壓力超大的應用系統,這個是最簡單的解決辦法,或者如果你選擇最原始的做法,可以伸縮mongodb數據庫。但是對於所有的承諾,可複製集羣在以下情況下無能爲力:

1.現有的硬件無法處理工作負荷,例如,我們前面章節提到的工作集,如果數據集超過了可用的內存大小,那麼隨機讀取從節點就不會像我們期望的那樣改善性能。從可複製集羣從節點讀數據可以增加IOPS數量,但是100-200IOPS可能無法解決性能問題,特別是同時寫入並消耗部分IO數量的時候,此時,分片可能是最好的選擇。

2.寫入和讀取的比例超過50%

3.應用程度需要一致性讀取。從節點異步複製,因此不能確保反映最新主節點的寫入數據。在極端的糟糕的情況下,從節點可能延遲幾個小時。

可複製集

可複製集是推薦使用的mongodb複製策略。

可複製集羣工作原理

可複製集羣依賴兩個基本的機制:oplog和heartbeat。oplog允許複製數據,heartbeat監控狀態並觸發災備。

oplog

mongodb的複製機制依賴oplog。oplog是個蓋子集合,它存在於每個複製節點的local數據庫裏,而且記錄了所有的數據變化。每次客戶端寫入主節點的數據,包含足夠重生信息的項目就會添加到主節點的oplog中。一旦寫入的數據被複制到某個從節點,從節點的oplog也會存儲這個寫入請求的記錄。每個oplog項目通過bson的時間戳來區分,並且所有的從節點使用時間戳來跟蹤它們應用的最新項目。

local數據庫存儲了所有的可複製集羣中的元數據和oplog操作日誌。自然地,這個數據庫不是複製的數據庫本身,因此它有自己的名字,local數據庫中的數據在本地節點被認爲是唯一的,而且不能重複的。

如果檢查local數據庫,就會看到名爲oplog.rs的集合,這就是可以複製存儲oplog的地方。我們也會看到一些其他的集合,以下是完整的輸出信息。

replset.minvalid包含可複製集成員最初同步的信息.並非所有的mongodb服務器都有replset.minvalid集合

system.replset存儲了可複製集的配置文檔。

me和slaves用來實現寫關注點

system.indexes是標準的索引容器。

第一個字段ts存儲的是項目的bson時間戳。時間戳包含2個部分:第一個部分表示從紀元(1970-01-01 00:00:00UTC)開始的秒數。第二個部分表示計數器的值,這裏是1。使用時間戳查詢,需要顯示指定一個時間戳對象。所有的驅動都有自己的bson時間戳構造函數,而且JavaScript也有。

回到oplog項目,op字段指定opcode操作代碼。它可以告訴從節點oplog項目表示的操作。這裏我們看到的是i,表示插入操作。op後面是ns,它可以用來定義命名空間(數據庫和集合),然後小寫的字母o表示插入操作包含了一個查詢文檔的副本。

當我們查看oplog項目時,可能會注意到影響多個文檔的操作會被單獨記錄日誌。對於多個更新或者大量的刪除,每個受影響的文檔都會單獨創建oplog文檔。例如,假如我們要在集合中插入更多的Dickens的書。

現在集合中有4本書,我們來更新作者信息,添加作者的名字:

它是怎麼出現在oplog中的呢?

正如你看到的,每個更新的文檔都會有自己的oplog記錄。這個過程是更通用的主從複製策略的一部分,用來確保主從節點一直有相同的數據。要保證這一點,每個應用的操作必須是冪等的——它無法干涉應用了多少次oplog項目。但是結果必須相同。其他多文檔的操作,比如刪除,將會出現相同的行爲。我們可以嘗試不同的操作來看看oplog的最終記錄。

理解複製機制剩下的最後一點是,主節點追蹤自己的oplog的步驟。答案是像從節點一樣保存了oplog。這是對於主從複製的一大改進,所以值得花時間來研究底層實現。

想象一下,在主節點上寫了個數據。接下來會發生什麼?一開始,寫操作會被記錄並添加到主節點的oplog裏。同時,所有的從節點都會複製主節點的oplog。當某個從節點準備更新自己的數據時,它會做3件事情。首先,它會查看自己oplog裏最新記錄的時間戳。然後,它會查詢主節點的oplog,查詢所有時間戳大於自己當前時間戳的oplog記錄。最後,它寫入數據,並添加每個操作日誌到自己的oplog裏。這意味着,假如出現故障,任意的提升爲主節點的從節點都會有一個oplog,這樣其他的從節點可以複製。這個特性本質上支持了可複製集的故障恢復功能。

從節點使用了長輪詢來立即應用從節點複製的oplog記錄。長輪詢意味着從節點向主節點建立了個長連接。當主節點接受修改時,它會立即通知從節點。因此,從節點將幾乎可以做到實時更新。當它們落後時,因爲網絡分區或者從節點維護,每個從節點裏的oplog可以用來監控任意落後的複製。

停止複製

如果從節點無法在主節點oplog找到同步的日誌記錄點,就會永久停止複製。發生這種問題時,我們會看到從節點日誌裏有這樣的異常信息:

回憶一下,oplog是個蓋子集合。這意味着oplog只能存儲固定數量的數據。如果從節點離線一段時間,oplog可能無法存儲這段時間裏的所有改變記錄。一旦從節點無法從主節點找到同步的oplog點,就無法確定從節點是主節點完美複製集合了。

因爲唯一的停止複製的補救措施就是完整地重新同步主節點的數據,肯定想避免這種問題。因此,需要去監控從節點的延遲,而且必須有足夠大的oplog空間。

複製集oplog的大小

oplog是個蓋子集合,因此,mongodb2.6不允許在創建後再修改其大小。所以非常重要的是開始就仔細選擇oplog的大小。在mongodb3。0裏,我們可以修改oplog的大小。操作步驟就是,停止mongodb實例,然後作爲獨立節點啓動,修改oplog大小,重新啓動成員。

心跳和故障轉移

可複製集心跳便於實現選舉和災備。默認情況下,每個可複製集成員會每隔2秒ping一次索引的其他成員。這樣,系統就可以判斷自己的健康狀態。當運行rs.status()時,查看每個節點的最新心跳和狀態(1 健康,0無應答)。

只要每個節點仍然健康並且響應,可複製集就會繼續正常工作。但是如果某個節點無法響應,就可能會採取行動了。每個可複製集都要確保一直只有一個主節點存在。這只是在大多數節點可用的時候。例如,如果關閉了某個從節點,但是大多數節點還在,那麼可複製集就不會改變,而是簡單地等待從節點回來,重新上線。如果殺死了主節點,則大多數節點還存在,但是沒有主節點,因此從節點會自動提升爲主節點。如果多於一個從節點,則最新的從節點將會被選中。

但是也有其他可能的場景存在。想象下從節點和裁判都被殺死的情況。選中的主節點還在,但是沒有其他節點——最初的節點只有一個是健康狀態。此時,我們會在主節點的日誌裏看到如下的信息

由於沒有從節點,主節點降級爲從節點。這看起來有點可笑,但是思考一下如果此節點依然是主節點會發生什麼問題?如果是網絡分區等原因導致心跳失敗,則其他節點就會仍然在線。如果裁判和從節點仍然正常工作,並且可以看到彼此,則根據大多數原則,剩餘的從節點會變成主節點。

如果主節點不退位,那麼就會遇到一個尷尬的情況:一個可複製集有2個主節點,如果應用程序持續運行,它也許會向兩臺節點寫入或者讀取數據,肯定會造成不一致而且非常奇怪的行爲。因此當主節點看不到其他成員時,它必須退位降級

 提交和回滾

從本質上講,你可以一直向主節點寫入數據,但是這些寫入操作不會被提交,直到它們被複制給大多數從節點,那麼什麼是提交?

注意,對於mongodb單個文檔的操作都是原子性的,但是對於多個文檔的操作並非原子性的。想象一下前面提到的,假如我們在主節點插入了一些數據,但是由於某種原因沒有及時複製到從節點(連接問題,從節點無法備份,從節點延遲等)。現在假設從節點突然提升爲主節點,我們向新的主節點寫入數據,但是最終舊的主節點又回來了,並且嘗試從新的主節點複製數據。當舊的主節點中有一些寫入數據在新主節點的oplog裏不存在時,就會觸發回滾。

在回滾裏,所有沒有複製給大多數節點的寫入操作都會被取消。這意味着它們會被從從節點oplog和集合裏刪除。如果從節點已經註冊了個刪除操作,則該節點將會從其他複製集裏查詢該文檔並恢復它。對於文檔更新和刪除集合的操作恢復機制是一樣的。

還原的寫操作被存儲在相關節點數據目錄的子目錄裏。對於每個回滾寫入的集合,都會創建一個單獨的bson文件,文件名包含回滾的時間。在需要恢復回滾文檔的事件裏,可以使用bsondump工具來檢查bson文件,並且手動恢復他們,可以使用mongorestore。

如果必須恢復回滾數據,就會發現這是我們想要極力去避免的。幸運的是,某種程度上也是可以的。如果應用程序可以容忍寫延遲,那麼可以使用寫關注點,這個概念在後面介紹,它可以確保寫數據被複制到大多數的節點。聰明地選擇寫關注和監控複製延遲可以幫助我們減少回滾,或者避免他們。

讀伸縮

對於讀伸縮來說,複製數據庫是很好的解決方案。如果單個服務器無法處理應用的讀壓力,就可以把查詢請求路由到可複製集中的多臺服務器上。

1.primary——這是默認的設置,表明只從可複製集主節點讀取數據,因此一直是連續的。如果可複製集有問題,並且沒有可用的從節點,就表示出現錯誤。

2.primaryPreferred——設置了此參數的驅動會從主節點讀取數據,除非某些原因使主節點不可用或者沒有主節點,此時它會從從節點讀取數據。這種設置對於我們想確保讀請求不會影響主節點的寫入請求時非常有用。如果沒有可用的從節點,讀請求會拋出異常

3.secondary——這個設置告訴驅動應該一直從從節點讀取數。這種設置對於我們想確保讀請求不會影響主節點的寫入請求時非常有用。如果沒有可用的從節點,讀請求會拋出異常。

4.secondaryPreferred——相比前面的設置,這個更加靈活。讀請求會發送到從節點,除非沒有從節點可用,此時會從主節點讀取。

5.nearest——此配置的驅動會嘗試從最近的可複製集成員節點讀取數據,通過網絡延遲判斷。可以是主節點也可以是從節點。因此讀請求只會發送給驅動認爲最快通信的節點。

 

總結:

1.mongodb的生產環境部署時,數據保護應該使用可複製集,如果做不到這一點,就必須經常備份數據

2.可複製集應該包含至少3個成員,其中一個是裁判

3.數據不會提交,直到它被寫入可複製集的大數據節點中。在故障的場景下,如果大多數成員存在,它們就繼續接受寫請求。沒有達到大多數成員的寫請求會被放入回滾數據目錄下,並且必須手動處理。

4.如果可複製集從節點宕機一段時間,並且數據庫修改沒有記錄到mongodb的oplog裏,這個節點就沒有辦法及時填補數據,而且必須重新同步數據。爲了避免這個問題,可以嘗試最小化從節點的失敗時間。

5.驅動的寫關注點控制着在返回之前必須有多少個節點被寫入。增加這個值可以增加持久性。對於正式的持久性,我們推薦設置爲大多數成員以避免回滾場景,但這個方法會帶來延遲成本。

6.mongodb允許我們通過讀偏好和標籤來控制更復雜的可複製集的讀寫行爲,特別是在多個數據中心部署可複製集成員時。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章