摘要:并依賴于提供的機(jī)制提供高數(shù)據(jù)可靠性,目前支持單機(jī)事務(wù)。源通知目標(biāo)開始同步數(shù)據(jù)源收到發(fā)送的命令后,會向目標(biāo)發(fā)送的命令,通知目標(biāo)開始遷移數(shù)據(jù)真正的數(shù)據(jù)遷移由目標(biāo)主動發(fā)起。源收到的結(jié)果,整個數(shù)據(jù)遷移的步驟完成。
本文分兩部分,分布式和單機(jī)。單個db的存儲引擎,物理和數(shù)據(jù)存儲簡介,事務(wù)實(shí)現(xiàn)等。分布式架構(gòu),分布式涉及的復(fù)制集,分片等可靠性和擴(kuò)展性保障。
第一部分 單機(jī)存儲引擎介紹mondod 引擎概述wiredTiger(簡稱WT)支持行存儲、列存儲以及LSM等3種存儲形式,Mongodb使用時,只是將其作為普通的KV存儲引擎來使用,mongodb的每個集合對應(yīng)一個WT的table,table里包含多個Key-value pairs,以B樹形式存儲。mongodb的集合和索引都對應(yīng)一個wiredTiger的table。并依賴于wiredTiger提供的checkpoint + write ahead log機(jī)制提供高數(shù)據(jù)可靠性,目前支持單機(jī)事務(wù)。
按照Mongodb默認(rèn)的配置,?WiredTiger的寫操作會先寫入Cache,并持久化到WAL(Write ahead log journal),每60s或log文件達(dá)到2GB時會做一次Checkpoint,將當(dāng)前的數(shù)據(jù)持久化,產(chǎn)生一個新的快照。Wiredtiger連接初始化時,首先將數(shù)據(jù)恢復(fù)至最新的快照狀態(tài),然后根據(jù)WAL恢復(fù)數(shù)據(jù),以保證存儲可靠性。
Wiredtiger的索引采用Btree的方式組織
Wiredtiger采用Copy on write[ps:存儲的COW意在W的時候C一份,不在原來上修改。linux的意在W的時候才C一份,不更改只會存在一份]的方式管理修改操作(insert、update、delete),保證一致性,并且不像InnoDB一樣,需要一個DoubleWriteBuffer保證非disk block 512B寫時對原有頁可能發(fā)生conrrupt。修改操作會先緩存在cache里,持久化時,修改操作不會在原來的leaf page上進(jìn)行,而是寫入新分配的page,每次checkpoint都會產(chǎn)生一個新的root page。
內(nèi)存結(jié)構(gòu):B樹索引頁和數(shù)據(jù)頁(B樹做了改版,中間節(jié)點(diǎn)不放數(shù)據(jù),要加update和insert占內(nèi)存),新插入跳表(有序)更新list(會變更,無需有序),copy on write,wal
物理結(jié)構(gòu):
ACID
寫入:寫入頁的跳表,不改變原值
更新:寫入更新數(shù)組中
讀取:若有update合并
ACID:隔離用的未提交快照。注意這個快照只是讀用的。寫還是到最新頁。
關(guān)于快照,緩存,數(shù)據(jù)
每個事務(wù)有自己的快照(可能是舊的page_root),新的事務(wù)會獲取當(dāng)前最新page_root(可能還未做checkpoint,因此繼續(xù)用舊的,加入寫入跳表和更新數(shù)組),checkpoint對最新的做持久化和生成新page_root到磁盤,按需讀取到內(nèi)存。新建連接會先進(jìn)行磁盤的數(shù)據(jù)的數(shù)據(jù)恢復(fù):最新快照+WAL,按需讀入內(nèi)存??煺找彩峭ㄟ^事務(wù)id判斷update和Insert是否可見
journal(wal):并發(fā),預(yù)先分配slots,申請slot用CAS,buffer和lsn, 刷盤。傳統(tǒng)的WAL使用互斥體來協(xié)調(diào)多線程的寫入,這在單核架構(gòu)上可以很好地工作,多核只有一個鎖浪費(fèi),journal的多線程申請slots,并行復(fù)制
做checkpoint時,將更新和寫入到新的頁中,生成新的page_root快照。
cache 驅(qū)逐:略
數(shù)據(jù)清理:
compact 加的是DB級別的互斥寫鎖,同一個DB上的讀寫都會被阻塞
compact基本不需要額外的空間,wiredtiger compact的原理是將數(shù)據(jù)不斷往前面的空洞挪動,并不需要把數(shù)據(jù)存儲到臨時的位置(額外的存儲空間)。
運(yùn)行中內(nèi)存占用
存儲引擎cache,集合,索引元數(shù)據(jù),新寫入數(shù)據(jù)
MongoDB Driver(client) 會跟 mongod 進(jìn)程建立 tcp 連接,一個連接一個線程的模型。并在連接上發(fā)送數(shù)據(jù)庫請求,接受應(yīng)答,tcp 協(xié)議棧除了為連接維護(hù)socket元數(shù)據(jù)為,每個連接會有一個read buffer及write buffer,用戶收發(fā)網(wǎng)絡(luò)包,buffer的大小通過如下sysctl系統(tǒng)參數(shù)配置,分別是buffer的最小值、默認(rèn)值以及最大值。500個類似的連接就會占用掉 1GB 的內(nèi)存 ,ss -m
其他并發(fā)大時排序等
主備節(jié)點(diǎn)差異,備節(jié)點(diǎn)buffer存儲oplog
分片
balancer+route
config
分片:范圍,hash
遷移步驟:
集合分片開啟后,默認(rèn)會創(chuàng)建一個新的chunk,shard key取值[minKey, maxKey]內(nèi)的文檔(即所有的文檔)都會存儲到這個chunk。當(dāng)使用Hash分片策略時,可以預(yù)先創(chuàng)建多個chunk,以減少chunk的遷移。
一個 Sharded Cluster 里可能有很多個 mongos(可以理解一個庫一個),如果所有的 mongos 的 Balancer 同時去觸發(fā)遷移,整個集群就亂了,為了不出亂子,同一時刻只能讓一個 Balancer 去做負(fù)載均衡。
Balancer 在開始負(fù)載均衡前,會先搶鎖(config.locks集合下的一個特殊文檔),搶到鎖的 Balancer 繼續(xù)干活,沒搶到鎖的則繼續(xù)等待,一段時間后再嘗試搶鎖。
Step1: mongos 發(fā)送 moveChunk 給源 shard mongos 接受到用戶發(fā)送的遷移 chunk 命令,或者因負(fù)載均衡策略需要遷移 chunk,會構(gòu)建一個 moveChunk 的命令,并發(fā)送給源 shard。 Step2:源 shard 通知目標(biāo) shard 開始同步 chunk數(shù)據(jù) 源 shard 收到 mongos 發(fā)送的 moveChunk 命令后,會向目標(biāo) shard 發(fā)送 _recvChunkStart 的命令,通知目標(biāo) shard 開始遷移數(shù)據(jù)(真正的數(shù)據(jù)遷移由目標(biāo)shard 主動發(fā)起)。接下來,源 shard 會記錄該 chunk 在遷移過程中的所有增量修改操作。 Step3: 目標(biāo) shard 同步 chunk 數(shù)據(jù)到本地 目標(biāo) shard 接受到 _recvChunkStart 命令后,就會啟動多帶帶的線程來讀取 chunk 數(shù)據(jù)并寫到本地,主要步驟包括: 目標(biāo) shard 創(chuàng)建集合及索引(如果有必要) 如果遷移的集合在目標(biāo) shard 上沒有任何 chunk,則需要先在目標(biāo) shard 上創(chuàng)建集合,并創(chuàng)建跟源 shard 上集合相同的索引 目標(biāo) shard 清理臟數(shù)據(jù) (如果有必要) 如果目標(biāo) shard 上已經(jīng)存在該 chunk 范圍內(nèi)的數(shù)據(jù),則肯定為某次遷移失敗導(dǎo)致的臟數(shù)據(jù),先將這些數(shù)據(jù)清理掉。 目標(biāo) shard 向源 shard 發(fā)送 _migrateClone 命令讀取 chunk 范圍內(nèi)的所有文檔并寫入到本地,即遷移 chunk 全量數(shù)據(jù),遷移完后更新狀態(tài)為 STEADY(可以理解為全量遷移完成的狀態(tài))。 源 shard 會不斷調(diào)用查詢目標(biāo) shard 上的遷移狀態(tài),看是否為 STEADY 狀態(tài),如果已經(jīng)是 STEADY 狀態(tài),就會停止源 shard 上的寫操作(通過對集合加互斥寫鎖實(shí)現(xiàn))。接下來發(fā)送 _recvChunkCommit 告訴目標(biāo) shard 不會再有新的寫入了。 目標(biāo) shard 的遷移線程不斷向源 shard 發(fā)送 _transferMods 命令,讀取遷移過程中的增量修改,并應(yīng)用到本地,增量遷移完成后,向源確認(rèn) _recvChunkCommit 的結(jié)果。 源 shard 收到 _recvChunkCommit 的結(jié)果,整個數(shù)據(jù)遷移的步驟完成。 Step4:源 shard 更新 config server 元數(shù)據(jù) 數(shù)據(jù)遷移完成后,源 shard 就會向 config server 更新 chunk 對應(yīng)的 shard 信息,同時也會更新 chunk 的版本信息,這樣 mongos 發(fā)現(xiàn)本地版本更低就會主動的 reload 元數(shù)據(jù),具體機(jī)制參考 MongoDB Sharded Cluster 路由策略。 Step5:源 shard 刪除 chunk 數(shù)據(jù) chunk 遷移到目標(biāo) shard 后,源上的 chunk 就沒有必要再保存了,源 shard 會將 chunk 數(shù)據(jù)刪除,默認(rèn)情況下源 shard 會將刪除操作加入到隊列,異步刪除,如果 moveChunk 時,指定了 _waitForDelete 參數(shù)為 true,則同步刪除完再返回。 一旦源shard 查詢到目標(biāo) shard 進(jìn)入到 STEADY 狀態(tài)了,源 shard 就會進(jìn)入臨界區(qū),測試源上的寫就會排隊等待。等整個遷移完了,這些等待的寫操作就會繼續(xù)執(zhí)行,但此時 chunk 的版本號已經(jīng)更新了,會告訴客戶端版本過低,客戶端重新從 config server 讀取配置,此時拿到的路由信息里 chunk 已經(jīng)在目標(biāo) shard 了,然后寫會發(fā)往目標(biāo) shard 。復(fù)制集: 數(shù)據(jù)同步
Secondary初次同步數(shù)據(jù)時,會先進(jìn)行init sync,從Primary(或其他數(shù)據(jù)更新的Secondary)同步全量數(shù)據(jù),然后不斷通過tailable cursor從Primary的local.oplog.rs集合里查詢最新的oplog并應(yīng)用到自身。
oplog: 冪等(incr會轉(zhuǎn)為set),循環(huán)覆蓋,
順序保證:寫入 oplog前,會先加鎖給 oplog 分配時間戳,并注冊到未提交列表里,正式寫入 oplog,在寫完后,將對應(yīng)的 oplog 從未提交列表里移除,在拉取 oplog 時若未提交列表為空,所有 oplog 都可讀,否則只能到未提交列表最小值以前的 oplog
Secondary 拉取到一批 oplog 后,在重放這批 oplog 時,會加一個特殊的 Lock::ParallelBatchWriterMode 的鎖,這個鎖會阻塞所有的讀請求,直到這批 oplog 重放完成
client與復(fù)制集心跳,復(fù)制集之間心跳
復(fù)制集成員間默認(rèn)每2s會發(fā)送一次心跳信息,如果10s未收到某個節(jié)點(diǎn)的心跳,則認(rèn)為該節(jié)點(diǎn)已宕機(jī);如果宕機(jī)的節(jié)點(diǎn)為Primary,Secondary(前提是可被選為Primary)會發(fā)起新的Primary選舉。Bully算法。
每個節(jié)點(diǎn)都傾向于投票給優(yōu)先級最高的節(jié)點(diǎn)(oplog時間戳,一樣誰先就誰)
優(yōu)先級為0的節(jié)點(diǎn)不會主動發(fā)起Primary選舉
當(dāng)Primary發(fā)現(xiàn)有優(yōu)先級更高Secondary,并且該Secondary的數(shù)據(jù)落后在10s內(nèi),則Primary會主動降級,讓優(yōu)先級更高的Secondary有成為Primary的機(jī)會。
如果Primary與大多數(shù)的節(jié)點(diǎn)斷開連接,Primary會主動降級為Secondary
當(dāng)復(fù)制集內(nèi)存活成員數(shù)量不足大多數(shù)時,整個復(fù)制集將無法選舉出Primary,復(fù)制集將無法提供寫服務(wù),處于只讀狀態(tài)
當(dāng)Primary宕機(jī)時,如果有數(shù)據(jù)未同步到Secondary,當(dāng)Primary重新加入時,如果新的Primary上已經(jīng)發(fā)生了寫操作,則舊Primary需要回滾部分操作,以保證數(shù)據(jù)集與新的Primary一致。舊Primary將回滾的數(shù)據(jù)寫到多帶帶的rollback目錄下,數(shù)據(jù)庫管理員可根據(jù)需要使用mongorestore進(jìn)行恢復(fù)。
Bully
如果P是最大的ID,直接向所有人發(fā)送Victory消息,成功新的Leader;否則向所有比他大的ID的進(jìn)程發(fā)送Election消息 如果P再發(fā)送Election消息后沒有收到Alive消息,則P向所有人發(fā)送Victory消息,成功新的Leader 如果P收到了從比自己ID還要大的進(jìn)程發(fā)來的Alive消息,P停止發(fā)送任何消息,等待Victory消息(如果過了一段時間沒有等到Victory消息,重新開始選舉流程) 如果P收到了比自己ID小的進(jìn)程發(fā)來的Election消息,回復(fù)一個Alive消息,然后重新開始選舉流程 如果P收到Victory消息,把發(fā)送者當(dāng)做Leader部署
Primary
Secondary:
Arbiter節(jié)點(diǎn)只參與投票,不能被選為Primary,并且不從Primary同步數(shù)據(jù),偶數(shù)時加入
Priority0節(jié)點(diǎn)的選舉優(yōu)先級為0,不會被選舉為Primary
Vote0復(fù)制集成員最多50個,參與Primary選舉投票的成員最多7個,其他成員(Vote0)
Hidden(Vote0)可使用Hidden節(jié)點(diǎn)做一些數(shù)據(jù)備份、離線計算的任務(wù),不會影響復(fù)制集的服務(wù)。
Delayed節(jié)點(diǎn)必須是Hidden節(jié)點(diǎn),并且其數(shù)據(jù)落后與Primary一段時間(錯誤恢復(fù))
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/19520.html
摘要:安裝全過程環(huán)境基本情況我是在電腦下安裝的系統(tǒng)位,這個也是導(dǎo)致我安裝的時候出現(xiàn)異常提示,原因可能是的版本是位的,我應(yīng)該再找一個位的,但事實(shí)上我找不到。 簡述 之前講了一些關(guān)于MongoDB的知識,出人意料的受歡迎,也讓我很吃驚,所以今天打算分享一些我在自己計算機(jī)的虛擬機(jī)的centos系統(tǒng)下安裝MongoDB的經(jīng)歷,希望感興趣的你們在安裝MongoDB的時候出現(xiàn)問題可以來看看我是怎么安裝的...
摘要:安裝全過程環(huán)境基本情況我是在電腦下安裝的系統(tǒng)位,這個也是導(dǎo)致我安裝的時候出現(xiàn)異常提示,原因可能是的版本是位的,我應(yīng)該再找一個位的,但事實(shí)上我找不到。 簡述 之前講了一些關(guān)于MongoDB的知識,出人意料的受歡迎,也讓我很吃驚,所以今天打算分享一些我在自己計算機(jī)的虛擬機(jī)的centos系統(tǒng)下安裝MongoDB的經(jīng)歷,希望感興趣的你們在安裝MongoDB的時候出現(xiàn)問題可以來看看我是怎么安裝的...
摘要:安裝全過程環(huán)境基本情況我是在電腦下安裝的系統(tǒng)位,這個也是導(dǎo)致我安裝的時候出現(xiàn)異常提示,原因可能是的版本是位的,我應(yīng)該再找一個位的,但事實(shí)上我找不到。 簡述 之前講了一些關(guān)于MongoDB的知識,出人意料的受歡迎,也讓我很吃驚,所以今天打算分享一些我在自己計算機(jī)的虛擬機(jī)的centos系統(tǒng)下安裝MongoDB的經(jīng)歷,希望感興趣的你們在安裝MongoDB的時候出現(xiàn)問題可以來看看我是怎么安裝的...
閱讀 2528·2021-10-12 10:12
閱讀 1707·2019-08-30 15:52
閱讀 2443·2019-08-30 13:04
閱讀 1734·2019-08-29 18:33
閱讀 961·2019-08-29 16:28
閱讀 451·2019-08-29 12:33
閱讀 2057·2019-08-26 13:33
閱讀 2361·2019-08-26 11:36