溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Mongos與集群均衡怎么理解

發(fā)布時間:2021-12-23 15:53:20 來源:億速云 閱讀:129 作者:iii 欄目:云計算

本篇內(nèi)容主要講解“Mongos與集群均衡怎么理解”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“Mongos與集群均衡怎么理解”吧!

mongodb 可以以單復(fù)制集的方式運(yùn)行,client 直連mongod讀取數(shù)據(jù)。
單復(fù)制集的方式下,數(shù)據(jù)的水平擴(kuò)展的責(zé)任推給了業(yè)務(wù)層解決(分實(shí)例,分庫分表),mongodb原生提供集群方案,該方案的簡要架構(gòu)如下:

mongodb集群是一個典型的去中心化分布式集群。mongodb集群主要為用戶解決了如下問題:

  • 元數(shù)據(jù)的一致性與高可用(Consistency + Partition Torrence)

  • 業(yè)務(wù)數(shù)據(jù)的多備份容災(zāi)(由復(fù)制集技術(shù)保證)

  • 動態(tài)自動分片

  • 動態(tài)自動數(shù)據(jù)均衡
    下文通過介紹mongodb集群中各個組成部分,逐步深入剖析mongodb集群原理。

ConfigServer

mongodb元數(shù)據(jù)全部存放在configServer中,configServer 是由一組(至少三個)mongod實(shí)例組成的集群。
configServer 的唯一功能是提供元數(shù)據(jù)的增刪改查。和大多數(shù)元數(shù)據(jù)管理系統(tǒng)(etcd,zookeeper)類似,也是保證一致性與分區(qū)容錯性。本身不具備中心化的調(diào)度功能。

ConfigServer與復(fù)制集

ConfigServer的分區(qū)容錯性(P)和數(shù)據(jù)一致性(C)是復(fù)制集本身的性質(zhì)。
MongoDb的讀寫一致性由WriteConcern和ReadConcern兩個參數(shù)保證。
兩者組合可以得到不同的一致性等級。
指定 writeConcern:majority 可以保證寫入數(shù)據(jù)不丟失,不會因選舉新主節(jié)點(diǎn)而被回滾掉。
readConcern:majority + writeConcern:majority 可以保證強(qiáng)一致性的讀
readConcern:local + writeConcern:majority 可以保證最終一致性的讀
mongodb 對configServer全部指定writeConcern:majority 的寫入方式,因此元數(shù)據(jù)可以保證不丟失。
對configServer的讀指定了ReadPreference:PrimaryOnly的方式,在CAP中舍棄了A與P得到了元數(shù)據(jù)的強(qiáng)一致性讀。

Mongos

數(shù)據(jù)自動分片

對于一個讀寫操作,mongos需要知道應(yīng)該將其路由到哪個復(fù)制集上,mongos通過將片鍵空間劃分為若干個區(qū)間,計算出一個操作的片鍵的所屬區(qū)間對應(yīng)的復(fù)制集來實(shí)現(xiàn)路由。

Collection1 被劃分為4個chunk,其中
chunk1 包含(-INF,1) , chunk3 包含[20, 99) 的數(shù)據(jù),放在shard1上。
chunk2 包含 [1,20), chunk4 包含[99, INF) 的數(shù)據(jù),放在shard2上。
chunk 的信息存放在configServer 的mongod實(shí)例的 config.chunks 表中,格式如下:

{   
    "_id" : "mydb.foo-a_\"cat\"",   
    "lastmod" : Timestamp(1000, 3),  
    "lastmodEpoch" : ObjectId("5078407bd58b175c5c225fdc"),   
    "ns" : "mydb.foo",   
    "min" : {         "animal" : "cat"   },   
    "max" : {         "animal" : "dog"   },   
    "shard" : "shard0004"
}

值得注意的是:chunk是一個邏輯上的組織結(jié)構(gòu),并不涉及到底層的文件組織方式。

啟發(fā)式觸發(fā)chunk分裂

