本文分兩部分,分佈式和單機。單個db的存儲引擎,物理和數據存儲簡介,事務實現等。分佈式架構,分佈式涉及的複製集,分片等可靠性和擴展性保障。linux
wiredTiger(簡稱WT)支持行存儲、列存儲以及LSM等3種存儲形式,Mongodb使用時,只是將其做爲普通的KV存儲引擎來使用,mongodb的每一個集合對應一個WT的table,table裏包含多個Key-value pairs,以B樹形式存儲。mongodb的集合和索引都對應一個wiredTiger的table。並依賴於wiredTiger提供的checkpoint + write ahead log機制提供高數據可靠性,目前支持單機事務。
按照Mongodb默認的配置,WiredTiger的寫操做會先寫入Cache,並持久化到WAL(Write ahead log journal),每60s或log文件達到2GB時會作一次Checkpoint,將當前的數據持久化,產生一個新的快照。Wiredtiger鏈接初始化時,首先將數據恢復至最新的快照狀態,而後根據WAL恢復數據,以保證存儲可靠性。
Wiredtiger的索引採用Btree的方式組織
Wiredtiger採用Copy on write[ps:存儲的COW意在W的時候C一份,不在原來上修改。linux的意在W的時候才C一份,不更改只會存在一份]的方式管理修改操做(insert、update、delete),保證一致性,而且不像InnoDB同樣,須要一個DoubleWriteBuffer保證非disk block 512B寫時對原有頁可能發生conrrupt。修改操做會先緩存在cache裏,持久化時,修改操做不會在原來的leaf page上進行,而是寫入新分配的page,每次checkpoint都會產生一個新的root page。算法
內存結構:B樹索引頁和數據頁(B樹作了改版,中間節點不放數據,要加update和insert佔內存),新插入跳錶(有序)更新list(會變動,無需有序),copy on write,wal
物理結構:mongodb
數據清理:數據庫
分片
balancer+route
config數組
分片:範圍,hash
遷移步驟:
集合分片開啓後,默認會建立一個新的chunk,shard key取值[minKey, maxKey]內的文檔(即全部的文檔)都會存儲到這個chunk。當使用Hash分片策略時,能夠預先建立多個chunk,以減小chunk的遷移。緩存
一個 Sharded Cluster 裏可能有不少個 mongos(能夠理解一個庫一個),若是全部的 mongos 的 Balancer 同時去觸發遷移,整個集羣就亂了,爲了避免出亂子,同一時刻只能讓一個 Balancer 去作負載均衡。
Balancer 在開始負載均衡前,會先搶鎖(config.locks集合下的一個特殊文檔),搶到鎖的 Balancer 繼續幹活,沒搶到鎖的則繼續等待,一段時間後再嘗試搶鎖。網絡
Step1: mongos 發送 moveChunk 給源 shard mongos 接受到用戶發送的遷移 chunk 命令,或者因負載均衡策略須要遷移 chunk,會構建一個 moveChunk 的命令,併發送給源 shard。 Step2:源 shard 通知目標 shard 開始同步 chunk數據 源 shard 收到 mongos 發送的 moveChunk 命令後,會向目標 shard 發送 _recvChunkStart 的命令,通知目標 shard 開始遷移數據(真正的數據遷移由目標shard 主動發起)。接下來,源 shard 會記錄該 chunk 在遷移過程當中的全部增量修改操做。 Step3: 目標 shard 同步 chunk 數據到本地 目標 shard 接受到 _recvChunkStart 命令後,就會啓動單獨的線程來讀取 chunk 數據並寫到本地,主要步驟包括: 目標 shard 建立集合及索引(若是有必要) 若是遷移的集合在目標 shard 上沒有任何 chunk,則須要先在目標 shard 上建立集合,並建立跟源 shard 上集合相同的索引 目標 shard 清理髒數據 (若是有必要) 若是目標 shard 上已經存在該 chunk 範圍內的數據,則確定爲某次遷移失敗致使的髒數據,先將這些數據清理掉。 目標 shard 向源 shard 發送 _migrateClone 命令讀取 chunk 範圍內的全部文檔並寫入到本地,即遷移 chunk 全量數據,遷移完後更新狀態爲 STEADY(能夠理解爲全量遷移完成的狀態)。 源 shard 會不斷調用查詢目標 shard 上的遷移狀態,看是否爲 STEADY 狀態,若是已是 STEADY 狀態,就會中止源 shard 上的寫操做(經過對集合加互斥寫鎖實現)。接下來發送 _recvChunkCommit 告訴目標 shard 不會再有新的寫入了。 目標 shard 的遷移線程不斷向源 shard 發送 _transferMods 命令,讀取遷移過程當中的增量修改,並應用到本地,增量遷移完成後,向源確認 _recvChunkCommit 的結果。 源 shard 收到 _recvChunkCommit 的結果,整個數據遷移的步驟完成。 Step4:源 shard 更新 config server 元數據 數據遷移完成後,源 shard 就會向 config server 更新 chunk 對應的 shard 信息,同時也會更新 chunk 的版本信息,這樣 mongos 發現本地版本更低就會主動的 reload 元數據,具體機制參考 MongoDB Sharded Cluster 路由策略。 Step5:源 shard 刪除 chunk 數據 chunk 遷移到目標 shard 後,源上的 chunk 就沒有必要再保存了,源 shard 會將 chunk 數據刪除,默認狀況下源 shard 會將刪除操做加入到隊列,異步刪除,若是 moveChunk 時,指定了 _waitForDelete 參數爲 true,則同步刪除完再返回。 一旦源shard 查詢到目標 shard 進入到 STEADY 狀態了,源 shard 就會進入臨界區,測試源上的寫就會排隊等待。等整個遷移完了,這些等待的寫操做就會繼續執行,但此時 chunk 的版本號已經更新了,會告訴客戶端版本太低,客戶端從新從 config server 讀取配置,此時拿到的路由信息裏 chunk 已經在目標 shard 了,而後寫會發往目標 shard 。
Secondary初次同步數據時,會先進行init sync,從Primary(或其餘數據更新的Secondary)同步全量數據,而後不斷經過tailable cursor從Primary的local.oplog.rs集合裏查詢最新的oplog並應用到自身。
oplog: 冪等(incr會轉爲set),循環覆蓋,
順序保證:寫入 oplog前,會先加鎖給 oplog 分配時間戳,並註冊到未提交列表裏,正式寫入 oplog,在寫完後,將對應的 oplog 從未提交列表裏移除,在拉取 oplog 時若未提交列表爲空,全部 oplog 均可讀,不然只能到未提交列表最小值之前的 oplog
Secondary 拉取到一批 oplog 後,在重放這批 oplog 時,會加一個特殊的 Lock::ParallelBatchWriterMode 的鎖,這個鎖會阻塞全部的讀請求,直到這批 oplog 重放完成多線程
client與複製集心跳,複製集之間心跳
複製集成員間默認每2s會發送一次心跳信息,若是10s未收到某個節點的心跳,則認爲該節點已宕機;若是宕機的節點爲Primary,Secondary(前提是可被選爲Primary)會發起新的Primary選舉。Bully算法。
每一個節點都傾向於投票給優先級最高的節點(oplog時間戳,同樣誰先就誰)
優先級爲0的節點不會主動發起Primary選舉
當Primary發現有優先級更高Secondary,而且該Secondary的數據落後在10s內,則Primary會主動降級,讓優先級更高的Secondary有成爲Primary的機會。
若是Primary與大多數的節點斷開鏈接,Primary會主動降級爲Secondary
當複製集內存活成員數量不足大多數時,整個複製集將沒法選舉出Primary,複製集將沒法提供寫服務,處於只讀狀態
當Primary宕機時,若是有數據未同步到Secondary,當Primary從新加入時,若是新的Primary上已經發生了寫操做,則舊Primary須要回滾部分操做,以保證數據集與新的Primary一致。舊Primary將回滾的數據寫到單獨的rollback目錄下,數據庫管理員可根據須要使用mongorestore進行恢復。
Bully架構
若是P是最大的ID,直接向全部人發送Victory消息,成功新的Leader;不然向全部比他大的ID的進程發送Election消息 若是P再發送Election消息後沒有收到Alive消息,則P向全部人發送Victory消息,成功新的Leader 若是P收到了從比本身ID還要大的進程發來的Alive消息,P中止發送任何消息,等待Victory消息(若是過了一段時間沒有等到Victory消息,從新開始選舉流程) 若是P收到了比本身ID小的進程發來的Election消息,回覆一個Alive消息,而後從新開始選舉流程 若是P收到Victory消息,把發送者當作Leader
Primary
Secondary:
Arbiter節點只參與投票,不能被選爲Primary,而且不從Primary同步數據,偶數時加入
Priority0節點的選舉優先級爲0,不會被選舉爲Primary
Vote0複製集成員最多50個,參與Primary選舉投票的成員最多7個,其餘成員(Vote0)
Hidden(Vote0)可以使用Hidden節點作一些數據備份、離線計算的任務,不會影響複製集的服務。
Delayed節點必須是Hidden節點,而且其數據落後與Primary一段時間(錯誤恢復)併發