mongodb 默認(rèn)配置下,每個chunk大小為16MB。超過該大小就需要執(zhí)行chunk分裂。chunk分裂是由mongos發(fā)起的,而數(shù)據(jù)放在mongod處,因此mongos無法準(zhǔn)確判斷每個增刪改操作后某個chunk的數(shù)據(jù)實(shí)際大小。因此mongos采用了一種啟發(fā)式的觸發(fā)分裂方式:
mongos在內(nèi)存中記錄一份 chunk_id -> incr_delta 的哈希表。
對于insert和update操作,估算出incr_delta的上界(WriteOp::targetWrites), 當(dāng)incr_delta超過閾值時,執(zhí)行chunk分裂。
值得注意的是:

1) chunk_id->incr_delta 是維護(hù)在mongos內(nèi)存里的一份數(shù)據(jù),重啟后丟失
2) 不同mongos之間的這份數(shù)據(jù)相互獨(dú)立
3) 不帶shardkey的update 無法對 chunk_id->incr_delta 作用

因此這個啟發(fā)式的分裂方式很不精確,而除了手工以命令的方式分裂之外,這是mongos自帶的唯一的chunk分裂方式。

chunk分裂的執(zhí)行過程

1) 向?qū)?yīng)的mongod 發(fā)起splitVector 命令,獲得一個chunk的可分裂點(diǎn)
2) mongos 拿到這些分裂點(diǎn)后,向mongod發(fā)起splitChunk 命令

splitVector執(zhí)行過程:

1) 計算出collection的文檔的 avgRecSize= coll.size/ coll.count
2) 計算出分裂后的chunk中,每個chunk應(yīng)該有的count數(shù), split_count = maxChunkSize / (2 * avgRecSize)
3) 線性遍歷collection 的shardkey 對應(yīng)的index的 [chunk_min_index, chunk_max_index] 范圍,在遍歷過程中利用split_count 分割出若干spli

splitChunk執(zhí)行過程:

1) 獲得待執(zhí)行collection的分布式鎖(向configSvr 的mongod中寫入一條記錄實(shí)現(xiàn))
2) 刷新(向configSvr讀?。┍緎hard的版本號,檢查是否和命令發(fā)起者攜帶的版本號一致
3) 向configSvr中寫入分裂后的chunk信息,成功后修改本地的chunk信息與shard的版本號
4) 向configSvr中寫入變更日志
5) 通知mongos操作完成,mongos修改自身元數(shù)據(jù)

chunk分裂的執(zhí)行流程圖:

問題與思考

問題一:為何mongos在接收到splitVector的返回后,執(zhí)行splitChunk 要放在mongod執(zhí)行而不是mongos中呢,為何不是mongos自己執(zhí)行完了splitChunk再通知mongod 修改元數(shù)據(jù)?
我們知道chunk元數(shù)據(jù)在三個地方持有,分別是configServer,mongos,mongod。如果chunk元信息由mongos更改,則其他mongos與mongod都無法第一時間獲得最新元數(shù)據(jù)??赡軙l(fā)生這樣的問題,如下圖描述:

Mongos對元數(shù)據(jù)的修改還沒有被mongod與其他mongos感知,其他mongos與mongod的版本號保持一致,導(dǎo)致其他mongos寫入錯誤的chunk。

如果chunk元信息由mongod更改,mongod 先于所有的mongos感知到本shard的元數(shù)據(jù)被更改,由于mongos對mongod的寫入請求都會帶有版本號(以發(fā)起者mongos的POV 持有的版本號),mongod發(fā)現(xiàn)一個讀寫帶有的版本號低于自身版本號時就會返回 StaleShardingError,從而避免對錯誤的chunk進(jìn)行讀寫。

Mongos對讀寫的路由

讀請求:
mongos將讀請求路由到對應(yīng)的shard上,如果得到StaleShardingError,則刷新本地的元數(shù)據(jù)(從configServer讀取最新元數(shù)據(jù))并重試。
寫請求:
mongos將寫請求路由到對應(yīng)的shard上,如果得到StaleShardingError,并不會像讀請求一樣重試,這樣做并不合理,截至當(dāng)前版本,mongos也只是列出了一個TODO(batch_write_exec.cpp:185)

185          // TODO: It may be necessary to refresh the cache if stale, or maybe just
186          // cancel and retarget the batch
chunk遷移

chunk遷移由balancer模塊執(zhí)行,balancer模塊并不是一個獨(dú)立的service,而是mongos的一個線程模塊。同一時間只有一個balancer模塊在執(zhí)行,這一點(diǎn)是mongos在configServer中注冊分布式鎖來保證的。

balancer 對于每一個collection的chunk 分布,計算出這個collection需要進(jìn)行遷移的chunk,以及每個chunk需要遷移到哪個shard上。計算的過程在BalancerPolicy 類中,比較瑣碎。

chunk遷移.Step1

MigrationManager::scheduleMigrations balancer對于每一個collection,嘗試獲得該collection的分布式鎖(向configSvr申請),如果獲得失敗,表明該collection已有正在執(zhí)行的搬遷任務(wù)。這一點(diǎn)說明對于同一張表統(tǒng)一時刻只能有一個搬遷任務(wù)。如果這張表分布在不同的shard上,完全隔離的IO條件可以提高并發(fā),不過mongos并沒有利用起來這一點(diǎn)。
如果獲得鎖成功,則向源shard發(fā)起moveChunk 命令

chunk遷移.Step2

mongod 執(zhí)行moveChunk命令
cloneStage
1) 源mongod 根據(jù)需要遷移的chunk 的上下限構(gòu)造好查詢計劃,基于分片索引的掃描查詢。并向目標(biāo)mongod發(fā)起recvChunkStart 指令,讓目標(biāo)chunk 開始進(jìn)入數(shù)據(jù)拉取階段。
2) 源mongod對此階段的修改, 將id字段buffer在內(nèi)存里(MigrationChunkClonerSourceLegacy類),為了防止搬遷時速度過慢buffer無限制增長,buffer大小設(shè)置為500MB,在搬遷過程中key的更改量超過buffer大小會導(dǎo)致搬遷失敗。
3) 目標(biāo)mongod 在接收到recvChunkStart命令后

a. 基于chunk的range,將本mongod上的可能臟數(shù)據(jù)清理掉

b. 向源發(fā)起_migrateClone指定,通過1)中構(gòu)造好的基于分配索引的掃描查詢得到該chunk 數(shù)據(jù)的snapshot

c. 拷貝完snapshot后,向源發(fā)起_transferMods命令,將2)中維護(hù)在內(nèi)存buffer中的修改

d. 源在收到_transferMods后,通過記錄的objid查詢對應(yīng)的collection,將真實(shí)數(shù)據(jù)返回給目標(biāo)。

e. 目標(biāo)在收完_transferMods 階段的數(shù)據(jù)后,進(jìn)入steady狀態(tài),等待源接下來的命令。這里有必要說明的是:用戶數(shù)據(jù)源源不斷的寫入,理論上_transferMods 階段會一直有新數(shù)據(jù),但是必須要找到一個點(diǎn)截斷數(shù)據(jù)流,將源的數(shù)據(jù)(搬遷對應(yīng)的chunk的數(shù)據(jù))設(shè)置為不可寫,才能發(fā)起路由更改。因此這里所說的“_transferMods階段的所有數(shù)據(jù)”只是針對于某個時間點(diǎn),這個時間點(diǎn)過后依然會有新數(shù)據(jù)進(jìn)來。

f. 源心跳檢查目標(biāo)是否已經(jīng)處于steady狀態(tài),如果是,則封禁chunk的寫入,向目標(biāo)發(fā)起_recvChunkCommit命令,之后源的chunk上就無修改了。

g. 目標(biāo)收到_recvChunkCommit命令后,拉取源chunk上的修改并執(zhí)行,執(zhí)行成功后源解禁路由并清理源chunk的數(shù)據(jù)

到此,相信大家對“Mongos與集群均衡怎么理解”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI